Skip to content

Commit 15ea8f9

Browse files
committed
Last touches to the premain PR
1 parent e157a27 commit 15ea8f9

File tree

12 files changed

+73
-83
lines changed

12 files changed

+73
-83
lines changed

substratevm/CHANGELOG.md

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

55
## GraalVM for JDK 24 (Internal Version 24.2.0)
6-
* Together with Alibaba, we added java agent support for native image as experimental feature.
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]`.
78
* (GR-54476): Issue a deprecation warning on first use of a legacy `graal.` prefix (see GR-49960 in [Compiler changelog](../compiler/CHANGELOG.md)).
89
The warning is planned to be replaced by an error in GraalVM for JDK 25.
910
* (GR-48384) Added a GDB Python script (`gdb-debughelpers.py`) to improve the Native Image debugging experience.
@@ -96,7 +97,7 @@ This changelog summarizes major changes to GraalVM Native Image.
9697
* (GR-42467) The search path for `System.loadLibrary()` by default includes the directory containing the native image.
9798
* (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`.
9899
* (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.
99-
* (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).
100101
* (GR-38414) BellSoft implemented the `MemoryPoolMXBean` for the serial and epsilon GCs.
101102
* (GR-40641) Dynamic linking of AWT libraries on Linux.
102103
* (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: 33 additions & 51 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():
@@ -1730,64 +1734,42 @@ def cinterfacetutorial(args):
17301734

17311735

17321736
@mx.command(suite.name, 'javaagenttest', 'Runs tests for java agent with native image')
1733-
def agenttest(args):
1734-
def build_and_test_agent_image(native_image, args):
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):
17351746
args = [] if args is None else args
17361747
build_dir = join(svmbuild_dir(), 'javaagenttest')
17371748

17381749
# clean / create output directory
17391750
if exists(build_dir):
17401751
mx.rmtree(build_dir)
17411752
mx_util.ensure_dir_exists(build_dir)
1742-
test_build_output = mx.dependency('com.oracle.svm.test').classpath_repr()
1743-
1744-
# create agent jar file
1745-
agent1 = join(build_dir, 'testagent1.jar')
1746-
mx.run([mx.get_jdk().jar, 'cmf', join(test_build_output, 'resources','agent1', 'MANIFEST.MF'),
1747-
agent1,
1748-
join('com', 'oracle', 'svm', 'test', 'agent', 'Agent.class'),
1749-
join('com', 'oracle', 'svm', 'test', 'agent', 'Agent$DemoTransformer.class'),
1750-
join('com', 'oracle', 'svm', 'test', 'agent', 'AgentPremainHelper.class')],
1751-
cwd = test_build_output)
1752-
1753-
agent2 = join(build_dir, 'testagent2.jar')
1754-
mx.run([mx.get_jdk().jar, 'cmf', join(test_build_output, 'resources','agent2', 'MANIFEST.MF'),
1755-
agent2,
1756-
join('com', 'oracle', 'svm', 'test', 'agent', 'Agent2.class'),
1757-
join('com', 'oracle', 'svm', 'test', 'agent', 'AgentPremainHelper.class')],
1758-
cwd = test_build_output)
1759-
1760-
# build test with agent
1761-
test_cp = os.pathsep.join([classpath('com.oracle.svm.test'), agent1, agent2])
1762-
1763-
1764-
nativeagent_premain_options=['-XXpremain:com.oracle.svm.test.agent.Agent:test.agent=true',
1765-
'-XXpremain:com.oracle.svm.test.agent.Agent2:test.agent2=true']
1766-
1767-
binary_path = join(build_dir, 'agenttest1')
1768-
native_image([
1769-
'-cp', test_cp,
1770-
'-J-ea', '-J-esa',
1771-
'-o', binary_path,
1772-
'-H:+ReportExceptionStackTraces',
1773-
'-H:PremainClasses=com.oracle.svm.test.agent.Agent,com.oracle.svm.test.agent.Agent2',
1774-
'-H:Class=com.oracle.svm.test.agent.AgentTest',
1775-
] + args)
1776-
mx.run([binary_path] + nativeagent_premain_options)
1777-
1778-
# Switch the premain sequence of agent1 and agent2
1779-
binary_path = join(build_dir, 'agenttest2')
1780-
native_image([
1781-
'-cp', test_cp,
1782-
'-J-ea', '-J-esa',
1783-
'-o', binary_path,
1784-
'-H:+ReportExceptionStackTraces',
1785-
'-H:PremainClasses=com.oracle.svm.test.agent.Agent2,com.oracle.svm.test.agent.Agent',
1786-
'-H:Class=com.oracle.svm.test.agent.AgentTest',
1787-
] + args)
1788-
mx.run([binary_path] + nativeagent_premain_options)
1789-
1790-
native_image_context_run(build_and_test_agent_image, args)
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)
17911773

