diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 853116a7a8e9..92348e511786 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -499,7 +499,18 @@ def conditional_config_task(native_image): config_dir = join(svmbuild_dir(), 'cond-config-test-config') if exists(config_dir): mx.rmtree(config_dir) - agent_opts = ['config-output-dir=' + config_dir, 'experimental-conditional-configuration-for-packages=com.oracle.svm.configure.test.conditionalconfig'] + conditional_config_filter_path = join(svmbuild_dir(), 'conditional-config-filter.json') + with open(conditional_config_filter_path, 'w') as conditional_config_filter: + conditional_config_filter.write( +''' +{ + "rules": [ + {"includeClasses": "com.oracle.svm.configure.test.conditionalconfig.**"} + ] +} +''' + ) + agent_opts = ['config-output-dir=' + config_dir, 'experimental-conditional-config-filter-file=' + conditional_config_filter_path] jvm_unittest(['-agentpath:' + agent_path + '=' + ','.join(agent_opts)] + ['com.oracle.svm.configure.test.conditionalconfig.ConfigurationGenerator']) diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java index 193fc39aab2c..01c07aed159c 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java @@ -41,9 +41,7 @@ import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.Date; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.TimeZone; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -56,10 +54,10 @@ import org.graalvm.nativeimage.ProcessProperties; import org.graalvm.nativeimage.hosted.Feature; +import com.oracle.svm.agent.conditionalconfig.ConditionalConfigurationWriter; import com.oracle.svm.agent.configwithorigins.ConfigurationWithOriginsWriter; import com.oracle.svm.agent.configwithorigins.MethodInfoRecordKeeper; import com.oracle.svm.agent.ignoredconfig.AgentMetaInfProcessor; -import com.oracle.svm.agent.conditionalconfig.ConditionalConfigurationWriter; import com.oracle.svm.agent.stackaccess.EagerlyLoadedJavaStackAccess; import com.oracle.svm.agent.stackaccess.InterceptedState; import com.oracle.svm.agent.stackaccess.OnDemandJavaStackAccess; @@ -70,6 +68,8 @@ import com.oracle.svm.configure.config.ConditionalConfigurationPredicate; import com.oracle.svm.configure.config.ConfigurationFileCollection; import com.oracle.svm.configure.config.ConfigurationSet; +import com.oracle.svm.configure.filters.ComplexFilter; +import com.oracle.svm.configure.filters.ConfigurationFilter; import com.oracle.svm.configure.filters.FilterConfigurationParser; import com.oracle.svm.configure.filters.RuleNode; import com.oracle.svm.configure.trace.AccessAdvisor; @@ -130,8 +130,8 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c boolean experimentalOmitClasspathConfig = false; boolean build = false; boolean configurationWithOrigins = false; - Set conditionalConfigUserPackagePrefixes = new HashSet<>(); - Set conditionalConfigClassNameExcludePatterns = new HashSet<>(); + List conditionalConfigUserPackageFilterFiles = new ArrayList<>(); + List conditionalConfigClassNameFilterFiles = new ArrayList<>(); int configWritePeriod = -1; // in seconds int configWritePeriodInitialDelay = 1; // in seconds boolean trackReflectionMetadata = true; @@ -203,12 +203,10 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c build = Boolean.parseBoolean(getTokenValue(token)); } else if (token.equals("experimental-configuration-with-origins")) { configurationWithOrigins = true; - } else if (token.startsWith("experimental-conditional-config-for-package=")) { - String userPackagePrefix = getTokenValue(token); - conditionalConfigUserPackagePrefixes.add(userPackagePrefix); - } else if (token.startsWith("conditional-config-class-name-exclude-pattern=")) { - String classNamePattern = getTokenValue(token); - conditionalConfigClassNameExcludePatterns.add(Pattern.compile(classNamePattern)); + } else if (token.startsWith("experimental-conditional-config-filter-file=")) { + conditionalConfigUserPackageFilterFiles.add(getTokenValue(token)); + } else if (token.startsWith("conditional-config-class-name-filter-file=")) { + conditionalConfigClassNameFilterFiles.add(getTokenValue(token)); } else if (token.equals("track-reflection-metadata")) { trackReflectionMetadata = true; } else if (token.startsWith("track-reflection-metadata=")) { @@ -223,7 +221,7 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c inform("no output/build options provided, tracking dynamic accesses and writing configuration to directory: " + configOutputDir); } - if (configurationWithOrigins && !conditionalConfigUserPackagePrefixes.isEmpty()) { + if (configurationWithOrigins && !conditionalConfigUserPackageFilterFiles.isEmpty()) { return error(5, "The agent can only be used in either the configuration with origins mode or the predefined classes mode."); } @@ -236,29 +234,32 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c warn("using experimental configuration with origins mode. Note that native-image cannot process these files, and this flag may change or be removed without a warning!"); } - RuleNode callerFilter = null; + ComplexFilter callerFilter = null; + RuleNode callerFilterRuleNode = null; if (!builtinCallerFilter) { - callerFilter = RuleNode.createRoot(); - callerFilter.addOrGetChildren("**", RuleNode.Inclusion.Include); + callerFilterRuleNode = RuleNode.createRootWithIncludedChildren(); + callerFilter = new ComplexFilter(callerFilterRuleNode); } + if (!callerFilterFiles.isEmpty()) { - if (callerFilter == null) { - callerFilter = AccessAdvisor.copyBuiltinCallerFilterTree(); + if (callerFilterRuleNode == null) { + callerFilterRuleNode = AccessAdvisor.copyBuiltinCallerFilterTree(); + callerFilter = new ComplexFilter(callerFilterRuleNode); } if (!parseFilterFiles(callerFilter, callerFilterFiles)) { return 1; } } - RuleNode accessFilter = null; + ComplexFilter accessFilter = null; if (!accessFilterFiles.isEmpty()) { - accessFilter = AccessAdvisor.copyBuiltinAccessFilterTree(); + accessFilter = new ComplexFilter(AccessAdvisor.copyBuiltinAccessFilterTree()); if (!parseFilterFiles(accessFilter, accessFilterFiles)) { return 1; } } - boolean shouldTraceOriginInformation = configurationWithOrigins || !conditionalConfigUserPackagePrefixes.isEmpty(); + boolean shouldTraceOriginInformation = configurationWithOrigins || !conditionalConfigUserPackageFilterFiles.isEmpty(); final MethodInfoRecordKeeper recordKeeper = new MethodInfoRecordKeeper(shouldTraceOriginInformation); final Supplier interceptedStateSupplier = shouldTraceOriginInformation ? EagerlyLoadedJavaStackAccess.stackAccessSupplier() : OnDemandJavaStackAccess.stackAccessSupplier(); @@ -307,9 +308,23 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c ConfigurationWithOriginsWriter writer = new ConfigurationWithOriginsWriter(processor, recordKeeper); tracer = writer; tracingResultWriter = writer; - } else if (!conditionalConfigUserPackagePrefixes.isEmpty()) { - ConditionalConfigurationPredicate filter = new ConditionalConfigurationPredicate(conditionalConfigClassNameExcludePatterns); - ConditionalConfigurationWriter writer = new ConditionalConfigurationWriter(processor, recordKeeper, conditionalConfigUserPackagePrefixes, filter); + } else if (!conditionalConfigUserPackageFilterFiles.isEmpty()) { + ComplexFilter userCodeFilter = new ComplexFilter(RuleNode.createRoot()); + if (!parseFilterFiles(userCodeFilter, conditionalConfigUserPackageFilterFiles)) { + return 2; + } + ComplexFilter classNameFilter; + if (!conditionalConfigClassNameFilterFiles.isEmpty()) { + classNameFilter = new ComplexFilter(RuleNode.createRoot()); + if(!parseFilterFiles(classNameFilter, conditionalConfigClassNameFilterFiles)) { + return 3; + } + } else { + classNameFilter = new ComplexFilter(RuleNode.createRootWithIncludedChildren()); + } + + ConditionalConfigurationPredicate predicate = new ConditionalConfigurationPredicate(classNameFilter); + ConditionalConfigurationWriter writer = new ConditionalConfigurationWriter(processor, recordKeeper, userCodeFilter, predicate); tracer = writer; tracingResultWriter = writer; } else { @@ -389,7 +404,7 @@ private static T usage(T result, String message) { return result; } - private static AccessAdvisor createAccessAdvisor(boolean builtinHeuristicFilter, RuleNode callerFilter, RuleNode accessFilter) { + private static AccessAdvisor createAccessAdvisor(boolean builtinHeuristicFilter, ConfigurationFilter callerFilter, ConfigurationFilter accessFilter) { AccessAdvisor advisor = new AccessAdvisor(); advisor.setHeuristicsEnabled(builtinHeuristicFilter); if (callerFilter != null) { @@ -409,7 +424,7 @@ private static int parseIntegerOrNegative(String number) { } } - private static boolean parseFilterFiles(RuleNode filter, List filterFiles) { + private static boolean parseFilterFiles(ComplexFilter filter, List filterFiles) { for (String path : filterFiles) { try { new FilterConfigurationParser(filter).parseAndRegister(Paths.get(path).toUri()); @@ -417,7 +432,7 @@ private static boolean parseFilterFiles(RuleNode filter, List filterFile return error(false, "cannot parse filter file " + path + ": " + e); } } - filter.removeRedundantNodes(); + filter.getRuleNode().removeRedundantNodes(); return true; } diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/conditionalconfig/ConditionalConfigurationWriter.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/conditionalconfig/ConditionalConfigurationWriter.java index 93412a25de41..ca2c3f60ec85 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/conditionalconfig/ConditionalConfigurationWriter.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/conditionalconfig/ConditionalConfigurationWriter.java @@ -35,6 +35,7 @@ import java.util.Map; import java.util.Set; +import com.oracle.svm.configure.filters.ComplexFilter; import org.graalvm.nativeimage.impl.ConfigurationCondition; import com.oracle.svm.agent.configwithorigins.ConfigurationWithOriginsTracer; @@ -58,14 +59,14 @@ * configuration. See {@link #createConditionalConfiguration()} */ public class ConditionalConfigurationWriter extends ConfigurationWithOriginsTracer implements TracingResultWriter { - private final Set applicationPackagePrefixes; + private final ComplexFilter userCodeFilter; private ConfigurationSet configurationContainer = new ConfigurationSet(); - private final ConditionalConfigurationPredicate filter; + private final ConditionalConfigurationPredicate predicate; - public ConditionalConfigurationWriter(TraceProcessor processor, MethodInfoRecordKeeper methodInfoRecordKeeper, Set applicationPackagePrefixes, ConditionalConfigurationPredicate filter) { + public ConditionalConfigurationWriter(TraceProcessor processor, MethodInfoRecordKeeper methodInfoRecordKeeper, ComplexFilter userCodeFilter, ConditionalConfigurationPredicate predicate) { super(processor, methodInfoRecordKeeper); - this.applicationPackagePrefixes = applicationPackagePrefixes; - this.filter = filter; + this.userCodeFilter = userCodeFilter; + this.predicate = predicate; } private Map> mapMethodsToCallNodes() { @@ -195,7 +196,7 @@ private void addConfigurationWithCondition(ConfigurationSet nodeConfig, Configur } private void filterConfiguration() { - configurationContainer = configurationContainer.filter(filter); + configurationContainer = configurationContainer.filter(predicate); } private void propagateConfiguration(Map> methodCallNodes) { @@ -216,7 +217,7 @@ private void propagateConfiguration(Map> method } private boolean methodOriginatesFromApplicationPackage(MethodInfo methodInfo) { - return applicationPackagePrefixes.stream().anyMatch(prefix -> methodInfo.getJavaDeclaringClassName().startsWith(prefix)); + return userCodeFilter.includes(methodInfo.getJavaDeclaringClassName()); } @Override diff --git a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/conditionalconfig/ConfigurationVerifier.java b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/conditionalconfig/ConfigurationVerifier.java index 505244527b8d..138fff701488 100644 --- a/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/conditionalconfig/ConfigurationVerifier.java +++ b/substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/conditionalconfig/ConfigurationVerifier.java @@ -87,10 +87,7 @@ private static ConfigurationSet loadExpectedConfig() throws Exception { try { String resourceName = "config-dir/" + resourceFileName; URL resourceURL = ConfigurationVerifier.class.getResource(resourceName); - if (resourceURL == null) { - Assert.fail("Configuration file " + resourceName + " does not exist. Make sure that the test or the config directory have not been moved."); - } - return resourceURL.toURI(); + return resourceURL == null ? null : resourceURL.toURI(); } catch (Exception e) { throw VMError.shouldNotReachHere("Unexpected error while locating the configuration files.", e); } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationTool.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationTool.java index 869d5cea162e..41c0c86a31db 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationTool.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ConfigurationTool.java @@ -29,6 +29,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.Reader; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -45,10 +47,12 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import com.oracle.svm.configure.config.ConfigurationSet; import org.graalvm.nativeimage.ImageInfo; import com.oracle.svm.configure.config.ConfigurationFileCollection; +import com.oracle.svm.configure.config.ConfigurationSet; +import com.oracle.svm.configure.filters.ComplexFilter; +import com.oracle.svm.configure.filters.ConfigurationFilter; import com.oracle.svm.configure.filters.FilterConfigurationParser; import com.oracle.svm.configure.filters.ModuleFilterTools; import com.oracle.svm.configure.filters.RuleNode; @@ -244,14 +248,17 @@ private static void generate(Iterator argsIter, boolean acceptTraceFileA } failIfAgentLockFilesPresent(inputSet, omittedInputSet, outputSet); - RuleNode callersFilter = null; + RuleNode callersFilterRuleNode = null; + ComplexFilter callersFilter = null; if (!builtinCallerFilter) { - callersFilter = RuleNode.createRoot(); - callersFilter.addOrGetChildren("**", RuleNode.Inclusion.Include); + callersFilterRuleNode = RuleNode.createRoot(); + callersFilterRuleNode.addOrGetChildren("**", ConfigurationFilter.Inclusion.Include); + callersFilter = new ComplexFilter(callersFilterRuleNode); } if (!callerFilters.isEmpty()) { - if (callersFilter == null) { - callersFilter = AccessAdvisor.copyBuiltinCallerFilterTree(); + if (callersFilterRuleNode == null) { + callersFilterRuleNode = AccessAdvisor.copyBuiltinCallerFilterTree(); + callersFilter = new ComplexFilter(callersFilterRuleNode); } for (URI uri : callerFilters) { try { @@ -261,7 +268,7 @@ private static void generate(Iterator argsIter, boolean acceptTraceFileA throw new UsageException("Cannot parse filter file " + uri + ": " + e); } } - callersFilter.removeRedundantNodes(); + callersFilter.getRuleNode().removeRedundantNodes(); } ConfigurationSet configurationSet; @@ -367,7 +374,9 @@ private static void generateFilterRules(Iterator argsIter) throws IOExce args.add(arg); } } - RuleNode rootNode = null; + RuleNode rootNode = RuleNode.createRoot(); + ComplexFilter filter = new ComplexFilter(rootNode); + boolean filterModified = false; for (String arg : args) { String[] parts = arg.split("=", 2); String current = parts[0]; @@ -377,17 +386,18 @@ private static void generateFilterRules(Iterator argsIter) throws IOExce case "--exclude-packages-from-modules": case "--exclude-unexported-packages-from-modules": if (!ImageInfo.inImageCode()) { - if (rootNode != null) { + if (filterModified) { throw new UsageException(current + " must be specified before other rule-creating arguments"); } + filterModified = true; String[] moduleNames = (value != null) ? value.split(",") : new String[0]; - RuleNode.Inclusion exportedInclusion = current.startsWith("--include") ? RuleNode.Inclusion.Include : RuleNode.Inclusion.Exclude; + RuleNode.Inclusion exportedInclusion = current.startsWith("--include") ? ConfigurationFilter.Inclusion.Include : ConfigurationFilter.Inclusion.Exclude; RuleNode.Inclusion unexportedInclusion = exportedInclusion; RuleNode.Inclusion rootInclusion = exportedInclusion.invert(); if (current.equals("--exclude-unexported-packages-from-modules")) { - rootInclusion = RuleNode.Inclusion.Include; - exportedInclusion = RuleNode.Inclusion.Include; - unexportedInclusion = RuleNode.Inclusion.Exclude; + rootInclusion = ConfigurationFilter.Inclusion.Include; + exportedInclusion = ConfigurationFilter.Inclusion.Include; + unexportedInclusion = ConfigurationFilter.Inclusion.Exclude; } rootNode = ModuleFilterTools.generateFromModules(moduleNames, rootInclusion, exportedInclusion, unexportedInclusion, reduce); } else { @@ -396,8 +406,8 @@ private static void generateFilterRules(Iterator argsIter) throws IOExce break; case "--input-file": - rootNode = maybeCreateRootNode(rootNode); - new FilterConfigurationParser(rootNode).parseAndRegister(requirePathUri(current, value)); + filterModified = true; + new FilterConfigurationParser(filter).parseAndRegister(requirePathUri(current, value)); break; case "--output-file": @@ -405,26 +415,31 @@ private static void generateFilterRules(Iterator argsIter) throws IOExce break; case "--include-classes": - rootNode = addSingleRule(rootNode, current, value, RuleNode.Inclusion.Include); + filterModified = true; + addSingleRule(rootNode, current, value, ConfigurationFilter.Inclusion.Include); break; case "--exclude-classes": - rootNode = addSingleRule(rootNode, current, value, RuleNode.Inclusion.Exclude); + filterModified = true; + addSingleRule(rootNode, current, value, ConfigurationFilter.Inclusion.Exclude); break; default: throw new UsageException("Unknown argument: " + current); } } - rootNode = maybeCreateRootNode(rootNode); // in case of no inputs rootNode.removeRedundantNodes(); + OutputStream targetStream; if (outputPath != null) { try (FileOutputStream os = new FileOutputStream(outputPath.toFile())) { - rootNode.printJsonTree(os); + targetStream = os; } } else { - rootNode.printJsonTree(System.out); + targetStream = System.out; + } + try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(targetStream))) { + filter.printJson(writer); } } @@ -432,8 +447,7 @@ private static RuleNode maybeCreateRootNode(RuleNode rootNode) { return (rootNode != null) ? rootNode : RuleNode.createRoot(); } - private static RuleNode addSingleRule(RuleNode rootNode, String argName, String qualifiedPkg, RuleNode.Inclusion inclusion) { - RuleNode root = maybeCreateRootNode(rootNode); + private static void addSingleRule(RuleNode root, String argName, String qualifiedPkg, RuleNode.Inclusion inclusion) { if (qualifiedPkg == null || qualifiedPkg.isEmpty()) { throw new UsageException("Argument must be provided for: " + argName); } @@ -442,7 +456,6 @@ private static RuleNode addSingleRule(RuleNode rootNode, String argName, String "or as .** to include all classes in the package and all of its subpackages"); } root.addOrGetChildren(qualifiedPkg, inclusion); - return root; } private static String getResource(String resourceName) { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConditionalConfigurationPredicate.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConditionalConfigurationPredicate.java index 2c233198bce9..2f1fd7b05d1c 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConditionalConfigurationPredicate.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConditionalConfigurationPredicate.java @@ -1,51 +1,47 @@ package com.oracle.svm.configure.config; import java.util.List; -import java.util.Set; import java.util.regex.Pattern; +import com.oracle.svm.configure.filters.ComplexFilter; import com.oracle.svm.core.configure.ConditionalElement; public class ConditionalConfigurationPredicate implements TypeConfiguration.Predicate, ProxyConfiguration.Predicate, ResourceConfiguration.Predicate, SerializationConfiguration.Predicate, PredefinedClassesConfiguration.Predicate { - private final Set classNamePatterns; + private final ComplexFilter filter; - public ConditionalConfigurationPredicate(Set classNamePatterns) { - this.classNamePatterns = classNamePatterns; - } - - private boolean classNameMatchesAny(String className) { - return classNamePatterns.stream().anyMatch(p -> p.matcher(className).find()); + public ConditionalConfigurationPredicate(ComplexFilter filter) { + this.filter = filter; } @Override public boolean testIncludedType(ConditionalElement conditionalElement, ConfigurationType type) { - return classNameMatchesAny(conditionalElement.getCondition().getTypeName()) || classNameMatchesAny(type.getQualifiedJavaName()); + return !filter.includes(conditionalElement.getCondition().getTypeName()) || !filter.includes(type.getQualifiedJavaName()); } @Override public boolean testProxyInterfaceList(ConditionalElement> conditionalElement) { - return classNameMatchesAny(conditionalElement.getCondition().getTypeName()); + return !filter.includes(conditionalElement.getCondition().getTypeName()); } @Override public boolean testIncludedResource(ConditionalElement condition, Pattern pattern) { - return classNameMatchesAny(condition.getCondition().getTypeName()); + return !filter.includes(condition.getCondition().getTypeName()); } @Override public boolean testIncludedBundle(ConditionalElement condition, ResourceConfiguration.BundleConfiguration bundleConfiguration) { - return classNameMatchesAny(condition.getCondition().getTypeName()); + return !filter.includes(condition.getCondition().getTypeName()); } @Override public boolean testSerializationType(SerializationConfigurationType type) { - return classNameMatchesAny(type.getQualifiedJavaName()); + return !filter.includes(type.getQualifiedJavaName()); } @Override public boolean testPredefinedClass(ConfigurationPredefinedClass clazz) { - return clazz.getNameInfo() != null && classNameMatchesAny(clazz.getNameInfo()); + return clazz.getNameInfo() != null && !filter.includes(clazz.getNameInfo()); } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java index 52d8dbffa4de..b6e5480c11c7 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ConfigurationFileCollection.java @@ -180,12 +180,4 @@ private static void loadConfig(Collection configPaths, ConfigurationParser } } } - - private static Path tryGetPath(URI uri) { - try { - return Paths.get(uri); - } catch (Exception e) { - return null; - } - } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ComplexFilter.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ComplexFilter.java new file mode 100644 index 000000000000..de1cc8d941f4 --- /dev/null +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ComplexFilter.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, 2022, 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.configure.filters; + +import com.oracle.svm.configure.json.JsonWriter; + +import java.io.IOException; +import java.util.Map; + +public class ComplexFilter implements ConfigurationFilter { + private final RuleNode ruleNode; + private final RegexFilter regexFilter = new RegexFilter(); + + public ComplexFilter(RuleNode ruleNode) { + this.ruleNode = ruleNode; + } + + @Override + public void printJson(JsonWriter writer) throws IOException { + writer.append('{'); + writer.indent().newline(); + ruleNode.printJson(writer); + regexFilter.printJson(writer); + writer.unindent().newline(); + writer.append('}').newline(); + } + + @Override + public void parseFromJson(Map topJsonObject) { + ruleNode.parseFromJson(topJsonObject); + regexFilter.parseFromJson(topJsonObject); + } + + @Override + public boolean includes(String qualifiedName) { + return ruleNode.includes(qualifiedName) && regexFilter.includes(qualifiedName); + } + + public RuleNode getRuleNode() { + return ruleNode; + } +} diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ConfigurationFilter.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ConfigurationFilter.java new file mode 100644 index 000000000000..c8aad6ab9d83 --- /dev/null +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ConfigurationFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022, 2022, 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.configure.filters; + +import java.io.IOException; +import java.util.Map; + +import com.oracle.svm.configure.json.JsonWriter; + +public interface ConfigurationFilter { + + void printJson(JsonWriter writer) throws IOException; + + void parseFromJson(Map topJsonObject); + + boolean includes(String qualifiedName); + + /** Inclusion status of a filter. */ + enum Inclusion { + Include("+"), + Exclude("-"); + + final String s; + + Inclusion(String s) { + this.s = s; + } + + @Override + public String toString() { + return s; + } + + public Inclusion invert() { + return (this == Include) ? Exclude : Include; + } + } +} diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/FilterConfigurationParser.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/FilterConfigurationParser.java index baf4d2186ac1..c38ade2f9ebc 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/FilterConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/FilterConfigurationParser.java @@ -26,66 +26,23 @@ import java.io.IOException; import java.io.Reader; -import java.util.List; -import java.util.Map; import com.oracle.svm.core.configure.ConfigurationParser; import com.oracle.svm.core.util.json.JSONParser; -import com.oracle.svm.core.util.json.JSONParserException; public class FilterConfigurationParser extends ConfigurationParser { - private final RuleNode rootNode; + private final ConfigurationFilter filter; - public FilterConfigurationParser(RuleNode rootNode) { + public FilterConfigurationParser(ConfigurationFilter filter) { super(true); - assert rootNode != null; - this.rootNode = rootNode; + assert filter != null; + this.filter = filter; } @Override public void parseAndRegister(Reader reader) throws IOException { Object json = new JSONParser(reader).parse(); - parseTopLevelObject(asMap(json, "First level of document must be an object")); + filter.parseFromJson(asMap(json, "First level of document must be an object")); } - private void parseTopLevelObject(Map top) { - Object rulesObject = null; - for (Map.Entry pair : top.entrySet()) { - if ("rules".equals(pair.getKey())) { - rulesObject = pair.getValue(); - } else { - throw new JSONParserException("Unknown attribute '" + pair.getKey() + "' (supported attributes: name) in resource definition"); - } - } - if (rulesObject != null) { - List rulesList = asList(rulesObject, "Attribute 'list' must be a list of rule objects"); - for (Object entryObject : rulesList) { - parseEntry(entryObject); - } - } - } - - private void parseEntry(Object entryObject) { - Map entry = asMap(entryObject, "Filter entries must be objects"); - Object qualified = null; - RuleNode.Inclusion inclusion = null; - String exactlyOneMessage = "Exactly one of attributes 'includeClasses' and 'excludeClasses' must be specified for a filter entry"; - for (Map.Entry pair : entry.entrySet()) { - if (qualified != null) { - throw new JSONParserException(exactlyOneMessage); - } - qualified = pair.getValue(); - if ("includeClasses".equals(pair.getKey())) { - inclusion = RuleNode.Inclusion.Include; - } else if ("excludeClasses".equals(pair.getKey())) { - inclusion = RuleNode.Inclusion.Exclude; - } else { - throw new JSONParserException("Unknown attribute '" + pair.getKey() + "' (supported attributes: 'includeClasses', 'excludeClasses') in filter"); - } - } - if (qualified == null) { - throw new JSONParserException(exactlyOneMessage); - } - rootNode.addOrGetChildren(asString(qualified), inclusion); - } } diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ModuleFilterTools.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ModuleFilterTools.java index 0375f216adbc..23ffa1b13ea4 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ModuleFilterTools.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/ModuleFilterTools.java @@ -29,7 +29,7 @@ import java.util.HashSet; import java.util.Set; -import com.oracle.svm.configure.filters.RuleNode.Inclusion; +import com.oracle.svm.configure.filters.ConfigurationFilter.Inclusion; public class ModuleFilterTools { diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RegexFilter.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RegexFilter.java new file mode 100644 index 000000000000..2b6e6f3cb56f --- /dev/null +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RegexFilter.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022, 2022, 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.configure.filters; + +import static com.oracle.svm.core.configure.ConfigurationParser.asList; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import com.oracle.svm.configure.json.JsonWriter; + +public class RegexFilter implements ConfigurationFilter { + + private final Map> regexPatterns; + + public RegexFilter() { + regexPatterns = new HashMap<>(); + for (Inclusion inclusion : Inclusion.values()) { + regexPatterns.put(inclusion, new HashMap<>()); + } + } + + @Override + public void printJson(JsonWriter writer) throws IOException { + writer.quote("regexRules").append(": [").indent().newline(); + + boolean first = true; + for (Inclusion inclusion : Inclusion.values()) { + for (String pattern : regexPatterns.get(inclusion).keySet()) { + if (first) { + first = false; + } else { + writer.append(',').newline(); + } + writer.append("{").quote(inclusion == Inclusion.Include ? "includeClasses" : "excludeClasses").append(": ").quote(pattern).append("}"); + } + } + + writer.unindent().newline(); + writer.append("]"); + writer.unindent().newline(); + writer.append("}"); + } + + @Override + public void parseFromJson(Map topJsonObject) { + Object regexRules = topJsonObject.get("regexRules"); + if (regexRules != null) { + List patternList = asList(regexRules, "Field 'regexRules' must be a list of objects."); + for (Object patternObject : patternList) { + RuleNode.parseEntry(patternObject, (pattern, inclusion) -> regexPatterns.get(inclusion).computeIfAbsent(pattern, Pattern::compile)); + } + } + } + + private boolean matchesForInclusion(Inclusion inclusion, String qualifiedName) { + return regexPatterns.get(inclusion).values().stream().anyMatch(p -> p.matcher(qualifiedName).matches()); + } + + private boolean hasPatternsForInclusion(Inclusion inclusion) { + return regexPatterns.get(inclusion).size() != 0; + } + + @Override + public boolean includes(String qualifiedName) { + if (hasPatternsForInclusion(Inclusion.Include)) { + if (!matchesForInclusion(Inclusion.Include, qualifiedName)) { + return false; + } + } + if (hasPatternsForInclusion(Inclusion.Exclude)) { + return !matchesForInclusion(Inclusion.Exclude, qualifiedName); + } + return true; + } +} diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RuleNode.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RuleNode.java index 86037e030856..71ba5de361d7 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RuleNode.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/filters/RuleNode.java @@ -25,18 +25,23 @@ package com.oracle.svm.configure.filters; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.StringTokenizer; +import java.util.function.BiConsumer; import com.oracle.svm.configure.json.JsonWriter; +import com.oracle.svm.core.util.json.JSONParserException; + +import static com.oracle.svm.core.configure.ConfigurationParser.asList; +import static com.oracle.svm.core.configure.ConfigurationParser.asMap; +import static com.oracle.svm.core.configure.ConfigurationParser.asString; /** Represents a rule that includes or excludes a set of Java classes. */ -public final class RuleNode { +public final class RuleNode implements ConfigurationFilter { /** Everything that is not included is considered excluded. */ private static final Inclusion DEFAULT_INCLUSION = Inclusion.Exclude; @@ -44,31 +49,10 @@ public final class RuleNode { private static final String CHILDREN_PATTERN = "*"; private static final String DESCENDANTS_PATTERN = "**"; - /** Inclusion status of a {@link RuleNode}. */ - public enum Inclusion { - Include("+"), - Exclude("-"); - - final String s; - - Inclusion(String s) { - this.s = s; - } - - @Override - public String toString() { - return s; - } - - public Inclusion invert() { - return (this == Include) ? Exclude : Include; - } - } - /** The non-qualified name. The qualified name is derived from the names of all parents. */ private final String name; - /** Inclusion for the exact qualified name when queried via {@link #treeIncludes}. */ + /** Inclusion for the exact qualified name when queried via {@link #includes}. */ private Inclusion inclusion; /** Inclusion for immediate children except those in {@link #children}. */ @@ -84,6 +68,12 @@ public static RuleNode createRoot() { return new RuleNode(""); } + public static RuleNode createRootWithIncludedChildren() { + RuleNode root = new RuleNode(""); + root.addOrGetChildren("**", ConfigurationFilter.Inclusion.Include); + return root; + } + private RuleNode(String unqualifiedName) { this.name = unqualifiedName; } @@ -226,17 +216,48 @@ private boolean isRedundantLeaf() { return inclusion == null && childrenInclusion == null && descendantsInclusion == null && isLeafNode(); } - public void printJsonTree(OutputStream out) throws IOException { - try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(out))) { - writer.append('{'); - writer.indent().newline(); - writer.quote("rules").append(": [").indent().newline(); - final boolean[] isFirstRule = {true}; - printJsonEntries(writer, isFirstRule, ""); - writer.unindent().newline(); - writer.append(']').unindent().newline(); - writer.append('}').newline(); + @Override + public void printJson(JsonWriter writer) throws IOException { + writer.quote("rules").append(": [").indent().newline(); + final boolean[] isFirstRule = {true}; + printJsonEntries(writer, isFirstRule, ""); + writer.unindent().newline(); + writer.append(']'); + } + + @Override + public void parseFromJson(Map top) { + Object rulesObject = top.get("rules"); + if (rulesObject != null) { + List rulesList = asList(rulesObject, "Attribute 'list' must be a list of rule objects"); + for (Object entryObject : rulesList) { + parseEntry(entryObject, this::addOrGetChildren); + } + } + } + + public static void parseEntry(Object entryObject, BiConsumer parsedEntryConsumer) { + Map entry = asMap(entryObject, "Filter entries must be objects"); + Object qualified = null; + RuleNode.Inclusion inclusion = null; + String exactlyOneMessage = "Exactly one of attributes 'includeClasses' and 'excludeClasses' must be specified for a filter entry"; + for (Map.Entry pair : entry.entrySet()) { + if (qualified != null) { + throw new JSONParserException(exactlyOneMessage); + } + qualified = pair.getValue(); + if ("includeClasses".equals(pair.getKey())) { + inclusion = ConfigurationFilter.Inclusion.Include; + } else if ("excludeClasses".equals(pair.getKey())) { + inclusion = ConfigurationFilter.Inclusion.Exclude; + } else { + throw new JSONParserException("Unknown attribute '" + pair.getKey() + "' (supported attributes: 'includeClasses', 'excludeClasses') in filter"); + } + } + if (qualified == null) { + throw new JSONParserException(exactlyOneMessage); } + parsedEntryConsumer.accept(asString(qualified), inclusion); } private void printJsonEntries(JsonWriter writer, boolean[] isFirstRule, String parentQualified) throws IOException { @@ -280,7 +301,8 @@ private static void printJsonRule(JsonWriter writer, boolean[] isFirstRule, Stri writer.append("}"); } - public boolean treeIncludes(String qualifiedName) { + @Override + public boolean includes(String qualifiedName) { RuleNode current = this; Inclusion inheritedInclusion = DEFAULT_INCLUSION; StringTokenizer tokenizer = new StringTokenizer(qualifiedName, ".", false); diff --git a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/AccessAdvisor.java b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/AccessAdvisor.java index 774030c5f085..e9acc538b8db 100644 --- a/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/AccessAdvisor.java +++ b/substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/trace/AccessAdvisor.java @@ -28,6 +28,7 @@ import org.graalvm.compiler.phases.common.LazyValue; +import com.oracle.svm.configure.filters.ConfigurationFilter; import com.oracle.svm.configure.filters.RuleNode; /** @@ -55,58 +56,55 @@ public final class AccessAdvisor { private static final RuleNode accessWithoutCallerFilter; static { - internalCallerFilter = RuleNode.createRoot(); - internalCallerFilter.addOrGetChildren("**", RuleNode.Inclusion.Include); - - internalCallerFilter.addOrGetChildren("com.sun.crypto.provider.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("com.sun.java.util.jar.pack.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("com.sun.net.ssl.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("com.sun.nio.file.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("com.sun.nio.sctp.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("com.sun.nio.zipfs.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.io.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.lang.**", RuleNode.Inclusion.Exclude); + internalCallerFilter = RuleNode.createRootWithIncludedChildren(); + + internalCallerFilter.addOrGetChildren("com.sun.crypto.provider.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("com.sun.java.util.jar.pack.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("com.sun.net.ssl.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("com.sun.nio.file.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("com.sun.nio.sctp.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("com.sun.nio.zipfs.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.io.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.lang.**", ConfigurationFilter.Inclusion.Exclude); // The agent should not filter calls from native libraries (JDK11). - internalCallerFilter.addOrGetChildren("java.lang.ClassLoader$NativeLibrary", RuleNode.Inclusion.Include); - internalCallerFilter.addOrGetChildren("java.math.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.net.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.nio.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.text.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.time.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("java.util.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("javax.crypto.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("javax.lang.model.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("javax.net.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("javax.tools.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("jdk.internal.**", RuleNode.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.lang.ClassLoader$NativeLibrary", ConfigurationFilter.Inclusion.Include); + internalCallerFilter.addOrGetChildren("java.math.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.net.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.nio.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.text.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.time.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("java.util.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("javax.crypto.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("javax.lang.model.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("javax.net.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("javax.tools.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("jdk.internal.**", ConfigurationFilter.Inclusion.Exclude); // The agent should not filter calls from native libraries (JDK17). - internalCallerFilter.addOrGetChildren("jdk.internal.loader.NativeLibraries$NativeLibraryImpl", RuleNode.Inclusion.Include); - internalCallerFilter.addOrGetChildren("jdk.jfr.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("jdk.net.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("jdk.nio.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("jdk.vm.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.invoke.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.launcher.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.misc.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.net.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.nio.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.reflect.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.text.**", RuleNode.Inclusion.Exclude); - internalCallerFilter.addOrGetChildren("sun.util.**", RuleNode.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("jdk.internal.loader.NativeLibraries$NativeLibraryImpl", ConfigurationFilter.Inclusion.Include); + internalCallerFilter.addOrGetChildren("jdk.jfr.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("jdk.net.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("jdk.nio.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("jdk.vm.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.invoke.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.launcher.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.misc.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.net.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.nio.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.reflect.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.text.**", ConfigurationFilter.Inclusion.Exclude); + internalCallerFilter.addOrGetChildren("sun.util.**", ConfigurationFilter.Inclusion.Exclude); excludeInaccessiblePackages(internalCallerFilter); internalCallerFilter.removeRedundantNodes(); - internalAccessFilter = RuleNode.createRoot(); - internalAccessFilter.addOrGetChildren("**", RuleNode.Inclusion.Include); + internalAccessFilter = RuleNode.createRootWithIncludedChildren(); excludeInaccessiblePackages(internalAccessFilter); internalAccessFilter.removeRedundantNodes(); - accessWithoutCallerFilter = RuleNode.createRoot(); // in addition to accessFilter - accessWithoutCallerFilter.addOrGetChildren("**", RuleNode.Inclusion.Include); - accessWithoutCallerFilter.addOrGetChildren("jdk.vm.ci.**", RuleNode.Inclusion.Exclude); - accessWithoutCallerFilter.addOrGetChildren("[Ljava.lang.String;", RuleNode.Inclusion.Exclude); + accessWithoutCallerFilter = RuleNode.createRootWithIncludedChildren(); // in addition to accessFilter + accessWithoutCallerFilter.addOrGetChildren("jdk.vm.ci.**", ConfigurationFilter.Inclusion.Exclude); + accessWithoutCallerFilter.addOrGetChildren("[Ljava.lang.String;", ConfigurationFilter.Inclusion.Exclude); // ^ String[]: for command-line argument arrays created before Java main method is called accessWithoutCallerFilter.removeRedundantNodes(); } @@ -117,10 +115,10 @@ public final class AccessAdvisor { * native-image-configure generate-filters --exclude-unexported-packages-from-modules [--reduce] */ private static void excludeInaccessiblePackages(RuleNode rootNode) { - rootNode.addOrGetChildren("com.oracle.graal.**", RuleNode.Inclusion.Exclude); - rootNode.addOrGetChildren("com.oracle.truffle.**", RuleNode.Inclusion.Exclude); - rootNode.addOrGetChildren("org.graalvm.compiler.**", RuleNode.Inclusion.Exclude); - rootNode.addOrGetChildren("org.graalvm.libgraal.**", RuleNode.Inclusion.Exclude); + rootNode.addOrGetChildren("com.oracle.graal.**", ConfigurationFilter.Inclusion.Exclude); + rootNode.addOrGetChildren("com.oracle.truffle.**", ConfigurationFilter.Inclusion.Exclude); + rootNode.addOrGetChildren("org.graalvm.compiler.**", ConfigurationFilter.Inclusion.Exclude); + rootNode.addOrGetChildren("org.graalvm.libgraal.**", ConfigurationFilter.Inclusion.Exclude); } public static RuleNode copyBuiltinCallerFilterTree() { @@ -131,8 +129,8 @@ public static RuleNode copyBuiltinAccessFilterTree() { return internalAccessFilter.copy(); } - private RuleNode callerFilter = internalCallerFilter; - private RuleNode accessFilter = internalAccessFilter; + private ConfigurationFilter callerFilter = internalCallerFilter; + private ConfigurationFilter accessFilter = internalAccessFilter; private boolean heuristicsEnabled = true; private boolean isInLivePhase = false; private int launchPhase = 0; @@ -141,11 +139,11 @@ public void setHeuristicsEnabled(boolean enable) { heuristicsEnabled = enable; } - public void setCallerFilterTree(RuleNode rootNode) { + public void setCallerFilterTree(ConfigurationFilter rootNode) { callerFilter = rootNode; } - public void setAccessFilterTree(RuleNode rootNode) { + public void setAccessFilterTree(ConfigurationFilter rootNode) { accessFilter = rootNode; } @@ -159,14 +157,14 @@ public boolean shouldIgnore(LazyValue queriedClass, LazyValue ca } String qualifiedCaller = callerClass.get(); assert qualifiedCaller == null || qualifiedCaller.indexOf('/') == -1 : "expecting Java-format qualifiers, not internal format"; - if (qualifiedCaller != null && !callerFilter.treeIncludes(qualifiedCaller)) { + if (qualifiedCaller != null && !callerFilter.includes(qualifiedCaller)) { return true; } // NOTE: queriedClass can be null for non-class accesses like resources - if (callerClass.get() == null && queriedClass.get() != null && !accessWithoutCallerFilter.treeIncludes(queriedClass.get())) { + if (callerClass.get() == null && queriedClass.get() != null && !accessWithoutCallerFilter.includes(queriedClass.get())) { return true; } - if (accessFilter != null && queriedClass.get() != null && !accessFilter.treeIncludes(queriedClass.get())) { + if (accessFilter != null && queriedClass.get() != null && !accessFilter.includes(queriedClass.get())) { return true; } return heuristicsEnabled && queriedClass.get() != null && PROXY_CLASS_NAME_PATTERN.matcher(queriedClass.get()).matches(); 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 6ca543ea9b76..7ac92675a997 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 @@ -78,7 +78,7 @@ protected static BufferedReader openReader(URI uri) throws IOException { public abstract void parseAndRegister(Reader reader) throws IOException; @SuppressWarnings("unchecked") - protected static List asList(Object data, String errorMessage) { + public static List asList(Object data, String errorMessage) { if (data instanceof List) { return (List) data; } @@ -86,7 +86,7 @@ protected static List asList(Object data, String errorMessage) { } @SuppressWarnings("unchecked") - protected static Map asMap(Object data, String errorMessage) { + public static Map asMap(Object data, String errorMessage) { if (data instanceof Map) { return (Map) data; } @@ -127,7 +127,7 @@ protected void checkAttributes(Map map, String type, Collection< checkAttributes(map, type, requiredAttrs, Collections.emptyList()); } - protected static String asString(Object value) { + public static String asString(Object value) { if (value instanceof String) { return (String) value; }