Skip to content

Commit a461aa0

Browse files
author
Aleksandar Gradinac
committed
[GR-30201] Introduce a native-image-agent and native-image-configure option to ignore previous configuration.
PullRequest: graal/8563
2 parents cf65f54 + a987c14 commit a461aa0

35 files changed

+1260
-166
lines changed

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ def _native_unittest(native_image, cmdline_args):
506506
except IOError:
507507
mx.log('warning: could not read blacklist: ' + blacklist)
508508

509-
unittest_args = unmask(pargs.unittest_args) if unmask(pargs.unittest_args) else ['com.oracle.svm.test']
509+
unittest_args = unmask(pargs.unittest_args) if unmask(pargs.unittest_args) else ['com.oracle.svm.test', 'com.oracle.svm.configure.test']
510510
_native_junit(native_image, unittest_args, unmask(pargs.build_args), unmask(pargs.run_args), blacklist, whitelist, pargs.preserve_image)
511511

512512

@@ -848,7 +848,8 @@ def _native_image_launcher_extra_jvm_args():
848848
'substratevm:SVM_AGENT',
849849
],
850850
build_args=[
851-
'--features=com.oracle.svm.agent.NativeImageAgent$RegistrationFeature'
851+
'--features=com.oracle.svm.agent.NativeImageAgent$RegistrationFeature',
852+
'--enable-url-protocols=jar',
852853
],
853854
),
854855
mx_sdk_vm.LibraryConfig(

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

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
import java.util.concurrent.ScheduledThreadPoolExecutor;
4242
import java.util.concurrent.TimeUnit;
4343
import java.util.function.Function;
44+
import java.util.function.Predicate;
4445
import java.util.function.Supplier;
4546
import java.util.regex.Pattern;
4647

48+
import com.oracle.svm.agent.ignoredconfig.AgentMetaInfProcessor;
4749
import com.oracle.svm.agent.stackaccess.InterceptedState;
4850
import com.oracle.svm.agent.stackaccess.EagerlyLoadedJavaStackAccess;
4951
import com.oracle.svm.agent.stackaccess.OnDemandJavaStackAccess;
@@ -52,6 +54,8 @@
5254
import com.oracle.svm.agent.tracing.core.Tracer;
5355
import com.oracle.svm.agent.tracing.core.TracingResultWriter;
5456
import com.oracle.svm.core.configure.ConfigurationFile;
57+
import com.oracle.svm.driver.metainf.NativeImageMetaInfWalker;
58+
import org.graalvm.nativeimage.Platform;
5559
import org.graalvm.nativeimage.ProcessProperties;
5660
import org.graalvm.nativeimage.hosted.Feature;
5761

@@ -104,12 +108,14 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
104108
String traceOutputFile = null;
105109
String configOutputDir = null;
106110
ConfigurationSet mergeConfigs = new ConfigurationSet();
111+
ConfigurationSet omittedConfigs = new ConfigurationSet();
107112
boolean builtinCallerFilter = true;
108113
boolean builtinHeuristicFilter = true;
109114
List<String> callerFilterFiles = new ArrayList<>();
110115
List<String> accessFilterFiles = new ArrayList<>();
111116
boolean experimentalClassLoaderSupport = true;
112117
boolean experimentalClassDefineSupport = false;
118+
boolean experimentalOmitClasspathConfig = false;
113119
boolean build = false;
114120
boolean configurationWithOrigins = false;
115121
int configWritePeriod = -1; // in seconds
@@ -130,6 +136,14 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
130136
if (token.startsWith("config-merge-dir=")) {
131137
mergeConfigs.addDirectory(Paths.get(configOutputDir));
132138
}
139+
} else if (token.startsWith("config-to-omit=")) {
140+
String omittedConfigDir = getTokenValue(token);
141+
omittedConfigDir = transformPath(omittedConfigDir);
142+
omittedConfigs.addDirectory(Paths.get(omittedConfigDir));
143+
} else if (token.equals("experimental-omit-config-from-classpath")) {
144+
experimentalOmitClasspathConfig = true;
145+
} else if (token.startsWith("experimental-omit-config-from-classpath=")) {
146+
experimentalOmitClasspathConfig = Boolean.parseBoolean(getTokenValue(token));
133147
} else if (token.startsWith("restrict-all-dir") || token.equals("restrict") || token.startsWith("restrict=")) {
134148
warn("restrict mode is no longer supported, ignoring option: " + token);
135149
} else if (token.equals("no-builtin-caller-filter")) {
@@ -235,7 +249,23 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
235249
}
236250
return e; // rethrow
237251
};
252+
if (experimentalOmitClasspathConfig) {
253+
ignoreConfigFromClasspath(jvmti, omittedConfigs);
254+
}
238255
AccessAdvisor advisor = createAccessAdvisor(builtinHeuristicFilter, callerFilter, accessFilter);
256+
TraceProcessor omittedConfigProcessor = null;
257+
Predicate<String> shouldExcludeClassesWithHash = null;
258+
if (!omittedConfigs.isEmpty()) {
259+
Function<IOException, Exception> ignore = e -> {
260+
warn("Failed to load omitted config: " + e);
261+
return null;
262+
};
263+
omittedConfigProcessor = new TraceProcessor(advisor, omittedConfigs.loadJniConfig(ignore), omittedConfigs.loadReflectConfig(ignore),
264+
omittedConfigs.loadProxyConfig(ignore), omittedConfigs.loadResourceConfig(ignore), omittedConfigs.loadSerializationConfig(ignore),
265+
omittedConfigs.loadPredefinedClassesConfig(null, null, ignore), null);
266+
shouldExcludeClassesWithHash = omittedConfigProcessor.getPredefinedClassesConfiguration()::containsClassWithHash;
267+
}
268+
239269
Path[] predefinedClassDestinationDirs = {configOutputDirPath.resolve(ConfigurationFile.PREDEFINED_CLASSES_AGENT_EXTRACTED_SUBDIR)};
240270
if (configurationWithOrigins) {
241271
ConfigurationWithOriginsResultWriter writer = new ConfigurationWithOriginsResultWriter(advisor, recordKeeper);
@@ -244,7 +274,7 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
244274
} else {
245275
TraceProcessor processor = new TraceProcessor(advisor, mergeConfigs.loadJniConfig(handler), mergeConfigs.loadReflectConfig(handler),
246276
mergeConfigs.loadProxyConfig(handler), mergeConfigs.loadResourceConfig(handler), mergeConfigs.loadSerializationConfig(handler),
247-
mergeConfigs.loadPredefinedClassesConfig(predefinedClassDestinationDirs, handler));
277+
mergeConfigs.loadPredefinedClassesConfig(predefinedClassDestinationDirs, shouldExcludeClassesWithHash, handler), omittedConfigProcessor);
248278
ConfigurationResultWriter writer = new ConfigurationResultWriter(processor);
249279
tracer = writer;
250280
tracingResultWriter = writer;
@@ -360,6 +390,30 @@ private void setupExecutorServiceForPeriodicConfigurationCapture(int writePeriod
360390
initialDelay, writePeriod, TimeUnit.SECONDS);
361391
}
362392