17921774
@mx.command(suite.name, 'clinittest', 'Runs the ')
17931775
def clinittest(args):

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ public class PreMainSupport {
100100
record PremainMethod(String className, Method method, Object[] args) {
101101
}
102102

103-
private Map<String, String> premainOptions = new HashMap<>();
103+
private final Map<String, String> premainOptions = new HashMap<>();
104104
// Order matters
105-
private List<PremainMethod> premainMethods = new ArrayList<>();
105+
private final List<PremainMethod> premainMethods = new ArrayList<>();
106106

107107
@Platforms({Platform.HOSTED_ONLY.class})
108108
public void registerPremainMethod(String className, Method executable, Object... args) {
@@ -120,8 +120,10 @@ public void registerPremainMethod(String className, Method executable, Object...
120120
* @return arguments for main class
121121
*/
122122
public String[] retrievePremainArgs(String[] args) {
123+
if (args == null) {
124+
return null;
125+
}
123126
List<String> mainArgs = new ArrayList<>();
124-
125127
for (String arg : args) {
126128
if (arg.startsWith(PREMAIN_OPTION_PREFIX)) {
127129
String premainOptionKeyValue = arg.substring(PREMAIN_OPTION_PREFIX.length());
@@ -147,10 +149,11 @@ public void invokePremain() {
147149
// premain method must be static
148150
premainMethod.method.invoke(null, args);
149151
} catch (Throwable t) {
152+
Throwable cause = t;
150153
if (t instanceof InvocationTargetException) {
151-
t = t.getCause();
154+
cause = t.getCause();
152155
}
153-
VMError.shouldNotReachHere("Fail to execute " + premainMethod.className + ".premain", t);
156+
VMError.shouldNotReachHere("Fail to execute " + premainMethod.className + ".premain", cause);
154157
}
155158
}
156159
}

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/agent/AgentPremainHelper.java renamed to substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/javaagent/AgentPremainHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* questions.
2525
*/
2626

27-
package com.oracle.svm.test.agent;
27+
package com.oracle.svm.test.javaagent;
2828

2929
public class AgentPremainHelper {
3030
public static void load(Class<?> agentClass) {

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/agent/AgentTest.java renamed to substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/javaagent/AgentTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
* questions.
2525
*/
2626

27-
package com.oracle.svm.test.agent;
27+
package com.oracle.svm.test.javaagent;
2828

29+
import com.oracle.svm.test.javaagent.agent1.TestJavaAgent1;
30+
import com.oracle.svm.test.javaagent.agent2.TestJavaAgent2;
2931
import org.junit.Assert;
3032

3133
public class AgentTest {
@@ -35,7 +37,7 @@ private static void testPremain() {
3537
}
3638

3739
private static void testAgentOptions() {
38-
Assert.assertEquals("true", System.getProperty("test.agent"));
40+
Assert.assertEquals("true", System.getProperty("test.agent1"));
3941
Assert.assertEquals("true", System.getProperty("test.agent2"));
4042
}
4143

@@ -44,8 +46,8 @@ private static void testPremainSequence() {
4446
String second = AgentPremainHelper.getSecond();
4547
Assert.assertNotNull(first);
4648
if (second != null) {
47-
String agentName = Agent.class.getName();
48-
String agent2Name = Agent2.class.getName();
49+
String agentName = TestJavaAgent1.class.getName();
50+
String agent2Name = TestJavaAgent2.class.getName();
4951

5052
if (first.equals(agentName)) {
5153
Assert.assertEquals(agent2Name, second);

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/agent/Agent.java renamed to substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/javaagent/agent1/TestJavaAgent1.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
* or visit www.oracle.com if you need additional information or have any
2424
* questions.
2525
*/
26-
package com.oracle.svm.test.agent;
26+
package com.oracle.svm.test.javaagent.agent1;
2727

28+
import com.oracle.svm.test.javaagent.AgentPremainHelper;
2829
import org.graalvm.nativeimage.ImageInfo;
2930
import org.junit.Assert;
3031

@@ -34,16 +35,16 @@
3435
import java.util.Collections;
3536
import java.util.Set;
3637

37-
public class Agent {
38+
public class TestJavaAgent1 {
3839
public static void premain(
3940
String agentArgs, Instrumentation inst) {
4041
AgentPremainHelper.parseOptions(agentArgs);
4142
System.setProperty("instrument.enable", "true");
4243
if (!ImageInfo.inImageRuntimeCode()) {
43-
DemoTransformer dt = new DemoTransformer("com.oracle.svm.test.agent.AgentTest");
44+
DemoTransformer dt = new DemoTransformer("com.oracle.svm.test.javaagent.TestJavaAgent1");
4445
inst.addTransformer(dt, true);
4546
} else {
46-
AgentPremainHelper.load(Agent.class);
47+
AgentPremainHelper.load(TestJavaAgent1.class);
4748
/**
4849
* Test {@code inst} is {@link NativeImageNoOpRuntimeInstrumentation} and behaves as
4950
* defined.
@@ -59,7 +60,7 @@ public static void premain(
5960
Assert.assertTrue(allClasses.length > 0);
6061
Class<?> currentAgentClassFromAllLoaded = null;
6162
for (Class<?> c : allClasses) {
62-
if (c.equals(Agent.class)) {
63+
if (c.equals(TestJavaAgent1.class)) {
6364
currentAgentClassFromAllLoaded = c;
6465
}
6566
}
@@ -118,7 +119,7 @@ public static void premain(
118119
Assert.assertEquals(-1, inst.getObjectSize(null));
119120
Assert.assertEquals(false, inst.isNativeMethodPrefixSupported());
120121

121-
Module currentModule = Agent.class.getModule();
122+
Module currentModule = TestJavaAgent1.class.getModule();
122123
Assert.assertEquals(true, inst.isModifiableModule(currentModule));
123124

124125
// redefineModule only does checks, no actual actions.

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/agent/Agent2.java renamed to substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/javaagent/agent2/TestJavaAgent2.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@
2424
* questions.
2525
*/
2626

27-
package com.oracle.svm.test.agent;
27+
package com.oracle.svm.test.javaagent.agent2;
2828

29+
import com.oracle.svm.test.javaagent.AgentPremainHelper;
2930
import org.graalvm.nativeimage.ImageInfo;
3031

31-
public class Agent2 {
32+
public class TestJavaAgent2 {
3233
public static void premain(String agentArgs) {
3334
AgentPremainHelper.parseOptions(agentArgs);
3435
System.setProperty("instrument.enable", "true");
3536
if (!ImageInfo.inImageRuntimeCode()) {
3637
// do class transformation
3738
} else {
38-
AgentPremainHelper.load(Agent2.class);
39+
AgentPremainHelper.load(TestJavaAgent2.class);
3940
}
4041
}
4142
}

substratevm/src/com.oracle.svm.test/src/resources/agent1/MANIFEST.MF

Lines changed: 0 additions & 5 deletions
This file was deleted.

substratevm/src/com.oracle.svm.test/src/resources/agent2/MANIFEST.MF

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)