Skip to content

Commit f16e655

Browse files
committed
[GR-55708] Add premain for static agent support.
PullRequest: graal/18656
2 parents 46e1782 + 15ea8f9 commit f16e655

File tree

14 files changed

+810
-4
lines changed

14 files changed

+810
-4
lines changed

substratevm/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
This changelog summarizes major changes to GraalVM Native Image.
44

55
## GraalVM for JDK 24 (Internal Version 24.2.0)
6+
* (GR-55708) (Alibaba contribution) Support for running premain of java agents at runtime as an experimental feature. At build time, `-H:PremainClasses= option` is used to set the premain classes.
7+
At runtime, premain runtime options are set along with main class' arguments in the format of `-XX-premain:[class]:[options]`.
68
* (GR-54476): Issue a deprecation warning on first use of a legacy `graal.` prefix (see GR-49960 in [Compiler changelog](../compiler/CHANGELOG.md)).
79
The warning is planned to be replaced by an error in GraalVM for JDK 25.
810
* (GR-48384) Added a GDB Python script (`gdb-debughelpers.py`) to improve the Native Image debugging experience.
@@ -95,7 +97,7 @@ This changelog summarizes major changes to GraalVM Native Image.
9597
* (GR-42467) The search path for `System.loadLibrary()` by default includes the directory containing the native image.
9698
* (GR-44216) Native Image is now shipped as part of the GraalVM JDK and thus no longer needs to be installed via `gu install native-image`.
9799
* (GR-44105) A warning is displayed when trying to generate debug info on macOS since that is not supported. It is now an error to use `-H:+StripDebugInfo` on macOS or `-H:-StripDebugInfo` on Windows since those values are not supported.
98-
* (GR-43966) Remove analysis options -H:AnalysisStatisticsFile and -H:ImageBuildStatisticsFile. Output files are now written to fixed subdirectories relative to image location (reports/image_build_statistics.json).
100+
* (GR-43966) Remove analysis options -H:AnalysisStatisticsFile and -H:ImageBuildStatisticsFile. Output files are now written to fixed subdirectories relative to image location (reports/image_build_statistics.json).
99101
* (GR-38414) BellSoft implemented the `MemoryPoolMXBean` for the serial and epsilon GCs.
100102
* (GR-40641) Dynamic linking of AWT libraries on Linux.
101103
* (GR-40463) Red Hat added experimental support for JMX, which can be enabled with the `--enable-monitoring` option (e.g. `--enable-monitoring=jmxclient,jmxserver`).

