Skip to content

Commit

Permalink
Add the capability to filter by regex in filter files
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksandar Gradinac committed Mar 4, 2022
1 parent cda7210 commit 0d6008d
Show file tree
Hide file tree
Showing 15 changed files with 451 additions and 224 deletions.
13 changes: 12 additions & 1 deletion substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -130,8 +130,8 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
boolean experimentalOmitClasspathConfig = false;
boolean build = false;
boolean configurationWithOrigins = false;
Set<String> conditionalConfigUserPackagePrefixes = new HashSet<>();
Set<Pattern> conditionalConfigClassNameExcludePatterns = new HashSet<>();
List<String> conditionalConfigUserPackageFilterFiles = new ArrayList<>();
List<String> conditionalConfigClassNameFilterFiles = new ArrayList<>();
int configWritePeriod = -1; // in seconds
int configWritePeriodInitialDelay = 1; // in seconds
boolean trackReflectionMetadata = true;
Expand Down Expand Up @@ -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=")) {
Expand All @@ -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.");
}

Expand All @@ -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<InterceptedState> interceptedStateSupplier = shouldTraceOriginInformation ? EagerlyLoadedJavaStackAccess.stackAccessSupplier()
: OnDemandJavaStackAccess.stackAccessSupplier();
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -389,7 +404,7 @@ private static <T> 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) {
Expand All @@ -409,15 +424,15 @@ private static int parseIntegerOrNegative(String number) {
}
}

private static boolean parseFilterFiles(RuleNode filter, List<String> filterFiles) {
private static boolean parseFilterFiles(ComplexFilter filter, List<String> filterFiles) {
for (String path : filterFiles) {
try {
new FilterConfigurationParser(filter).parseAndRegister(Paths.get(path).toUri());
} catch (Exception e) {
return error(false, "cannot parse filter file " + path + ": " + e);
}
}
filter.removeRedundantNodes();
filter.getRuleNode().removeRedundantNodes();
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -58,14 +59,14 @@
* configuration. See {@link #createConditionalConfiguration()}
*/
public class ConditionalConfigurationWriter extends ConfigurationWithOriginsTracer implements TracingResultWriter {
private final Set<String> 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<String> 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<MethodInfo, List<MethodCallNode>> mapMethodsToCallNodes() {
Expand Down Expand Up @@ -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<MethodInfo, List<MethodCallNode>> methodCallNodes) {
Expand All @@ -216,7 +217,7 @@ private void propagateConfiguration(Map<MethodInfo, List<MethodCallNode>> method
}

private boolean methodOriginatesFromApplicationPackage(MethodInfo methodInfo) {
return applicationPackagePrefixes.stream().anyMatch(prefix -> methodInfo.getJavaDeclaringClassName().startsWith(prefix));
return userCodeFilter.includes(methodInfo.getJavaDeclaringClassName());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Loading

0 comments on commit 0d6008d

Please sign in to comment.