From bbba6e1a6acdf55beb857f1442a6b321bd5a1c3f Mon Sep 17 00:00:00 2001
From: Vojin Jovanovic
Date: Mon, 29 Apr 2024 19:42:53 +0200
Subject: [PATCH 1/8] Use JVMCI for @Delete classes
(cherry picked from commit 30ae9d3c8dce269e1bcb9f1a090fddfff7d8eea4)
---
.../AnnotationSubstitutionProcessor.java | 30 +++++++++++++------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java
index 8f35f4f73891..687344c79623 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java
@@ -635,23 +635,35 @@ private static boolean hasDefaultValue(Field annotatedField) {
private void handleDeletedClass(Class> originalClass, Delete deleteAnnotation) {
if (NativeImageOptions.ReportUnsupportedElementsAtRuntime.getValue()) {
+ ResolvedJavaType type = metaAccess.lookupJavaType(originalClass);
+
+ try {
+ type.link();
+ } catch (LinkageError ignored) {
+ /*
+ * Ignore any linking errors. A type that cannot be linked doesn't need elements
+ * replaced: it will simply fail at runtime with the same linkage error before
+ * reaching those elements.
+ */
+ return;
+ }
+
/*
* We register all methods and fields as deleted. That still allows usage of the type in
* type checks.
*/
- for (Executable m : originalClass.getDeclaredMethods()) {
- ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
+ for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
registerAsDeleted(null, method, deleteAnnotation);
}
- for (Executable m : originalClass.getDeclaredConstructors()) {
- ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
- registerAsDeleted(null, method, deleteAnnotation);
+ for (ResolvedJavaMethod constructor : type.getDeclaredConstructors()) {
+ registerAsDeleted(null, constructor, deleteAnnotation);
}
- for (Field f : originalClass.getDeclaredFields()) {
- ResolvedJavaField field = metaAccess.lookupJavaField(f);
- registerAsDeleted(null, field, deleteAnnotation);
+ for (ResolvedJavaField f : type.getInstanceFields(false)) {
+ registerAsDeleted(null, f, deleteAnnotation);
+ }
+ for (ResolvedJavaField f : type.getStaticFields()) {
+ registerAsDeleted(null, f, deleteAnnotation);
}
-
} else {
deleteAnnotations.put(metaAccess.lookupJavaType(originalClass), deleteAnnotation);
}
From 3a097bf0534c5d3471acbb3354404697a12283cb Mon Sep 17 00:00:00 2001
From: Loic Ottet
Date: Tue, 27 Aug 2024 14:36:49 +0200
Subject: [PATCH 2/8] Replace configuration parser with master version
---
.../configure/ConditionalRuntimeValue.java | 69 ++++++
.../ConfigurationConditionResolver.java | 50 +++++
.../svm/core/configure/ConfigurationFile.java | 45 ++--
.../core/configure/ConfigurationFiles.java | 109 +++++++---
.../core/configure/ConfigurationParser.java | 146 +++++++++++--
.../ConfigurationTypeDescriptor.java | 80 +++++++
.../LegacyReflectionConfigurationParser.java | 142 +++++++++++++
.../LegacyResourceConfigurationParser.java | 67 ++++++
...egacySerializationConfigurationParser.java | 112 ++++++++++
.../NamedConfigurationTypeDescriptor.java | 67 ++++++
.../configure/ProxyConfigurationParser.java | 40 ++--
.../ProxyConfigurationTypeDescriptor.java | 74 +++++++
.../ReflectionConfigurationParser.java | 196 ++++-------------
...ReflectionConfigurationParserDelegate.java | 48 ++---
.../configure/ReflectionMetadataParser.java | 128 ++++++++++++
.../ResourceConfigurationParser.java | 144 +++++++------
.../configure/ResourceMetadataParser.java | 45 ++++
.../svm/core/configure/ResourcesRegistry.java | 43 +---
.../core/configure/RuntimeConditionSet.java | 197 ++++++++++++++++++
.../SerializationConfigurationParser.java | 81 ++-----
.../SerializationMetadataParser.java | 67 ++++++
.../doc-files/ProxyConfigurationFilesHelp.txt | 1 +
.../ReflectionConfigurationFilesHelp.txt | 3 +-
.../SerializationConfigurationFilesHelp.txt | 3 +-
24 files changed, 1541 insertions(+), 416 deletions(-)
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationTypeDescriptor.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyReflectionConfigurationParser.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacyResourceConfigurationParser.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/LegacySerializationConfigurationParser.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionMetadataParser.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ResourceMetadataParser.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java
create mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationMetadataParser.java
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java
new file mode 100644
index 000000000000..d78533653924
--- /dev/null
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConditionalRuntimeValue.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.graalvm.nativeimage.Platform;
+import org.graalvm.nativeimage.Platforms;
+
+/**
+ * A image-heap stored {@link ConditionalRuntimeValue#value} that is guarded by run-time computed
+ * {@link ConditionalRuntimeValue#conditions}.
+ *
+ * {@link ConditionalRuntimeValue#conditions} are stored as an array to save space in the image
+ * heap. This is subject to further optimizations.
+ *
+ * @param type of the stored value.
+ */
+public final class ConditionalRuntimeValue {
+ RuntimeConditionSet conditions;
+ volatile T value;
+
+ public ConditionalRuntimeValue(RuntimeConditionSet conditions, T value) {
+ this.conditions = conditions;
+ this.value = value;
+ }
+
+ @Platforms(Platform.HOSTED_ONLY.class)
+ public T getValueUnconditionally() {
+ return value;
+ }
+
+ public RuntimeConditionSet getConditions() {
+ return conditions;
+ }
+
+ public T getValue() {
+ if (conditions.satisfied()) {
+ return value;
+ } else {
+ return null;
+ }
+ }
+
+ @Platforms(Platform.HOSTED_ONLY.class)
+ public void updateValue(T newValue) {
+ this.value = newValue;
+ }
+}
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java
new file mode 100644
index 000000000000..bfbba32b23cc
--- /dev/null
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationConditionResolver.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, 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 org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition;
+
+import com.oracle.svm.core.TypeResult;
+
+public interface ConfigurationConditionResolver {
+
+ static ConfigurationConditionResolver identityResolver() {
+ return new ConfigurationConditionResolver<>() {
+ @Override
+ public TypeResult resolveCondition(UnresolvedConfigurationCondition unresolvedCondition) {
+ return TypeResult.forType(unresolvedCondition.getTypeName(), unresolvedCondition);
+ }
+
+ @Override
+ public UnresolvedConfigurationCondition alwaysTrue() {
+ return UnresolvedConfigurationCondition.alwaysTrue();
+ }
+ };
+ }
+
+ TypeResult resolveCondition(UnresolvedConfigurationCondition unresolvedCondition);
+
+ T alwaysTrue();
+}
diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFile.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFile.java
index 98dac61e3b0c..8ec71e14ba5a 100644
--- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFile.java
+++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFile.java
@@ -24,21 +24,34 @@
*/
package com.oracle.svm.core.configure;
+import static com.oracle.svm.core.configure.ConfigurationParser.JNI_KEY;
+import static com.oracle.svm.core.configure.ConfigurationParser.REFLECTION_KEY;
+import static com.oracle.svm.core.configure.ConfigurationParser.RESOURCES_KEY;
+import static com.oracle.svm.core.configure.ConfigurationParser.SERIALIZATION_KEY;
+
import java.util.Arrays;
public enum ConfigurationFile {
- DYNAMIC_PROXY("proxy", true),
- RESOURCES("resource", true),
- JNI("jni", true),
- FOREIGN("foreign", false),
- REFLECTION("reflect", true),
- SERIALIZATION("serialization", true),
- SERIALIZATION_DENY("serialization-deny", false),
- PREDEFINED_CLASSES_NAME("predefined-classes", true);
+ /* Combined file */
+ REACHABILITY_METADATA("reachability-metadata", null, true, true),
+ /* Main metadata categories (order matters) */
+ REFLECTION("reflect", REFLECTION_KEY, true, false),
+ RESOURCES("resource", RESOURCES_KEY, true, false),
+ SERIALIZATION("serialization", SERIALIZATION_KEY, true, false),
+ JNI("jni", JNI_KEY, true, false),
+ /* Deprecated metadata categories */
+ DYNAMIC_PROXY("proxy", null, true, false),
+ PREDEFINED_CLASSES_NAME("predefined-classes", null, true, false),
+ /* Non-metadata categories */
+ FOREIGN("foreign", null, false, false),
+ SERIALIZATION_DENY("serialization-deny", null, false, false);
- public static final String DEFAULT_FILE_NAME_SUFFIX = "-config.json";
+ public static final String LEGACY_FILE_NAME_SUFFIX = "-config.json";
+ public static final String COMBINED_FILE_NAME_SUFFIX = ".json";
private final String name;
+ private final String fieldName;
private final boolean canAgentGenerate;
+ private final boolean combinedFile;
public static final String LOCK_FILE_NAME = ".lock";
public static final String PREDEFINED_CLASSES_AGENT_EXTRACTED_SUBDIR = "agent-extracted-predefined-classes";
@@ -47,17 +60,23 @@ public enum ConfigurationFile {
private static final ConfigurationFile[] agentGeneratedFiles = computeAgentGeneratedFiles();
- ConfigurationFile(String name, boolean canAgentGenerate) {
+ ConfigurationFile(String name, String fieldName, boolean canAgentGenerate, boolean combinedFile) {
this.name = name;
+ this.fieldName = fieldName;
this.canAgentGenerate = canAgentGenerate;
+ this.combinedFile = combinedFile;
}
public String getName() {
return name;
}
+ public String getFieldName() {
+ return fieldName;
+ }
+
public String getFileName() {
- return name + DEFAULT_FILE_NAME_SUFFIX;
+ return name + (combinedFile ? COMBINED_FILE_NAME_SUFFIX : LEGACY_FILE_NAME_SUFFIX);
}
public String getFileName(String suffix) {
@@ -65,7 +84,7 @@ public String getFileName(String suffix) {
}
public boolean canBeGeneratedByAgent() {
- return canAgentGenerate;
+ return canAgentGenerate && !combinedFile;
}
public static ConfigurationFile getByName(String name) {
@@ -82,6 +101,6 @@ public static ConfigurationFile[] agentGeneratedFiles() {
}
private static ConfigurationFile[] computeAgentGeneratedFiles() {
- return Arrays.stream(values()).filter(ConfigurationFile::canBeGeneratedByAgent).toArray(ConfigurationFile[]::new);
+ return Arrays.stream(values()).filter(f -> f.canBeGeneratedByAgent()).toArray(ConfigurationFile[]::new);
}
}
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 c78a2ea1d5ee..53bfa1a703ea 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
@@ -34,15 +34,16 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import org.graalvm.compiler.options.Option;
-import org.graalvm.compiler.options.OptionStability;
-import org.graalvm.compiler.options.OptionType;
-
+import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
import com.oracle.svm.core.option.BundleMember;
import com.oracle.svm.core.option.HostedOptionKey;
-import com.oracle.svm.core.option.LocatableMultiOptionValue;
+import com.oracle.svm.core.option.OptionMigrationMessage;
import com.oracle.svm.core.util.UserError;
+import jdk.graal.compiler.options.Option;
+import jdk.graal.compiler.options.OptionStability;
+import jdk.graal.compiler.options.OptionType;
+
/**
* Gathers configuration files from specified directories without having to provide each
* configuration file individually.
@@ -50,70 +51,118 @@
public final class ConfigurationFiles {
public static final class Options {
+
@Option(help = "Directories directly containing configuration files for dynamic features at runtime.", type = OptionType.User, stability = OptionStability.STABLE)//
@BundleMember(role = BundleMember.Role.Input)//
- static final HostedOptionKey ConfigurationFileDirectories = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ static final HostedOptionKey ConfigurationFileDirectories = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resource path above configuration resources for dynamic features at runtime.", type = OptionType.User)//
- public static final HostedOptionKey ConfigurationResourceRoots = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey ConfigurationResourceRoots = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ @OptionMigrationMessage("Use a reflect-config.json in your META-INF/native-image// directory instead.")//
@Option(help = "file:doc-files/ReflectionConfigurationFilesHelp.txt", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey ReflectionConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ public static final HostedOptionKey ReflectionConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing program elements to be made available for reflection (see ReflectionConfigurationFiles).", type = OptionType.User)//
- public static final HostedOptionKey ReflectionConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey ReflectionConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
- @Option(help = "file:doc-files/ProxyConfigurationFilesHelp.txt", type = OptionType.User)//
+ @OptionMigrationMessage("Use a proxy-config.json in your META-INF/native-image// directory instead.")//
+ @Option(help = "file:doc-files/ProxyConfigurationFilesHelp.txt", type = OptionType.User, deprecated = true)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey DynamicProxyConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
- @Option(help = "Resources describing program elements to be made available for reflection (see ProxyConfigurationFiles).", type = OptionType.User)//
- public static final HostedOptionKey DynamicProxyConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
-
+ public static final HostedOptionKey DynamicProxyConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ @Option(help = "Resources describing program elements to be made available for reflection (see ProxyConfigurationFiles).", type = OptionType.User, deprecated = true, //
+ deprecationMessage = "This can be caused by a proxy-config.json file in your META-INF directory. " +
+ "Consider including proxy configuration in the reflection section of reachability-metadata.md instead.")//
+ public static final HostedOptionKey DynamicProxyConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+
+ @OptionMigrationMessage("Use a serialization-config.json in your META-INF/native-image// directory instead.")//
@Option(help = "file:doc-files/SerializationConfigurationFilesHelp.txt", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey SerializationConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ public static final HostedOptionKey SerializationConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing program elements to be made available for serialization (see SerializationConfigurationFiles).", type = OptionType.User)//
- public static final HostedOptionKey SerializationConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey SerializationConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ @OptionMigrationMessage("Use a serialization-config.json in your META-INF/native-image// directory instead.")//
@Option(help = "file:doc-files/SerializationConfigurationFilesHelp.txt", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey SerializationDenyConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ public static final HostedOptionKey SerializationDenyConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing program elements that must not be made available for serialization.", type = OptionType.User)//
- public static final HostedOptionKey SerializationDenyConfigurationResources = new HostedOptionKey<>(
- LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey SerializationDenyConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ @OptionMigrationMessage("Use a resource-config.json in your META-INF/native-image// directory instead.")//
@Option(help = "Files describing Java resources to be included in the image according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/resource-config-schema-v1.0.0.json", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey ResourceConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ public static final HostedOptionKey ResourceConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing Java resources to be included in the image according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/resource-config-schema-v1.0.0.json", type = OptionType.User)//
- public static final HostedOptionKey ResourceConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey ResourceConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
- @Option(help = "Files describing program elements to be made accessible via JNI (for syntax, see ReflectionConfigurationFiles)", type = OptionType.User)//
+ @OptionMigrationMessage("Use a jni-config.json in your META-INF/native-image// directory instead.")//
+ @Option(help = "Files describing program elements to be made accessible via JNI according to the schema at " +
+ "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/jni-config-schema-v1.1.0.json", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey JNIConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
- @Option(help = "Resources describing program elements to be made accessible via JNI (see JNIConfigurationFiles).", type = OptionType.User)//
- public static final HostedOptionKey JNIConfigurationResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey JNIConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ @Option(help = "Resources describing program elements to be made accessible via JNI according to the schema at " +
+ "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/jni-config-schema-v1.1.0.json", type = OptionType.User)//
+ public static final HostedOptionKey JNIConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+
+ @Option(help = "Resources describing reachability metadata needed for the program " +
+ "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/reachability-metadata-schema-v1.0.0.json", type = OptionType.User)//
+ public static final HostedOptionKey ReachabilityMetadataResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
@Option(help = "Files describing stubs allowing foreign calls.", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey ForeignConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ public static final HostedOptionKey ForeignConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing stubs allowing foreign calls.", type = OptionType.User)//
- public static final HostedOptionKey ForeignResources = new HostedOptionKey<>(LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey ForeignResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ @OptionMigrationMessage("Use a predefined-classes-config.json in your META-INF/native-image// directory instead.")//
@Option(help = "Files describing predefined classes that can be loaded at runtime according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/predefined-classes-config-schema-v1.0.0.json", type = OptionType.User)//
@BundleMember(role = BundleMember.Role.Input)//
- public static final HostedOptionKey PredefinedClassesConfigurationFiles = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
+ public static final HostedOptionKey PredefinedClassesConfigurationFiles = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Paths.buildWithCommaDelimiter());
@Option(help = "Resources describing predefined classes that can be loaded at runtime according to the schema at " +
"https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/predefined-classes-config-schema-v1.0.0.json", type = OptionType.User)//
- public static final HostedOptionKey PredefinedClassesConfigurationResources = new HostedOptionKey<>(
- LocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
+ public static final HostedOptionKey PredefinedClassesConfigurationResources = new HostedOptionKey<>(
+ AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
@Option(help = "When configuration files do not match their schema, abort the image build instead of emitting a warning.")//
public static final HostedOptionKey StrictConfiguration = new HostedOptionKey<>(false);
+ @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' in reflection configuration.")//
+ public static final HostedOptionKey TreatAllNameEntriesAsType = new HostedOptionKey<>(false);
+
+ @Option(help = "Testing flag: the 'typeReached' condition is always satisfied however it prints the stack trace where it would not be satisfied.")//
+ public static final HostedOptionKey TrackUnsatisfiedTypeReachedConditions = new HostedOptionKey<>(false);
+
+ @Option(help = "Testing flag: print 'typeReached' conditions that are used on interfaces without default methods at build time.")//
+ public static final HostedOptionKey TrackTypeReachedOnInterfaces = new HostedOptionKey<>(false);
+
+ @Option(help = "Testing flag: every type is considered as it participates in a typeReachable condition.")//
+ public static final HostedOptionKey TreatAllUserSpaceTypesAsTrackedForTypeReached = new HostedOptionKey<>(false);
+
@Option(help = "Warn when reflection and JNI configuration files have elements that could not be found on the classpath or modulepath.", type = OptionType.Expert)//
public static final HostedOptionKey WarnAboutMissingReflectionOrJNIMetadataElements = 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 49b77297caf5..cc28760d0899 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
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 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
@@ -24,7 +24,12 @@
*/
package com.oracle.svm.core.configure;
+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;
+
import java.io.BufferedReader;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -37,18 +42,20 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import org.graalvm.collections.EconomicMap;
-import org.graalvm.nativeimage.impl.ConfigurationCondition;
-import org.graalvm.util.json.JSONParser;
-import org.graalvm.util.json.JSONParserException;
+import org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.jdk.JavaNetSubstitutions;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.LogUtils;
+import jdk.graal.compiler.util.json.JsonParser;
+import jdk.graal.compiler.util.json.JsonParserException;
+
public abstract class ConfigurationParser {
public static InputStream openStream(URI uri) throws IOException {
URL url = uri.toURL();
@@ -60,7 +67,15 @@ public static InputStream openStream(URI uri) throws IOException {
}
public static final String CONDITIONAL_KEY = "condition";
- public static final String TYPE_REACHABLE_KEY = "typeReachable";
+ public static final String NAME_KEY = "name";
+ public static final String TYPE_KEY = "type";
+ public static final String PROXY_KEY = "proxy";
+ public static final String REFLECTION_KEY = "reflection";
+ public static final String JNI_KEY = "jni";
+ public static final String SERIALIZATION_KEY = "serialization";
+ public static final String RESOURCES_KEY = "resources";
+ public static final String BUNDLES_KEY = "bundles";
+ public static final String GLOBS_KEY = "globs";
private final Map> seenUnknownAttributesByType = new HashMap<>();
private final boolean strictSchema;
@@ -70,7 +85,12 @@ protected ConfigurationParser(boolean strictConfiguration) {
public void parseAndRegister(URI uri) throws IOException {
try (Reader reader = openReader(uri)) {
- parseAndRegister(new JSONParser(reader).parse(), uri);
+ parseAndRegister(new JsonParser(reader).parse(), uri);
+ } catch (FileNotFoundException e) {
+ /*
+ * Ignore: *-config.json files can be missing when reachability-metadata.json is
+ * present, and vice-versa
+ */
}
}
@@ -79,17 +99,23 @@ protected static BufferedReader openReader(URI uri) throws IOException {
}
public void parseAndRegister(Reader reader) throws IOException {
- parseAndRegister(new JSONParser(reader).parse(), null);
+ parseAndRegister(new JsonParser(reader).parse(), null);
}
public abstract void parseAndRegister(Object json, URI origin) throws IOException;
+ public Object getFromGlobalFile(Object json, String key) {
+ EconomicMap map = asMap(json, "top level of reachability metadata file must be an object");
+ checkAttributes(map, "reachability metadata", Collections.emptyList(), List.of(REFLECTION_KEY, JNI_KEY, SERIALIZATION_KEY, RESOURCES_KEY, BUNDLES_KEY, "reason", "comment"));
+ return map.get(key);
+ }
+
@SuppressWarnings("unchecked")
public static List