Skip to content

Commit 08df97d

Browse files
[GR-58546] [GR-59428] [GR-59422] [GR-59440] Allow coverage collection for espresso.
PullRequest: graal/19131
2 parents 482627e + 2ddfc59 commit 08df97d

File tree

13 files changed

+175
-30
lines changed

13 files changed

+175
-30
lines changed

espresso/ci/ci_common/common.jsonnet

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,26 @@ local benchmark_suites = ['dacapo', 'renaissance', 'scala-dacapo'];
170170
// LD_DEBUG=unused is a workaround for: symbol lookup error: jre/lib/amd64/libnio.so: undefined symbol: fstatat64
171171
maybe_set_ld_debug_flag(env): if std.startsWith(env, 'jvm') then [['set-export', 'LD_DEBUG', 'unused']] else [],
172172

173-
espresso_gate(allow_warnings, tags, ld_debug=false, mx_args=[], imports=null, gate_args=[], timelimit='15:00', name=null): {
173+
espresso_gate(allow_warnings, tags, ld_debug=false, mx_args=[], imports=null, gate_args=[], timelimit='15:00', name=null, coverage=false): {
174174
local mx_cmd =
175175
['mx']
176176
+ mx_args
177177
+ (if imports != null then ['--dynamicimports=' + imports] else []),
178178
run+: [
179179
if ld_debug then ['set-export', 'LD_DEBUG', 'unused'] else ['unset', 'LD_DEBUG'],
180-
mx_cmd + ['--strict-compliance', 'gate', '--strict-mode', '--tags', tags] + ( if allow_warnings then ['--no-warning-as-error'] else []) + gate_args,
180+
mx_cmd + ['--strict-compliance', 'gate', '--strict-mode', '--tags', tags]
181+
+ (if allow_warnings then ['--no-warning-as-error'] else [])
182+
+ (if coverage then ['--jacoco-omit-excluded', '--jacoco-relativize-paths', '--jacoco-omit-src-gen', '--jacocout=coverage', '--jacoco-format=lcov'] else [])
183+
+ gate_args,
181184
],
182185
}
183186
+ (if timelimit != null then {timelimit: timelimit} else {})
184-
+ (if name != null then {name: name} else {}),
187+
+ (if name != null then {name: name} else {})
188+
+ (if coverage then {
189+
teardown+: [
190+
['mx', 'sversions', '--print-repositories', '--json', '|', 'coverage-uploader.py', '--associated-repos', '-'],
191+
],
192+
} else {}),
185193

186194
host_jvm(env, java_version): 'graalvm-espresso-' + _base_env(env),
187195
host_jvm_config(env): if std.startsWith(env, 'jvm') then 'jvm' else 'native',

espresso/mx.espresso/mx_espresso.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import mx_pomdistribution
3535
import mx_subst
3636
import mx_util
37+
import mx_gate
3738
import mx_espresso_benchmarks # pylint: disable=unused-import
3839
import mx_sdk_vm
3940
import mx_sdk_vm_impl
@@ -59,23 +60,29 @@ def _espresso_command(launcher, args):
5960

6061
def _espresso_launcher_command(args):
6162
"""Espresso launcher embedded in GraalVM + arguments"""
62-
return _espresso_command('espresso', args)
63+
jacoco_args = ['--vm.' + arg for arg in mx_gate.get_jacoco_agent_args() or []]
64+
return _espresso_command('espresso', jacoco_args + args)
6365

6466

6567
def _java_truffle_command(args):
6668
"""Java launcher using libjavavm in GraalVM + arguments"""
6769
return _espresso_command('java', ['-truffle'] + args)
6870

6971

70-
def _espresso_standalone_command(args, use_optimized_runtime=False, with_sulong=False):
72+
def _espresso_standalone_command(args, use_optimized_runtime=False, with_sulong=False, allow_jacoco=True):
7173
"""Espresso standalone command from distribution jars + arguments"""
7274
vm_args, args = mx.extract_VM_args(args, useDoubleDash=True, defaultAllVMArgs=False)
7375
distributions = ['ESPRESSO', 'ESPRESSO_LAUNCHER', 'ESPRESSO_LIBS_RESOURCES', 'ESPRESSO_RUNTIME_RESOURCES', 'TRUFFLE_NFI_LIBFFI']
7476
if with_sulong:
7577
distributions += ['SULONG_NFI', 'SULONG_NATIVE']
78+
if allow_jacoco:
79+
jacoco_args = ['--vm.' + arg for arg in mx_gate.get_jacoco_agent_args() or []]
80+
else:
81+
jacoco_args = []
7682
return (
7783
vm_args
7884
+ mx.get_runtime_jvm_args(distributions, jdk=mx.get_jdk())
85+
+ jacoco_args
7986
# We are not adding the truffle runtime
8087
+ ['-Dpolyglot.engine.WarnInterpreterOnly=false']
8188
+ [mx.distribution('ESPRESSO_LAUNCHER').mainClass] + args
@@ -124,7 +131,7 @@ def _run_espresso_meta(args, nonZeroIsFatal=True, timeout=None):
124131
"""Run Espresso (standalone) on Espresso (launcher)"""
125132
return _run_espresso_launcher([
126133
'--vm.Xss4m',
127-
] + _espresso_standalone_command(args), nonZeroIsFatal=nonZeroIsFatal, timeout=timeout)
134+
] + _espresso_standalone_command(args, allow_jacoco=False), nonZeroIsFatal=nonZeroIsFatal, timeout=timeout)
128135

