118
118
#define IS_VM_LIBRARY_PATH_ARG (ARG ) STARTS_WITH(ARG, VM_LIBRARY_PATH_ARG_PREFIX)
119
119
#define IS_VM_STACK_SIZE_ARG (ARG ) STARTS_WITH(ARG, VM_STACK_SIZE_ARG_PREFIX)
120
120
#define IS_VM_ARG_FILE_ARG (ARG ) STARTS_WITH(ARG, VM_ARG_FILE_ARG_PREFIX)
121
+ #define IS_VM_START_ON_FIRST_THREAD (ARG ) (ARG == " --vm.XstartOnFirstThread" )
121
122
122
123
#define NMT_ARG_NAME " XX:NativeMemoryTracking"
123
124
#define NMT_ENV_NAME " NMT_LEVEL_"
@@ -364,7 +365,8 @@ static void parse_vm_option(
364
365
std::ostringstream *cp,
365
366
std::ostringstream *modulePath,
366
367
std::ostringstream *libraryPath,
367
- size_t * stack_size,
368
+ size_t *stack_size,
369
+ bool *startOnFirstThread,
368
370
std::string_view option) {
369
371
if (IS_VM_CP_ARG (option)) {
370
372
*cp << CP_SEP_STR << option.substr (VM_CP_ARG_OFFSET);
@@ -379,6 +381,10 @@ static void parse_vm_option(
379
381
} else if (IS_VM_ARG_FILE_ARG (option)) {
380
382
std::string arg_file (option.substr (VM_ARG_FILE_ARG_OFFSET));
381
383
expand_vm_arg_file (arg_file.c_str (), vmArgs, cp, modulePath, libraryPath, stack_size);
384
+ #if defined (__APPLE__)
385
+ } else if (IS_VM_START_ON_FIRST_THREAD (option)) {
386
+ *startOnFirstThread = true ;
387
+ #endif
382
388
} else if (IS_VM_ARG (option)) {
383
389
if (IS_VM_STACK_SIZE_ARG (option)) {
384
390
*stack_size = parse_size (option.substr (VM_STACK_SIZE_ARG_OFFSET));
@@ -555,13 +561,14 @@ struct MainThreadArgs {
555
561
bool jvmMode;
556
562
std::string libPath;
557
563
size_t stack_size{};
564
+ bool startOnFirstThread;
558
565
std::vector<std::string> vmArgs;
559
566
std::vector<std::string> optionVarsArgs;
560
567
};
561
568
562
569
/* parse the VM arguments that should be passed to JNI_CreateJavaVM */
563
570
static void parse_vm_options (struct MainThreadArgs & parsedArgs) {
564
- auto & [argc, argv, exeDir, jvmMode, _, stack_size, vmArgs, optionVarsArgs] = parsedArgs;
571
+ auto & [argc, argv, exeDir, jvmMode, _, stack_size, startOnFirstThread, vmArgs, optionVarsArgs] = parsedArgs;
565
572
566
573
/* check if vm args have been set on relaunch already */
567
574
int vmArgCount = 0 ;
@@ -715,7 +722,7 @@ static void parse_vm_options(struct MainThreadArgs& parsedArgs) {
715
722
const char *launcherDefaultVmArgs[] = LAUNCHER_DEFAULT_VM_ARGS;
716
723
for (int i = 0 ; i < sizeof (launcherDefaultVmArgs)/sizeof (char *); i++) {
717
724
if (IS_VM_ARG (std::string (launcherDefaultVmArgs[i]))) {
718
- parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, launcherDefaultVmArgs[i]);
725
+ parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, &startOnFirstThread, launcherDefaultVmArgs[i]);
719
726
}
720
727
}
721
728
#endif
@@ -724,7 +731,7 @@ static void parse_vm_options(struct MainThreadArgs& parsedArgs) {
724
731
if (!relaunch) {
725
732
/* handle CLI arguments */
726
733
for (int i = 1 ; i < argc; i++) {
727
- parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, argv[i]);
734
+ parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, &startOnFirstThread, argv[i]);
728
735
}
729
736
730
737
/* handle optional vm args from LanguageLibraryConfig.option_vars */
@@ -745,12 +752,12 @@ static void parse_vm_options(struct MainThreadArgs& parsedArgs) {
745
752
while ((next = optionLine.find (" " , last)) != std::string::npos) {
746
753
option = optionLine.substr (last, next-last);
747
754
optionVarsArgs.push_back (option);
748
- parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, option);
755
+ parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, &startOnFirstThread, option);
749
756
last = next + 1 ;
750
757
};
751
758
option = optionLine.substr (last);
752
759
optionVarsArgs.push_back (option);
753
- parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, option);
760
+ parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, &startOnFirstThread, option);
754
761
}
755
762
#endif
756
763
} else {
@@ -769,7 +776,7 @@ static void parse_vm_options(struct MainThreadArgs& parsedArgs) {
769
776
std::cerr << " VM arguments specified: " << vmArgCount << " but argument " << i << " missing" << std::endl;
770
777
break ;
771
778
}
772
- parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, cur);
779
+ parse_vm_option (&vmArgs, &cp, &modulePath, &libraryPath, &stack_size, &startOnFirstThread, cur);
773
780
/* clean up env variable */
774
781
setenv (envKey, " " );
775
782
}
@@ -865,7 +872,7 @@ int main(int argc, char *argv[]) {
865
872
866
873
867
874
/* parse VM args */
868
- struct MainThreadArgs parsedArgs{argc, argv, exeDir, jvmMode, libPath, 0 };
875
+ struct MainThreadArgs parsedArgs{argc, argv, exeDir, jvmMode, libPath, 0 , false };
869
876
parse_vm_options (parsedArgs);
870
877
size_t stack_size = parsedArgs.stack_size ;
871
878
@@ -883,10 +890,12 @@ int main(int argc, char *argv[]) {
883
890
size_t main_thread_stack_size = current_thread_stack_size ();
884
891
bool use_new_thread = stack_size > main_thread_stack_size;
885
892
#if defined (__APPLE__)
886
- /* On macOS, always create a dedicated "main" thread for the JVM.
893
+ /* On macOS, default to creating a dedicated "main" thread for the JVM.
887
894
* The actual main thread must run the UI event loop (needed for AWT).
895
+ * It can be overridden with -XstartOnFirstThread, this is needed to
896
+ * use other UI frameworks that *do* need to run on the main thread.
888
897
*/
889
- use_new_thread = true ;
898
+ use_new_thread = !parsedArgs. startOnFirstThread ;
890
899
891
900
if (jvmMode) {
892
901
if (!load_jli_lib (exeDir)) {
@@ -965,7 +974,7 @@ int main(int argc, char *argv[]) {
965
974
}
966
975
967
976
static int jvm_main_thread (struct MainThreadArgs & parsedArgs) {
968
- auto & [argc, argv, _, jvmMode, libPath, stack_size, vmArgs, optionVarsArgs] = parsedArgs;
977
+ auto & [argc, argv, _, jvmMode, libPath, stack_size, startOnFirstThread, vmArgs, optionVarsArgs] = parsedArgs;
969
978
970
979
/* load VM library - after parsing arguments s.t. NMT
971
980
* tracking environment variables are already set */
0 commit comments