47
47
#include < cstdlib>
48
48
49
49
#include < string>
50
+ #include < optional>
50
51
#include < iostream>
51
52
#include < sstream>
53
+ #include < fstream>
52
54
#include < vector>
53
55
56
+ #include < cassert>
57
+
54
58
#define QUOTE (name ) #name
55
59
#define STR (macro ) QUOTE(macro)
56
60
94
98
#define VM_MODULE_PATH_ARG_PREFIX " --vm.-module-path="
95
99
#define VM_LIBRARY_PATH_ARG_PREFIX " --vm.Djava.library.path="
96
100
#define VM_STACK_SIZE_ARG_PREFIX " --vm.Xss"
101
+ #define VM_ARG_FILE_ARG_PREFIX " --vm.@"
97
102
98
103
#define VM_ARG_OFFSET (sizeof (VM_ARG_PREFIX)-1 )
99
104
#define VM_CP_ARG_OFFSET (sizeof (VM_CP_ARG_PREFIX)-1 )
102
107
#define VM_MODULE_PATH_ARG_OFFSET (sizeof (VM_MODULE_PATH_ARG_PREFIX)-1 )
103
108
#define VM_LIBRARY_PATH_ARG_OFFSET (sizeof (VM_LIBRARY_PATH_ARG_PREFIX)-1 )
104
109
#define VM_STACK_SIZE_ARG_OFFSET (sizeof (VM_STACK_SIZE_ARG_PREFIX)-1 )
110
+ #define VM_ARG_FILE_ARG_OFFSET (sizeof (VM_ARG_FILE_ARG_PREFIX)-1 )
105
111
106
112
#define STARTS_WITH (ARG, PREFIX ) (ARG.rfind(PREFIX, 0 ) != std::string::npos)
107
113
#define IS_VM_ARG (ARG ) STARTS_WITH(ARG, VM_ARG_PREFIX)
111
117
#define IS_VM_MODULE_PATH_ARG (ARG ) STARTS_WITH(ARG, VM_MODULE_PATH_ARG_PREFIX)
112
118
#define IS_VM_LIBRARY_PATH_ARG (ARG ) STARTS_WITH(ARG, VM_LIBRARY_PATH_ARG_PREFIX)
113
119
#define IS_VM_STACK_SIZE_ARG (ARG ) STARTS_WITH(ARG, VM_STACK_SIZE_ARG_PREFIX)
120
+ #define IS_VM_ARG_FILE_ARG (ARG ) STARTS_WITH(ARG, VM_ARG_FILE_ARG_PREFIX)
114
121
115
122
#define NMT_ARG_NAME " XX:NativeMemoryTracking"
116
123
#define NMT_ENV_NAME " NMT_LEVEL_"
@@ -345,6 +352,12 @@ static std::string vm_path(std::string exeDir, bool jvmMode) {
345
352
}
346
353
347
354
static size_t parse_size (std::string_view str);
355
+ static void expand_vm_arg_file (const char *arg_file,
356
+ std::vector<std::string> *vmArgs,
357
+ std::ostringstream *cp,
358
+ std::ostringstream *modulePath,
359
+ std::ostringstream *libraryPath,
360
+ size_t * stack_size);
348
361
349
362
static void parse_vm_option (
350
363
std::vector<std::string> *vmArgs,
@@ -363,6 +376,9 @@ static void parse_vm_option(
363
376
*modulePath << CP_SEP_STR << option.substr (VM_MODULE_PATH_ARG_OFFSET);
364
377
} else if (IS_VM_LIBRARY_PATH_ARG (option)) {
365
378
*libraryPath << CP_SEP_STR << option.substr (VM_LIBRARY_PATH_ARG_OFFSET);
379
+ } else if (IS_VM_ARG_FILE_ARG (option)) {
380
+ std::string arg_file (option.substr (VM_ARG_FILE_ARG_OFFSET));
381
+ expand_vm_arg_file (arg_file.c_str (), vmArgs, cp, modulePath, libraryPath, stack_size);
366
382
} else if (IS_VM_ARG (option)) {
367
383
if (IS_VM_STACK_SIZE_ARG (option)) {
368
384
*stack_size = parse_size (option.substr (VM_STACK_SIZE_ARG_OFFSET));
@@ -375,6 +391,163 @@ static void parse_vm_option(
375
391
}
376
392
}
377
393
394
+ enum ArgFileState {
395
+ FIND_NEXT,
396
+ IN_COMMENT,
397
+ IN_QUOTE,
398
+ IN_ESCAPE,
399
+ SKIP_LEAD_WS,
400
+ IN_TOKEN
401
+ };
402
+ // Parse @arg-files as handled by libjli. See libjli/args.c.
403
+ static std::optional<std::string> arg_file_next_token (std::ifstream &input) {
404
+ ArgFileState state = FIND_NEXT;
405
+ int currentQuoteChar = -1 ;
406
+ std::istream::int_type ch;
407
+
408
+ std::ostringstream token;
409
+ std::ostringstream::pos_type start = token.tellp ();
410
+
411
+ while ((ch = input.get ()) != std::istream::traits_type::eof ()) {
412
+ // Skip white space characters
413
+ if (state == FIND_NEXT || state == SKIP_LEAD_WS) {
414
+ while (ch == ' ' || ch == ' \n ' || ch == ' \r ' || ch == ' \t ' || ch == ' \f ' ) {
415
+ if ((ch = input.get ()) == std::istream::traits_type::eof ()) {
416
+ goto done;
417
+ }
418
+ }
419
+ state = (state == FIND_NEXT) ? IN_TOKEN : IN_QUOTE;
420
+ // Deal with escape sequences
421
+ } else if (state == IN_ESCAPE) {
422
+ // concatenation directive
423
+ if (ch == ' \n ' || ch == ' \r ' ) {
424
+ state = SKIP_LEAD_WS;
425
+ } else {
426
+ // escaped character
427
+ switch (ch) {
428
+ case ' n' :
429
+ token << ' \n ' ;
430
+ break ;
431
+ case ' r' :
432
+ token << ' \r ' ;
433
+ break ;
434
+ case ' t' :
435
+ token << ' \t ' ;
436
+ break ;
437
+ case ' f' :
438
+ token << ' \f ' ;
439
+ break ;
440
+ default :
441
+ token << (char ) ch;
442
+ break ;
443
+ }
444
+ state = IN_QUOTE;
445
+ }
446
+ continue ;
447
+ // ignore comment to EOL
448
+ } else if (state == IN_COMMENT) {
449
+ while (ch != ' \n ' && ch != ' \r ' ) {
450
+ if ((ch = input.get ()) == std::istream::traits_type::eof ()) {
451
+ goto done;
452
+ }
453
+ }
454
+ state = FIND_NEXT;
455
+ continue ;
456
+ }
457
+
458
+ assert (state != IN_ESCAPE);
459
+ assert (state != FIND_NEXT);
460
+ assert (state != SKIP_LEAD_WS);
461
+ assert (state != IN_COMMENT);
462
+
463
+ switch (ch) {
464
+ case ' ' :
465
+ case ' \t ' :
466
+ case ' \f ' :
467
+ if (state == IN_QUOTE) {
468
+ token << (char ) ch;
469
+ continue ;
470
+ }
471
+ // fallthrough
472
+ case ' \n ' :
473
+ case ' \r ' :
474
+ return token.str ();
475
+ case ' #' :
476
+ if (state == IN_QUOTE) {
477
+ token << (char ) ch;
478
+ continue ;
479
+ }
480
+ state = IN_COMMENT;
481
+ break ;
482
+ case ' \\ ' :
483
+ if (state != IN_QUOTE) {
484
+ token << (char ) ch;
485
+ continue ;
486
+ }
487
+ state = IN_ESCAPE;
488
+ break ;
489
+ case ' \' ' :
490
+ case ' "' :
491
+ if (state == IN_QUOTE && currentQuoteChar != ch) {
492
+ // not matching quote
493
+ token << (char ) ch;
494
+ continue ;
495
+ }
496
+ if (state == IN_TOKEN) {
497
+ currentQuoteChar = ch;
498
+ state = IN_QUOTE;
499
+ } else {
500
+ state = IN_TOKEN;
501
+ }
502
+ break ;
503
+ default :
504
+ token << (char ) ch;
505
+ break ;
506
+ }
507
+ }
508
+ done:
509
+ if (token.tellp () == start) {
510
+ return {};
511
+ }
512
+ return token.str ();
513
+ }
514
+
515
+ static void expand_vm_arg_file (const char *arg_file,
516
+ std::vector<std::string> *vmArgs,
517
+ std::ostringstream *cp,
518
+ std::ostringstream *modulePath,
519
+ std::ostringstream *libraryPath,
520
+ size_t * stack_size) {
521
+ if (debug) {
522
+ std::cout << " Expanding VM arg file " << arg_file << std::endl;
523
+ }
524
+ std::ifstream input (arg_file);
525
+ if (input.fail ()) {
526
+ std::cerr << " Error: could not open `" << arg_file << " ': " << strerror (errno) << std::endl;
527
+ exit (EXIT_FAILURE);
528
+ }
529
+
530
+ while (true ) {
531
+ std::optional<std::string> token = arg_file_next_token (input);
532
+ if (token.has_value ()) {
533
+ if (STARTS_WITH (token.value (), " --class-path=" )) {
534
+ *cp << CP_SEP_STR << token.value ().substr (sizeof (" --class-path=" ) - 1 );
535
+ } else if (STARTS_WITH (token.value (), " --module-path=" )) {
536
+ *modulePath << CP_SEP_STR << token.value ().substr (sizeof (" --module-path=" ) - 1 );
537
+ } else if (STARTS_WITH (token.value (), " -Djava.library.path=" )) {
538
+ *libraryPath << CP_SEP_STR << token.value ().substr (sizeof (" -Djava.library.path=" ) - 1 );
539
+ } else {
540
+ if (STARTS_WITH (token.value (), " -Xss" )) {
541
+ *stack_size = parse_size (token.value ().substr (sizeof (" -Xss" ) - 1 ));
542
+ }
543
+ vmArgs->push_back (token.value ());
544
+ }
545
+ } else {
546
+ break ;
547
+ }
548
+ }
549
+ }
550
+
378
551
struct MainThreadArgs {
379
552
int argc;
380
553
char **argv;
0 commit comments