Skip to content

Commit ab0744a

Browse files
author
Aleksandar Gradinac
committed
Add the capability to filter by regex in filter files
1 parent cda7210 commit ab0744a

File tree

14 files changed

+451
-216
lines changed

14 files changed

+451
-216
lines changed

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,18 @@ def conditional_config_task(native_image):
499499
config_dir = join(svmbuild_dir(), 'cond-config-test-config')
500500
if exists(config_dir):
501501
mx.rmtree(config_dir)
502-
agent_opts = ['config-output-dir=' + config_dir, 'experimental-conditional-configuration-for-packages=com.oracle.svm.configure.test.conditionalconfig']
502+
conditional_config_filter_path = join(svmbuild_dir(), 'conditional-config-filter.json')
503+
with open(conditional_config_filter_path, 'w') as conditional_config_filter:
504+
conditional_config_filter.write(
505+
'''
506+
{
507+
"rules": [
508+
{"includeClasses": "com.oracle.svm.configure.test.conditionalconfig.**"}
509+
]
510+
}
511+
'''
512+
)
513+
agent_opts = ['config-output-dir=' + config_dir, 'experimental-conditional-config-filter-file=' + conditional_config_filter_path]
503514
jvm_unittest(['-agentpath:' + agent_path + '=' + ','.join(agent_opts)]
504515
+ ['com.oracle.svm.configure.test.conditionalconfig.ConfigurationGenerator'])
505516

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@
4141
import java.util.Arrays;
4242
import java.util.ConcurrentModificationException;
4343
import java.util.Date;
44-
import java.util.HashSet;
4544
import java.util.List;
46-
import java.util.Set;
4745
import java.util.TimeZone;
4846
import java.util.concurrent.ScheduledThreadPoolExecutor;
4947
import java.util.concurrent.TimeUnit;
@@ -56,10 +54,10 @@
5654
import org.graalvm.nativeimage.ProcessProperties;
5755
import org.graalvm.nativeimage.hosted.Feature;
5856

57+
import com.oracle.svm.agent.conditionalconfig.ConditionalConfigurationWriter;
5958
import com.oracle.svm.agent.configwithorigins.ConfigurationWithOriginsWriter;
6059
import com.oracle.svm.agent.configwithorigins.MethodInfoRecordKeeper;
6160
import com.oracle.svm.agent.ignoredconfig.AgentMetaInfProcessor;
62-
import com.oracle.svm.agent.conditionalconfig.ConditionalConfigurationWriter;
6361
import com.oracle.svm.agent.stackaccess.EagerlyLoadedJavaStackAccess;
6462
import com.oracle.svm.agent.stackaccess.InterceptedState;
6563
import com.oracle.svm.agent.stackaccess.OnDemandJavaStackAccess;
@@ -70,6 +68,8 @@
7068
import com.oracle.svm.configure.config.ConditionalConfigurationPredicate;
7169
import com.oracle.svm.configure.config.ConfigurationFileCollection;
7270
import com.oracle.svm.configure.config.ConfigurationSet;
71+
import com.oracle.svm.configure.filters.ComplexFilter;
72+
import com.oracle.svm.configure.filters.ConfigurationFilter;
7373
import com.oracle.svm.configure.filters.FilterConfigurationParser;
7474
import com.oracle.svm.configure.filters.RuleNode;
7575
import com.oracle.svm.configure.trace.AccessAdvisor;
@@ -130,8 +130,8 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
130130
boolean experimentalOmitClasspathConfig = false;
131131
boolean build = false;
132132
boolean configurationWithOrigins = false;
133-
Set<String> conditionalConfigUserPackagePrefixes = new HashSet<>();
134-
Set<Pattern> conditionalConfigClassNameExcludePatterns = new HashSet<>();
133+
List<String> conditionalConfigUserPackageFilterFiles = new ArrayList<>();
134+
List<String> conditionalConfigClassNameFilterFiles = new ArrayList<>();
135135
int configWritePeriod = -1; // in seconds
136136
int configWritePeriodInitialDelay = 1; // in seconds
137137
boolean trackReflectionMetadata = true;
@@ -203,12 +203,10 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
203203
build = Boolean.parseBoolean(getTokenValue(token));
204204
} else if (token.equals("experimental-configuration-with-origins")) {
205205
configurationWithOrigins = true;
206-
} else if (token.startsWith("experimental-conditional-config-for-package=")) {
207-
String userPackagePrefix = getTokenValue(token);
208-
conditionalConfigUserPackagePrefixes.add(userPackagePrefix);
209-
} else if (token.startsWith("conditional-config-class-name-exclude-pattern=")) {
210-
String classNamePattern = getTokenValue(token);
211-
conditionalConfigClassNameExcludePatterns.add(Pattern.compile(classNamePattern));
206+
} else if (token.startsWith("experimental-conditional-config-filter-file=")) {
207+
conditionalConfigUserPackageFilterFiles.add(getTokenValue(token));
208+
} else if (token.startsWith("conditional-config-class-name-filter-file=")) {
209+
conditionalConfigClassNameFilterFiles.add(getTokenValue(token));
212210
} else if (token.equals("track-reflection-metadata")) {
213211
trackReflectionMetadata = true;
214212
} else if (token.startsWith("track-reflection-metadata=")) {
@@ -223,7 +221,7 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
223221
inform("no output/build options provided, tracking dynamic accesses and writing configuration to directory: " + configOutputDir);
224222
}
225223