substratevm/ci/ci.jsonnet

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@
122122
// but since we support JDK 21 anyways, there is not good reason to do so.
123123
"linux:amd64:jdk21": gate + t("30:00"),
124124
}),
125-
"basics": mxgate("build,helloworld,native_unittests,truffle_unittests,debuginfotest,hellomodule") + maven + jsonschema + platform_spec(no_jobs) + platform_spec({
125+
"basics": mxgate("build,helloworld,native_unittests,truffle_unittests,debuginfotest,hellomodule,java_agent") + maven + jsonschema + platform_spec(no_jobs) + platform_spec({
126126
"linux:amd64:jdk-latest": gate + gdb("10.2") + t("55:00"),
127127
"windows:amd64:jdk-latest": gate + t("1:30:00"),
128128
}) + variants({

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ def __getattr__(self, name):
210210
'truffle_unittests',
211211
'check_libcontainer_annotations',
212212
'check_libcontainer_namespace',
213+
'java_agent'
213214
])
214215

215216
def vm_native_image_path(config=None):
@@ -510,6 +511,9 @@ def help_stdout_check(output):
510511
except SchemaError as e:
511512
mx.abort(f'JSON schema not valid: {e}')
512513

514+
with Task('java agent tests', tasks, tags=[GraalTags.java_agent]) as t:
515+
if t:
516+
java_agent_test(args.extra_image_builder_arguments)
513517

514518
def native_unittests_task(extra_build_args=None):
515519
if mx.is_windows():
@@ -1729,6 +1733,44 @@ def cinterfacetutorial(args):
17291733
native_image_context_run(_cinterfacetutorial, args)
17301734

17311735

1736+
@mx.command(suite.name, 'javaagenttest', 'Runs tests for java agent with native image')
1737+
def java_agent_test(args):
1738+
def build_and_run(args, binary_path, native_image, agents, agents_arg):
1739+
test_cp = os.pathsep.join([classpath('com.oracle.svm.test')] + agents)
1740+
native_agent_premain_options = ['-XXpremain:com.oracle.svm.test.javaagent.agent1.TestJavaAgent1:test.agent1=true', '-XXpremain:com.oracle.svm.test.javaagent.agent2.TestJavaAgent2:test.agent2=true']
1741+
image_args = ['-cp', test_cp, '-J-ea', '-J-esa', '-H:+ReportExceptionStackTraces', '-H:Class=com.oracle.svm.test.javaagent.AgentTest']
1742+
native_image(image_args + svm_experimental_options(['-H:PremainClasses=' + agents_arg]) + ['-o', binary_path] + args)
1743+
mx.run([binary_path] + native_agent_premain_options)
1744+
1745+
def build_and_test_java_agent_image(native_image, args):
1746+
args = [] if args is None else args
1747+
build_dir = join(svmbuild_dir(), 'javaagenttest')
1748+
1749+
# clean / create output directory
1750+
if exists(build_dir):
1751+
mx.rmtree(build_dir)
1752+
mx_util.ensure_dir_exists(build_dir)
1753+
with mx.TempDir() as tmp_dir:
1754+
test_classpath = mx.dependency('com.oracle.svm.test').classpath_repr()
1755+
# Create agent jar files
1756+
# Note: we are not using MX here to avoid polluting the suite.py and requiring extra build flags
1757+
mx.log("Building agent jars from " + test_classpath)
1758+
agents = []
1759+
for i in range(1, 2):
1760+
agent = join(tmp_dir, "testagent%d.jar" % (i))
1761+
agent_test_classpath = join(test_classpath, 'com', 'oracle', 'svm', 'test', 'javaagent', 'agent' + str(i))
1762+
class_list = [join(test_classpath, 'com', 'oracle', 'svm', 'test', 'javaagent', 'agent' + str(i), f) for f in os.listdir(agent_test_classpath) if os.path.isfile(os.path.join(agent_test_classpath, f)) and f.endswith(".class")]
1763+
mx.run([mx.get_jdk().jar, 'cmf', join(test_classpath, 'resources', 'javaagent' + str(i), 'MANIFEST.MF'), agent] + class_list, cwd = tmp_dir)
1764+
agents.append(agent)
1765+
1766+
mx.log("Building images with different agent orders ")
1767+
build_and_run(args, join(tmp_dir, 'agenttest1'), native_image, agents,'com.oracle.svm.test.javaagent.agent1.TestJavaAgent1,com.oracle.svm.test.javaagent.agent2.TestJavaAgent2')
1768+
1769+
# Switch the premain sequence of agent1 and agent2
1770+
build_and_run(args, join(tmp_dir, 'agenttest2'), native_image, agents, 'com.oracle.svm.test.javaagent.agent2.TestJavaAgent2,com.oracle.svm.test.javaagent.agent1.TestJavaAgent1')
1771+
1772+
native_image_context_run(build_and_test_java_agent_image, args)
1773+
17321774
@mx.command(suite.name, 'clinittest', 'Runs the ')
17331775
def clinittest(args):
17341776
def build_and_test_clinittest_image(native_image, args):

substratevm/mx.substratevm/suite.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@
308308
"jdk.internal.util",
309309
"jdk.internal.org.objectweb.asm",
310310
],
311+
"java.instrument":[
312+
"java.lang.instrument"
313+
],
311314
"java.management": [
312315
"com.sun.jmx.mbeanserver",
313316
"sun.management",
@@ -641,6 +644,9 @@
641644
"sun.util.locale",
642645
"sun.invoke.util",
643646
],
647+
"java.instrument":[
648+
"java.lang.instrument"
649+
],
644650
"java.management": [
645651
"com.sun.jmx.mbeanserver", # Needed for javadoc links (MXBeanIntrospector,DefaultMXBeanMappingFactory, MXBeanProxy)
646652
"sun.management", # Needed for javadoc links (MappedMXBeanType)
@@ -981,6 +987,7 @@
981987
"jdk.jfr",
982988
"java.management",
983989
"jdk.management.jfr",
990+
"java.instrument",
984991
"java.rmi",
985992
],
986993
"requiresConcealed" : {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/JavaMainWrapper.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,19 +166,22 @@ public List<String> getInputArguments() {
166166
}
167167

168168
public static void invokeMain(String[] args) throws Throwable {
169+
PreMainSupport preMainSupport = ImageSingletons.lookup(PreMainSupport.class);
170+
String[] mainArgs = preMainSupport.retrievePremainArgs(args);
171+
preMainSupport.invokePremain();
169172
JavaMainSupport javaMainSupport = ImageSingletons.lookup(JavaMainSupport.class);
170173
if (javaMainSupport.mainNonstatic) {
171174
Object instance = javaMainSupport.javaMainClassCtorHandle.invoke();
172175
if (javaMainSupport.mainWithoutArgs) {
173176
javaMainSupport.javaMainHandle.invoke(instance);
174177
} else {
175-
javaMainSupport.javaMainHandle.invoke(instance, args);
178+
javaMainSupport.javaMainHandle.invoke(instance, mainArgs);
176179
}
177180
} else {
178181
if (javaMainSupport.mainWithoutArgs) {
179182
javaMainSupport.javaMainHandle.invokeExact();
180183
} else {
181-
javaMainSupport.javaMainHandle.invokeExact(args);
184+
javaMainSupport.javaMainHandle.invokeExact(mainArgs);
182185
}
183186
}
184187
}

0 commit comments

Comments
 (0)