129136

130137
class EspressoTags:

espresso/mx.espresso/suite.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
"com.oracle.truffle.espresso.ffi.NativeAccess.Provider",
148148
],
149149
"annotationProcessors": ["truffle:TRUFFLE_DSL_PROCESSOR", "ESPRESSO_PROCESSOR"],
150+
"jacoco" : "include",
150151
"javaCompliance" : "17+",
151152
"checkstyle": "com.oracle.truffle.espresso",
152153
"checkstyleVersion": "10.7.0",
@@ -180,6 +181,7 @@
180181
"sdk:POLYGLOT",
181182
"sdk:LAUNCHER_COMMON",
182183
],
184+
"jacoco" : "include",
183185
"javaCompliance" : "17+",
184186
"checkstyle": "com.oracle.truffle.espresso",
185187
},

espresso/src/com.oracle.truffle.espresso.classfile/src/com/oracle/truffle/espresso/classfile/descriptors/Symbol.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,11 @@ public static void ensureInitialized() {
453453
public static final Symbol<Name> SIG_IGN = StaticSymbols.putName("SIG_IGN");
454454
// sun.misc.NativeSignalHandler
455455
public static final Symbol<Name> handler = StaticSymbols.putName("handler");
456+
// sun.nio.ch.NativeThread
457+
public static final Symbol<Name> isNativeThread = StaticSymbols.putName("isNativeThread");
458+
public static final Symbol<Name> current0 = StaticSymbols.putName("current0");
459+
public static final Symbol<Name> signal = StaticSymbols.putName("signal");
460+
public static final Symbol<Name> init = StaticSymbols.putName("init");
456461

457462
// jdk.internal.util.ArraysSupport
458463
public static final Symbol<Name> vectorizedMismatch = StaticSymbols.putName("vectorizedMismatch");
@@ -688,6 +693,7 @@ public static void ensureInitialized() {
688693
public static final Symbol<Type> java_nio_file_Path = StaticSymbols.putType("Ljava/nio/file/Path;");
689694
public static final Symbol<Type> java_nio_file_Path_array = StaticSymbols.putType("[Ljava/nio/file/Path;");
690695
public static final Symbol<Type> java_nio_file_Paths = StaticSymbols.putType("Ljava/nio/file/Paths;");
696+
public static final Symbol<Type> sun_nio_ch_NativeThread = StaticSymbols.putType("Lsun/nio/ch/NativeThread;");
691697

692698
public static final Symbol<Type> jdk_internal_loader_ClassLoaders = StaticSymbols.putType("Ljdk/internal/loader/ClassLoaders;");
693699
public static final Symbol<Type> jdk_internal_loader_ClassLoaders$PlatformClassLoader = StaticSymbols.putType("Ljdk/internal/loader/ClassLoaders$PlatformClassLoader;");
@@ -1131,6 +1137,7 @@ public static void ensureInitialized() {
11311137
public static final Symbol<Signature> _void_long_long = StaticSymbols.putSignature(Type._void, Type._long, Type._long);
11321138
public static final Symbol<Signature> _boolean_int = StaticSymbols.putSignature(Type._boolean, Type._int);
11331139
public static final Symbol<Signature> _boolean_int_int = StaticSymbols.putSignature(Type._boolean, Type._int, Type._int);
1140+
public static final Symbol<Signature> _boolean_long = StaticSymbols.putSignature(Type._boolean, Type._long);
11341141
public static final Symbol<Signature> _int_int_int = StaticSymbols.putSignature(Type._int, Type._int, Type._int);
11351142
public static final Symbol<Signature> _void_char_array = StaticSymbols.putSignature(Type._void, Type._char_array);
11361143
public static final Symbol<Signature> _void_byte_array = StaticSymbols.putSignature(Type._void, Type._byte_array);

espresso/src/com.oracle.truffle.espresso.native/src/nespresso.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,10 @@ jint GetJavaVM(JNIEnv *env, JavaVM **vmPtr) {
458458
if (vmPtr == NULL) {
459459
return JNI_ERR;
460460
}
461+
if (env == NULL) {
462+
fprintf(stderr, "GetJavaVM: Passed JNIEnv* is NULL" OS_NEWLINE_STR);
463+
return JNI_ERR;
464+
}
461465

462466
moka_env = (MokapotEnv*) (*env)->reserved1;
463467
if (moka_env == NULL) {
@@ -494,16 +498,17 @@ JNIEXPORT JNIEnv* JNICALL initializeNativeContext(void* (*fetch_by_name)(const c
494498
struct JNINativeInterface_* jni_impl = malloc(sizeof(*jni_impl));
495499
struct NespressoEnv* nespresso_env = (struct NespressoEnv*) malloc(sizeof(*nespresso_env));
496500

501+
jni_impl->reserved0 = nespresso_env;
502+
jni_impl->reserved1 = NULL;
503+
jni_impl->reserved2 = NULL;
504+
jni_impl->reserved3 = NULL;
497505
int fnCount = sizeof(*jni_impl) / sizeof(void*);
498-
int i;
499-
for (i = 0; i < fnCount; ++i) {
506+
for (int i = 4; i < fnCount; ++i) {
500507
((void**)jni_impl)[i] = &unset_function_error;
501508
}
502509

503510
*env = jni_impl;
504511

505-
jni_impl->reserved0 = nespresso_env;
506-
507512
// Fetch Java ... varargs methods.
508513
#define INIT_VARARGS_METHOD__(fn_name) \
509514
*(void**)(&nespresso_env->fn_name) = fetch_by_name(#fn_name);

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/ffi/NativeAccess.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
import com.oracle.truffle.api.interop.UnsupportedMessageException;
3636
import com.oracle.truffle.api.interop.UnsupportedTypeException;
3737
import com.oracle.truffle.espresso.EspressoOptions;
38-
import com.oracle.truffle.espresso.meta.EspressoError;
3938
import com.oracle.truffle.espresso.classfile.JavaKind;
39+
import com.oracle.truffle.espresso.meta.EspressoError;
4040
import com.oracle.truffle.espresso.runtime.EspressoProperties;
4141

4242
/**

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/meta/Meta.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,18 @@ public Meta(EspressoContext context) {
378378
java_nio_file_Paths = knownKlass(Type.java_nio_file_Paths);
379379
java_nio_file_Paths_get = java_nio_file_Paths.requireDeclaredMethod(Name.get, Signature.Path_String_String_array);
380380

381+
ObjectKlass nioNativeThreadKlass = knownKlass(Type.sun_nio_ch_NativeThread);
382+
sun_nio_ch_NativeThread_init = nioNativeThreadKlass.lookupDeclaredMethod(Name.init, Signature._void);
383+
if (getJavaVersion().java21OrLater()) {
384+
sun_nio_ch_NativeThread_isNativeThread = nioNativeThreadKlass.requireDeclaredMethod(Name.isNativeThread, Signature._boolean_long);
385+
sun_nio_ch_NativeThread_current0 = nioNativeThreadKlass.requireDeclaredMethod(Name.current0, Signature._long);
386+
sun_nio_ch_NativeThread_signal = null;
387+
} else {
388+
sun_nio_ch_NativeThread_isNativeThread = null;
389+
sun_nio_ch_NativeThread_current0 = null;
390+
sun_nio_ch_NativeThread_signal = nioNativeThreadKlass.requireDeclaredMethod(Name.signal, Signature._void_long);
391+
}
392+
381393
sun_launcher_LauncherHelper = knownKlass(Type.sun_launcher_LauncherHelper);
382394
sun_launcher_LauncherHelper_printHelpMessage = sun_launcher_LauncherHelper.requireDeclaredMethod(Name.printHelpMessage, Signature._void_boolean);
383395
sun_launcher_LauncherHelper_ostream = sun_launcher_LauncherHelper.requireDeclaredField(Name.ostream, Type.java_io_PrintStream);
@@ -1554,6 +1566,11 @@ private DiffVersionLoadHelper diff() {
15541566
public final ObjectKlass java_nio_file_Paths;
15551567
public final Method java_nio_file_Paths_get;
15561568

1569+
public final Method sun_nio_ch_NativeThread_isNativeThread;
1570+
public final Method sun_nio_ch_NativeThread_current0;
1571+
public final Method sun_nio_ch_NativeThread_signal;
1572+
public final Method sun_nio_ch_NativeThread_init;
1573+
15571574
// Array support.
15581575
public final ObjectKlass java_lang_Cloneable;
15591576
public final ObjectKlass java_io_Serializable;

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/AbstractInstrumentableBytecodeNode.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
*/
2323
package com.oracle.truffle.espresso.nodes;
2424

25+
import java.util.ArrayList;
26+
import java.util.HashMap;
27+
2528
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
2629
import com.oracle.truffle.api.frame.Frame;
2730
import com.oracle.truffle.api.frame.MaterializedFrame;
@@ -35,18 +38,15 @@
3538
import com.oracle.truffle.api.library.ExportMessage;
3639
import com.oracle.truffle.api.source.SourceSection;
3740
import com.oracle.truffle.espresso.EspressoScope;
41+
import com.oracle.truffle.espresso.classfile.attributes.Local;
3842
import com.oracle.truffle.espresso.classfile.descriptors.ByteSequence;
3943
import com.oracle.truffle.espresso.classfile.descriptors.Signatures;
4044
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
4145
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Name;
4246
import com.oracle.truffle.espresso.classfile.descriptors.Symbol.Type;
4347
import com.oracle.truffle.espresso.impl.Method;
44-
import com.oracle.truffle.espresso.classfile.attributes.Local;
4548
import com.oracle.truffle.espresso.vm.continuation.UnwindContinuationException;
4649

47-
import java.util.ArrayList;
48-
import java.util.HashMap;
49-
5050
@GenerateWrapper(yieldExceptions = UnwindContinuationException.class, resumeMethodPrefix = "resumeContinuation")
5151
@ExportLibrary(NodeLibrary.class)
5252
abstract class AbstractInstrumentableBytecodeNode extends EspressoInstrumentableNode {
@@ -83,14 +83,15 @@ public final boolean hasScope(@SuppressWarnings("unused") Frame frame) {
8383

8484
@ExportMessage
8585
public final Object getScope(Frame frame, @SuppressWarnings("unused") boolean nodeEnter) {
86-
return getScopeSlowPath(frame != null ? frame.materialize() : null);
86+
return getScopeSlowPath(frame != null ? frame.materialize() : null, getMethod(), getBci(frame));
8787
}
8888

8989
@TruffleBoundary
90-
private Object getScopeSlowPath(MaterializedFrame frame) {
91-
// construct the current scope with valid local variables information
92-
Method method = getMethodVersion().getMethod();
93-
Local[] liveLocals = method.getLocalVariableTable().getLocalsAt(getBci(frame));
90+
private static Object getScopeSlowPath(MaterializedFrame frame, Method method, int bci) {
91+
// NOTE: this might be called while the thread is not entered into the context so
92+
// don't use things like a LanguageReference
93+
// Construct the current scope with valid local variables information
94+
Local[] liveLocals = method.getLocalVariableTable().getLocalsAt(bci);
9495
boolean allParamsIncluded = checkLocals(liveLocals, method);
9596
if (!allParamsIncluded) {
9697
ArrayList<Local> constructedLiveLocals = new ArrayList<>();
@@ -120,7 +121,7 @@ private Object getScopeSlowPath(MaterializedFrame frame) {
120121
for (int i = startslot; i < localCount; i++) {
121122
Symbol<Type> paramType = hasReceiver ? Signatures.parameterType(parsedSignature, i - 1) : Signatures.parameterType(parsedSignature, i);
122123
if (!slotToLocal.containsKey(i)) {
123-
Symbol<Name> localName = getLanguage().getNames().getOrCreate(ByteSequence.create("arg_" + i));
124+
Symbol<Name> localName = method.getLanguage().getNames().getOrCreate(ByteSequence.create("arg_" + i));
124125
constructedLiveLocals.add(new Local(localName, paramType, null, 0, 0xffff, i));
125126
slotToLocal.remove(i);
126127
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/Target_sun_nio_ch_NativeThread.java

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,82 @@
2222
*/
2323
package com.oracle.truffle.espresso.substitutions;
2424

25-
/**
26-
* This substitution is only needed when using the Sulong backend, since installing signal handlers
27-
* is not supported. See GR-29359.
28-
*/
25+
import com.oracle.truffle.api.dsl.Bind;
26+
import com.oracle.truffle.api.dsl.Cached;
27+
import com.oracle.truffle.api.dsl.Specialization;
28+
import com.oracle.truffle.api.nodes.DirectCallNode;
29+
import com.oracle.truffle.espresso.EspressoOptions;
30+
import com.oracle.truffle.espresso.ffi.nfi.NFISulongNativeAccess;
31+
import com.oracle.truffle.espresso.runtime.EspressoContext;
32+
import com.oracle.truffle.espresso.substitutions.VersionFilter.Java17OrEarlier;
33+
import com.oracle.truffle.espresso.substitutions.VersionFilter.Java21OrLater;
34+
2935
@EspressoSubstitutions
3036
public final class Target_sun_nio_ch_NativeThread {
31-
37+
/*
38+
* This doesn't exist on Windows, it just won't match
39+
*/
3240
@Substitution
33-
public static void init() {
34-
// nop
41+
abstract static class Init extends SubstitutionNode {
42+
abstract void execute();
43+
44+
@Specialization
45+
static void doDefault(@Bind("getContext()") EspressoContext context,
46+
@Cached("create(context.getMeta().sun_nio_ch_NativeThread_init.getCallTargetNoSubstitution())") DirectCallNode original) {
47+
// avoid the installation of a signal handler except on SVM and not with llvm
48+
if (EspressoOptions.RUNNING_ON_SVM && !(context.getNativeAccess() instanceof NFISulongNativeAccess)) {
49+
original.call();
50+
}
51+
}
52+
}
53+
54+
@Substitution(versionFilter = Java21OrLater.class)
55+
abstract static class IsNativeThread extends SubstitutionNode {
56+
abstract boolean execute(long tid);
57+
58+
@Specialization
59+
static boolean doDefault(long tid,
60+
@Bind("getContext()") EspressoContext context,
61+
@Cached("create(context.getMeta().sun_nio_ch_NativeThread_isNativeThread.getCallTargetNoSubstitution())") DirectCallNode original) {
62+
if (context.getNativeAccess() instanceof NFISulongNativeAccess) {
63+
// sulong virtualizes pthread_self but not ptrhead_kill
64+
// signal to the JDK that we don't support signaling
65+
return false;
66+
} else {
67+
return (boolean) original.call(tid);
68+
}
69+
}
70+
}
71+
72+
@Substitution(versionFilter = Java21OrLater.class)
73+
abstract static class Current0 extends SubstitutionNode {
74+
abstract long execute();
75+
76+
@Specialization
77+
static long doDefault(@Bind("getContext()") EspressoContext context,
78+
@Cached("create(context.getMeta().sun_nio_ch_NativeThread_current0.getCallTargetNoSubstitution())") DirectCallNode original) {
79+
if (context.getNativeAccess() instanceof NFISulongNativeAccess) {
80+
// sulong virtualizes pthread_self but not ptrhead_kill
81+
// signal to the JDK that we don't support signaling
82+
return 0;
83+
} else {
84+
return (long) original.call();
85+
}
86+
}
87+
}
88+
89+
@Substitution(versionFilter = Java17OrEarlier.class)
90+
abstract static class Signal extends SubstitutionNode {
91+
abstract void execute(long nt);
92+
93+
@Specialization
94+
static void doDefault(long nt,
95+
@Bind("getContext()") EspressoContext context,
96+
@Cached("create(context.getMeta().sun_nio_ch_NativeThread_signal.getCallTargetNoSubstitution())") DirectCallNode original) {
97+
// sulong virtualizes pthread_self but not ptrhead_kill
98+
if (!(context.getNativeAccess() instanceof NFISulongNativeAccess)) {
99+
original.call(nt);
100+
}
101+
}
35102
}
36103
}

espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/VersionFilter.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ public boolean isValidFor(JavaVersion version) {
8989
}
9090
}
9191

92+
final class Java17OrEarlier implements VersionFilter {
93+
public static final Java17OrEarlier INSTANCE = new Java17OrEarlier();
94+
95+
private Java17OrEarlier() {
96+
}
97+
98+
@Override
99+
public boolean isValidFor(JavaVersion version) {
100+
return version.java17OrEarlier();
101+
}
102+
}
103+
92104
final class Java18OrEarlier implements VersionFilter {
93105
public static final Java18OrEarlier INSTANCE = new Java18OrEarlier();
94106

@@ -124,4 +136,16 @@ public boolean isValidFor(JavaVersion version) {
124136
return version.java20OrLater();
125137
}
126138
}
139+
140+
final class Java21OrLater implements VersionFilter {
141+
public static final Java21OrLater INSTANCE = new Java21OrLater();
142+
143+
private Java21OrLater() {
144+
}
145+
146+
@Override
147+
public boolean isValidFor(JavaVersion version) {
148+
return version.java21OrLater();
149+
}
150+
}
127151
}

sdk/mx.sdk/vm/launcher_template.cmd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ exit /b %errorlevel%
187187
) else if "!vm_arg:~0,10!"=="classpath=" (
188188
call :unquote_arg %vm_arg:~10%
189189
set "absolute_cp=%absolute_cp%;!arg!"
190+
) else if "!vm_arg:~0,1!"=="@" (
191+
if %arg_quoted%==true ( set "arg="%vm_arg%"" ) else ( set "arg=%vm_arg%" )
192+
set "jvm_args=%jvm_args% !arg!"
190193
) else (
191194
if %arg_quoted%==true ( set "arg="-%vm_arg%"" ) else ( set "arg=-%vm_arg%" )
192195
set "jvm_args=%jvm_args% !arg!"

0 commit comments

Comments
 (0)