393+
private static void ignoreConfigFromClasspath(JvmtiEnv jvmti, ConfigurationSet ignoredConfigSet) {
394+
String classpath = Support.getSystemProperty(jvmti, "java.class.path");
395+
String sep = Support.getSystemProperty(jvmti, "path.separator");
396+
if (sep == null) {
397+
if (Platform.includedIn(Platform.LINUX.class) || Platform.includedIn(Platform.DARWIN.class)) {
398+
sep = ":";
399+
} else if (Platform.includedIn(Platform.WINDOWS.class)) {
400+
sep = "[:;]";
401+
} else {
402+
warn("Running on unknown platform. Not omitting existing config from classpath.");
403+
return;
404+
}
405+
}
406+
407+
AgentMetaInfProcessor processor = new AgentMetaInfProcessor(ignoredConfigSet);
408+
for (String cpEntry : classpath.split(sep)) {
409+
try {
410+
NativeImageMetaInfWalker.walkMetaInfForCPEntry(Paths.get(cpEntry), processor);
411+
} catch (NativeImageMetaInfWalker.MetaInfWalkException e) {
412+
warn("Failed to walk the classpath entry: " + cpEntry + " Reason: " + e);
413+
}
414+
}
415+
}
416+
363417
private static final Pattern propertyBlacklist = Pattern.compile("(java\\..*)|(sun\\..*)|(jvmci\\..*)");
364418
private static final Pattern propertyWhitelist = Pattern.compile("(java\\.library\\.path)|(java\\.io\\.tmpdir)");
365419

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.agent.ignoredconfig;
26+
27+
import java.nio.file.Path;
28+
29+
import com.oracle.svm.configure.config.ConfigurationSet;
30+
import com.oracle.svm.driver.metainf.MetaInfFileType;
31+
import com.oracle.svm.driver.metainf.NativeImageMetaInfResourceProcessor;
32+
33+
public class AgentMetaInfProcessor implements NativeImageMetaInfResourceProcessor {
34+
35+
private ConfigurationSet ignoredConfigSet;
36+
37+
public AgentMetaInfProcessor(ConfigurationSet ignoredConfigSet) {
38+
this.ignoredConfigSet = ignoredConfigSet;
39+
}
40+
41+
@Override
42+
public void processMetaInfResource(Path classpathEntry, Path resourceRoot, Path resourcePath, MetaInfFileType type) throws Exception {
43+
ignoredConfigSet.addDirectory(resourcePath.getParent());
44+
}
45+
46+
@Override
47+
public void showWarning(String message) {
48+
}
49+
50+
@Override
51+
public void showVerboseMessage(String message) {
52+
}
53+
54+
@Override
55+
public boolean isExcluded(Path resourcePath, Path classpathEntry) {
56+
return false;
57+
}
58+
}

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/predicatedconfig/ConfigurationWithOriginsResultWriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ private TraceProcessor createNewTraceProcessor() {
9898
ProxyConfiguration proxyConfig = new ProxyConfiguration();
9999
ResourceConfiguration resourceConfig = new ResourceConfiguration();
100100
SerializationConfiguration serializationConfiguration = new SerializationConfiguration();
101-
PredefinedClassesConfiguration predefinedClassesConfiguration = new PredefinedClassesConfiguration(new Path[0]);
102-
return new TraceProcessor(advisor, jniConfig, reflectConfig, proxyConfig, resourceConfig, serializationConfiguration, predefinedClassesConfiguration);
101+
PredefinedClassesConfiguration predefinedClassesConfiguration = new PredefinedClassesConfiguration(new Path[0], null);
102+
return new TraceProcessor(advisor, jniConfig, reflectConfig, proxyConfig, resourceConfig, serializationConfiguration, predefinedClassesConfiguration, null);
103103
}
104104

105105
private static final class MethodCallNode {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Args = -H:IncludeResources=com/oracle/svm/configure/test/config/.*json

0 commit comments

Comments
 (0)