226-
if (configurationWithOrigins && !conditionalConfigUserPackagePrefixes.isEmpty()) {
224+
if (configurationWithOrigins && !conditionalConfigUserPackageFilterFiles.isEmpty()) {
227225
return error(5, "The agent can only be used in either the configuration with origins mode or the predefined classes mode.");
228226
}
229227

@@ -236,29 +234,32 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
236234
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!");
237235
}
238236

239-
RuleNode callerFilter = null;
237+
ComplexFilter callerFilter = null;
238+
RuleNode callerFilterRuleNode = null;
240239
if (!builtinCallerFilter) {
241-
callerFilter = RuleNode.createRoot();
242-
callerFilter.addOrGetChildren("**", RuleNode.Inclusion.Include);
240+
callerFilterRuleNode = RuleNode.createRootWithIncludedChildren();
241+
callerFilter = new ComplexFilter(callerFilterRuleNode);
243242
}
243+
244244
if (!callerFilterFiles.isEmpty()) {
245-
if (callerFilter == null) {
246-
callerFilter = AccessAdvisor.copyBuiltinCallerFilterTree();
245+
if (callerFilterRuleNode == null) {
246+
callerFilterRuleNode = AccessAdvisor.copyBuiltinCallerFilterTree();
247+
callerFilter = new ComplexFilter(callerFilterRuleNode);
247248
}
248249
if (!parseFilterFiles(callerFilter, callerFilterFiles)) {
249250
return 1;
250251
}
251252
}
252253

253-
RuleNode accessFilter = null;
254+
ComplexFilter accessFilter = null;
254255
if (!accessFilterFiles.isEmpty()) {
255-
accessFilter = AccessAdvisor.copyBuiltinAccessFilterTree();
256+
accessFilter = new ComplexFilter(AccessAdvisor.copyBuiltinAccessFilterTree());
256257
if (!parseFilterFiles(accessFilter, accessFilterFiles)) {
257258
return 1;
258259
}
259260
}
260261

261-
boolean shouldTraceOriginInformation = configurationWithOrigins || !conditionalConfigUserPackagePrefixes.isEmpty();
262+
boolean shouldTraceOriginInformation = configurationWithOrigins || !conditionalConfigUserPackageFilterFiles.isEmpty();
262263
final MethodInfoRecordKeeper recordKeeper = new MethodInfoRecordKeeper(shouldTraceOriginInformation);
263264
final Supplier<InterceptedState> interceptedStateSupplier = shouldTraceOriginInformation ? EagerlyLoadedJavaStackAccess.stackAccessSupplier()
264265
: OnDemandJavaStackAccess.stackAccessSupplier();
@@ -307,9 +308,23 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
307308
ConfigurationWithOriginsWriter writer = new ConfigurationWithOriginsWriter(processor, recordKeeper);
308309
tracer = writer;
309310
tracingResultWriter = writer;
310-
} else if (!conditionalConfigUserPackagePrefixes.isEmpty()) {
311-
ConditionalConfigurationPredicate filter = new ConditionalConfigurationPredicate(conditionalConfigClassNameExcludePatterns);
312-
ConditionalConfigurationWriter writer = new ConditionalConfigurationWriter(processor, recordKeeper, conditionalConfigUserPackagePrefixes, filter);
311+
} else if (!conditionalConfigUserPackageFilterFiles.isEmpty()) {
312+
ComplexFilter userCodeFilter = new ComplexFilter(RuleNode.createRoot());
313+
if (!parseFilterFiles(userCodeFilter, conditionalConfigUserPackageFilterFiles)) {
314+
return 2;
315+
}
316+
ComplexFilter classNameFilter;
317+
if (!conditionalConfigClassNameFilterFiles.isEmpty()) {
318+
classNameFilter = new ComplexFilter(RuleNode.createRoot());
319+
if(!parseFilterFiles(classNameFilter, conditionalConfigClassNameFilterFiles)) {
320+
return 3;
321+
}
322+
} else {
323+
classNameFilter = new ComplexFilter(RuleNode.createRootWithIncludedChildren());
324+
}
325+
326+
ConditionalConfigurationPredicate predicate = new ConditionalConfigurationPredicate(classNameFilter);
327+
ConditionalConfigurationWriter writer = new ConditionalConfigurationWriter(processor, recordKeeper, userCodeFilter, predicate);
313328
tracer = writer;
314329
tracingResultWriter = writer;
315330
} else {
@@ -389,7 +404,7 @@ private static <T> T usage(T result, String message) {
389404
return result;
390405
}
391406

392-
private static AccessAdvisor createAccessAdvisor(boolean builtinHeuristicFilter, RuleNode callerFilter, RuleNode accessFilter) {
407+
private static AccessAdvisor createAccessAdvisor(boolean builtinHeuristicFilter, ConfigurationFilter callerFilter, ConfigurationFilter accessFilter) {
393408
AccessAdvisor advisor = new AccessAdvisor();
394409
advisor.setHeuristicsEnabled(builtinHeuristicFilter);
395410
if (callerFilter != null) {
@@ -409,15 +424,15 @@ private static int parseIntegerOrNegative(String number) {
409424
}
410425
}
411426

412-
private static boolean parseFilterFiles(RuleNode filter, List<String> filterFiles) {
427+
private static boolean parseFilterFiles(ComplexFilter filter, List<String> filterFiles) {
413428
for (String path : filterFiles) {
414429
try {
415430
new FilterConfigurationParser(filter).parseAndRegister(Paths.get(path).toUri());
416431
} catch (Exception e) {
417432
return error(false, "cannot parse filter file " + path + ": " + e);
418433
}
419434
}
420-
filter.removeRedundantNodes();
435+
filter.getRuleNode().removeRedundantNodes();
421436
return true;
422437
}
423438

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/conditionalconfig/ConditionalConfigurationWriter.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.Map;
3636
import java.util.Set;
3737

38+
import com.oracle.svm.configure.filters.ComplexFilter;
3839
import org.graalvm.nativeimage.impl.ConfigurationCondition;
3940

4041
import com.oracle.svm.agent.configwithorigins.ConfigurationWithOriginsTracer;
@@ -58,14 +59,14 @@
5859
* configuration. See {@link #createConditionalConfiguration()}
5960
*/
6061
public class ConditionalConfigurationWriter extends ConfigurationWithOriginsTracer implements TracingResultWriter {
61-
private final Set<String> applicationPackagePrefixes;
62+
private final ComplexFilter userCodeFilter;
6263
private ConfigurationSet configurationContainer = new ConfigurationSet();
63-
private final ConditionalConfigurationPredicate filter;
64+
private final ConditionalConfigurationPredicate predicate;
6465

65-
public ConditionalConfigurationWriter(TraceProcessor processor, MethodInfoRecordKeeper methodInfoRecordKeeper, Set<String> applicationPackagePrefixes, ConditionalConfigurationPredicate filter) {
66+
public ConditionalConfigurationWriter(TraceProcessor processor, MethodInfoRecordKeeper methodInfoRecordKeeper, ComplexFilter userCodeFilter, ConditionalConfigurationPredicate predicate) {
6667
super(processor, methodInfoRecordKeeper);
67-
this.applicationPackagePrefixes = applicationPackagePrefixes;
68-
this.filter = filter;
68+
this.userCodeFilter = userCodeFilter;
69+
this.predicate = predicate;
6970
}
7071

7172
private Map<MethodInfo, List<MethodCallNode>> mapMethodsToCallNodes() {
@@ -195,7 +196,7 @@ private void addConfigurationWithCondition(ConfigurationSet nodeConfig, Configur
195196
}
196197

197198
private void filterConfiguration() {
198-
configurationContainer = configurationContainer.filter(filter);
199+
configurationContainer = configurationContainer.filter(predicate);
199200
}
200201

201202
private void propagateConfiguration(Map<MethodInfo, List<MethodCallNode>> methodCallNodes) {
@@ -216,7 +217,7 @@ private void propagateConfiguration(Map<MethodInfo, List<MethodCallNode>> method
216217
}
217218

218219
private boolean methodOriginatesFromApplicationPackage(MethodInfo methodInfo) {
219-
return applicationPackagePrefixes.stream().anyMatch(prefix -> methodInfo.getJavaDeclaringClassName().startsWith(prefix));
220+
return userCodeFilter.includes(methodInfo.getJavaDeclaringClassName());
220221
}
221222

222223
@Override

substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/conditionalconfig/ConfigurationVerifier.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,7 @@ private static ConfigurationSet loadExpectedConfig() throws Exception {
8787
try {
8888
String resourceName = "config-dir/" + resourceFileName;
8989
URL resourceURL = ConfigurationVerifier.class.getResource(resourceName);
90-
if (resourceURL == null) {
91-
Assert.fail("Configuration file " + resourceName + " does not exist. Make sure that the test or the config directory have not been moved.");
92-
}
93-
return resourceURL.toURI();
90+
return resourceURL == null ? null : resourceURL.toURI();
9491
} catch (Exception e) {
9592
throw VMError.shouldNotReachHere("Unexpected error while locating the configuration files.", e);
9693
}

0 commit comments

Comments
 (0)