@@ -96,9 +96,18 @@ static JImageClose_t JImageClose = nullptr;
96
96
static JImageFindResource_t JImageFindResource = nullptr ;
97
97
static JImageGetResource_t JImageGetResource = nullptr ;
98
98
99
- // JimageFile pointer, or null if exploded JDK build.
99
+ // JImageFile pointer, or null if exploded JDK build.
100
100
static JImageFile* JImage_file = nullptr ;
101
101
102
+ // JImageMode status to control preview behaviour. JImage_file is unusable
103
+ // for normal lookup until (JImage_mode != JIMAGE_MODE_UNINITIALIZED).
104
+ enum JImageMode {
105
+ JIMAGE_MODE_UNINITIALIZED = 0 ,
106
+ JIMAGE_MODE_DEFAULT = 1 ,
107
+ JIMAGE_MODE_ENABLE_PREVIEW = 2
108
+ };
109
+ static JImageMode JImage_mode = JIMAGE_MODE_UNINITIALIZED;
110
+
102
111
// Globals
103
112
104
113
PerfCounter* ClassLoader::_perf_accumulated_time = nullptr ;
@@ -153,7 +162,7 @@ void ClassLoader::print_counters(outputStream *st) {
153
162
154
163
GrowableArray<ModuleClassPathList*>* ClassLoader::_patch_mod_entries = nullptr ;
155
164
GrowableArray<ModuleClassPathList*>* ClassLoader::_exploded_entries = nullptr ;
156
- ClassPathEntry * ClassLoader::_jrt_entry = nullptr ;
165
+ ClassPathImageEntry * ClassLoader::_jrt_entry = nullptr ;
157
166
158
167
ClassPathEntry* volatile ClassLoader::_first_append_entry_list = nullptr ;
159
168
ClassPathEntry* volatile ClassLoader::_last_append_entry = nullptr ;
@@ -170,15 +179,6 @@ static bool string_starts_with(const char* str, const char* str_to_find) {
170
179
}
171
180
#endif
172
181
173
- static const char * get_jimage_version_string () {
174
- static char version_string[10 ] = " " ;
175
- if (version_string[0 ] == ' \0 ' ) {
176
- jio_snprintf (version_string, sizeof (version_string), " %d.%d" ,
177
- VM_Version::vm_major_version (), VM_Version::vm_minor_version ());
178
- }
179
- return (const char *)version_string;
180
- }
181
-
182
182
bool ClassLoader::string_ends_with (const char * str, const char * str_to_find) {
183
183
size_t str_len = strlen (str);
184
184
size_t str_to_find_len = strlen (str_to_find);
@@ -233,6 +233,73 @@ Symbol* ClassLoader::package_from_class_name(const Symbol* name, bool* bad_class
233
233
return SymbolTable::new_symbol (name, pointer_delta_as_int (start, base), pointer_delta_as_int (end, base));
234
234
}
235
235
236
+ // --------------------------------
237
+ // The following jimage_xxx static functions encapsulate all JImage_file and JImage_mode access.
238
+ // This is done to make it easy to reason about the JImage file state (exists vs initialized etc.).
239
+
240
+ // Opens the named JImage file and sets the JImage file reference.
241
+ // Returns true if opening the JImage file was successful (see also jimage_exists()).
242
+ static bool jimage_open (const char * modules_path) {
243
+ // Currently 'error' is not set to anything useful, so ignore it here.
244
+ jint error;
245
+ JImage_file = (*JImageOpen)(modules_path, &error);
246
+ return JImage_file != nullptr ;
247
+ }
248
+
249
+ // Closes and clears the JImage file reference (this will only be called during shutdown).
250
+ static void jimage_close () {
251
+ if (JImage_file != nullptr ) {
252
+ (*JImageClose)(JImage_file);
253
+ JImage_file = nullptr ;
254
+ }
255
+ }
256
+
257
+ // Returns whether a JImage file was opened (but NOT whether it was initialized yet).
258
+ static bool jimage_exists () {
259
+ return JImage_file != nullptr ;
260
+ }
261
+
262
+ // Returns the JImage file reference (which may or may not be initialized).
263
+ static JImageFile* jimage_non_null () {
264
+ assert (jimage_exists (), " should have been opened by ClassLoader::lookup_vm_options "
265
+ " and remained throughout normal JVM lifetime" );
266
+ return JImage_file;
267
+ }
268
+
269
+ // Called once to set the access mode for resource (i.e. preview or non-preview) before
270
+ // general resource lookup can occur.
271
+ static void jimage_init (bool enable_preview) {
272
+ assert (JImage_mode == JIMAGE_MODE_UNINITIALIZED, " jimage_init must not be called twice" );
273
+ JImage_mode = enable_preview ? JIMAGE_MODE_ENABLE_PREVIEW : JIMAGE_MODE_DEFAULT;
274
+ }
275
+
276
+ // Returns true if jimage_init() has been called. Once the JImage file is initialized,
277
+ // jimage_is_preview_enabled() can be called to correctly determine the access mode.
278
+ static bool jimage_is_initialized () {
279
+ return jimage_exists () && JImage_mode != JIMAGE_MODE_UNINITIALIZED;
280
+ }
281
+
282
+ // Returns the access mode for an initialized JImage file (reflects --enable-preview).
283
+ static bool jimage_is_preview_enabled () {
284
+ assert (jimage_is_initialized (), " jimage is not initialized" );
285
+ return JImage_mode == JIMAGE_MODE_ENABLE_PREVIEW;
286
+ }
287
+
288
+ // Looks up the location of a named JImage resource. This "raw" lookup function allows
289
+ // the preview mode to be manually specified, so must not be accessible outside this
290
+ // class. ClassPathImageEntry manages all calls for resources after startup is complete.
291
+ static JImageLocationRef jimage_find_resource (const char * module_name,
292
+ const char * file_name,
293
+ bool is_preview,
294
+ jlong *size) {
295
+ return ((*JImageFindResource)(jimage_non_null (),
296
+ module_name,
297
+ file_name,
298
+ is_preview,
299
+ size));
300
+ }
301
+ // --------------------------------
302
+
236
303
// Given a fully qualified package name, find its defining package in the class loader's
237
304
// package entry table.
238
305
PackageEntry* ClassLoader::get_package_entry (Symbol* pkg_name, ClassLoaderData* loader_data) {
@@ -371,28 +438,15 @@ ClassFileStream* ClassPathZipEntry::open_stream(JavaThread* current, const char*
371
438
372
439
DEBUG_ONLY (ClassPathImageEntry* ClassPathImageEntry::_singleton = nullptr ;)
373
440
374
- JImageFile* ClassPathImageEntry::jimage() const {
375
- return JImage_file;
376
- }
377
-
378
- JImageFile* ClassPathImageEntry::jimage_non_null () const {
379
- assert (ClassLoader::has_jrt_entry (), " must be" );
380
- assert (jimage () != nullptr , " should have been opened by ClassLoader::lookup_vm_options "
381
- " and remained throughout normal JVM lifetime" );
382
- return jimage ();
383
- }
384
-
385
441
void ClassPathImageEntry::close_jimage() {
386
- if (jimage () != nullptr ) {
387
- (*JImageClose)(jimage ());
388
- JImage_file = nullptr ;
389
- }
442
+ jimage_close ();
390
443
}
391
444
392
- ClassPathImageEntry::ClassPathImageEntry (JImageFile* jimage, const char * name) :
445
+ ClassPathImageEntry::ClassPathImageEntry (const char * name) :
393
446
ClassPathEntry() {
394
- guarantee (jimage != nullptr , " jimage file is null " );
447
+ guarantee (jimage_is_initialized () , " jimage is not initialized " );
395
448
guarantee (name != nullptr , " jimage file name is null" );
449
+
396
450
assert (_singleton == nullptr , " VM supports only one jimage" );
397
451
DEBUG_ONLY (_singleton = this );
398
452
size_t len = strlen (name) + 1 ;
@@ -411,16 +465,18 @@ ClassFileStream* ClassPathImageEntry::open_stream(JavaThread* current, const cha
411
465
// 2. A package is in at most one module in the jimage file.
412
466
//
413
467
ClassFileStream* ClassPathImageEntry::open_stream_for_loader (JavaThread* current, const char * name, ClassLoaderData* loader_data) {
468
+ bool is_preview = jimage_is_preview_enabled ();
469
+
414
470
jlong size;
415
- JImageLocationRef location = (*JImageFindResource)( jimage_non_null (), " " , get_jimage_version_string (), name , &size);
471
+ JImageLocationRef location = jimage_find_resource ( " " , name, is_preview , &size);
416
472
417
473
if (location == 0 ) {
418
474
TempNewSymbol class_name = SymbolTable::new_symbol (name);
419
475
TempNewSymbol pkg_name = ClassLoader::package_from_class_name (class_name);
420
476
421
477
if (pkg_name != nullptr ) {
422
478
if (!Universe::is_module_initialized ()) {
423
- location = (*JImageFindResource)( jimage_non_null (), JAVA_BASE_NAME, get_jimage_version_string (), name , &size);
479
+ location = jimage_find_resource ( JAVA_BASE_NAME, name, is_preview , &size);
424
480
} else {
425
481
PackageEntry* package_entry = ClassLoader::get_package_entry (pkg_name, loader_data);
426
482
if (package_entry != nullptr ) {
@@ -431,7 +487,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
431
487
assert (module ->is_named (), " Boot classLoader package is in unnamed module" );
432
488
const char * module_name = module ->name ()->as_C_string ();
433
489
if (module_name != nullptr ) {
434
- location = (*JImageFindResource)( jimage_non_null (), module_name, get_jimage_version_string (), name , &size);
490
+ location = jimage_find_resource ( module_name, name, is_preview , &size);
435
491
}
436
492
}
437
493
}
@@ -444,7 +500,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
444
500
char * data = NEW_RESOURCE_ARRAY (char , size);
445
501
(*JImageGetResource)(jimage_non_null (), location, data, size);
446
502
// Resource allocated
447
- assert (this == (ClassPathImageEntry*) ClassLoader::get_jrt_entry (), " must be" );
503
+ assert (this == ClassLoader::get_jrt_entry (), " must be" );
448
504
return new ClassFileStream ((u1*)data,
449
505
checked_cast<int >(size),
450
506
_name,
@@ -454,16 +510,9 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
454
510
return nullptr ;
455
511
}
456
512
457
- JImageLocationRef ClassLoader::jimage_find_resource (JImageFile* jf,
458
- const char * module_name,
459
- const char * file_name,
460
- jlong &size) {
461
- return ((*JImageFindResource)(jf, module_name, get_jimage_version_string (), file_name, &size));
462
- }
463
-
464
513
bool ClassPathImageEntry::is_modules_image () const {
465
514
assert (this == _singleton, " VM supports a single jimage" );
466
- assert (this == (ClassPathImageEntry*) ClassLoader::get_jrt_entry (), " must be used for jrt entry" );
515
+ assert (this == ClassLoader::get_jrt_entry (), " must be used for jrt entry" );
467
516
return true ;
468
517
}
469
518
@@ -618,14 +667,15 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
618
667
struct stat st;
619
668
if (os::stat (path, &st) == 0 ) {
620
669
// Directory found
621
- if (JImage_file != nullptr ) {
670
+ if (jimage_exists () ) {
622
671
assert (Arguments::has_jimage (), " sanity check" );
623
672
const char * canonical_path = get_canonical_path (path, current);
624
673
assert (canonical_path != nullptr , " canonical_path issue" );
625
674
626
- _jrt_entry = new ClassPathImageEntry (JImage_file, canonical_path);
675
+ // Hand over lifecycle control of the JImage file to the _jrt_entry singleton
676
+ // (see ClassPathImageEntry::close_jimage). The image must be initialized by now.
677
+ _jrt_entry = new ClassPathImageEntry (canonical_path);
627
678
assert (_jrt_entry != nullptr && _jrt_entry->is_modules_image (), " No java runtime image present" );
628
- assert (_jrt_entry->jimage () != nullptr , " No java runtime image" );
629
679
} // else it's an exploded build.
630
680
} else {
631
681
// If path does not exist, exit
@@ -1388,49 +1438,51 @@ void ClassLoader::initialize(TRAPS) {
1388
1438
setup_bootstrap_search_path (THREAD);
1389
1439
}
1390
1440
1391
- static char * lookup_vm_resource (JImageFile *jimage, const char *jimage_version, const char *path) {
1392
- jlong size;
1393
- JImageLocationRef location = (*JImageFindResource)(jimage, " java.base" , jimage_version, path, &size);
1394
- if (location == 0 )
1395
- return nullptr ;
1396
- char *val = NEW_C_HEAP_ARRAY (char , size+1 , mtClass);
1397
- (*JImageGetResource)(jimage, location, val, size);
1398
- val[size] = ' \0 ' ;
1399
- return val;
1400
- }
1401
-
1402
1441
// Lookup VM options embedded in the modules jimage file
1403
1442
char * ClassLoader::lookup_vm_options () {
1404
- jint error;
1405
1443
char modules_path[JVM_MAXPATHLEN];
1406
1444
const char * fileSep = os::file_separator ();
1407
1445
1408
1446
// Initialize jimage library entry points
1409
1447
load_jimage_library ();
1410
1448
1411
1449
jio_snprintf (modules_path, JVM_MAXPATHLEN, " %s%slib%smodules" , Arguments::get_java_home (), fileSep, fileSep);
1412
- JImage_file =(*JImageOpen)(modules_path, &error);
1413
- if (JImage_file == nullptr ) {
1414
- return nullptr ;
1450
+ if (jimage_open (modules_path)) {
1451
+ // Special case where we lookup the options string *before* calling jimage_init().
1452
+ // Since VM arguments have not been parsed, and the ClassPathImageEntry singleton
1453
+ // has not been created yet, we access the JImage file directly in non-preview mode.
1454
+ jlong size;
1455
+ JImageLocationRef location =
1456
+ jimage_find_resource (JAVA_BASE_NAME, " jdk/internal/vm/options" , /* is_preview */ false , &size);
1457
+ if (location != 0 ) {
1458
+ char *options = NEW_C_HEAP_ARRAY (char , size+1 , mtClass);
1459
+ (*JImageGetResource)(jimage_non_null (), location, options, size);
1460
+ options[size] = ' \0 ' ;
1461
+ return options;
1462
+ }
1415
1463
}
1464
+ return nullptr ;
1465
+ }
1416
1466
1417
- const char *jimage_version = get_jimage_version_string ();
1418
- char *options = lookup_vm_resource (JImage_file, jimage_version, " jdk/internal/vm/options" );
1419
- return options;
1467
+ // Finishes initializing the JImageFile (if present) by setting the access mode.
1468
+ void ClassLoader::init_jimage (bool enable_preview) {
1469
+ if (jimage_exists ()) {
1470
+ jimage_init (enable_preview);
1471
+ }
1420
1472
}
1421
1473
1422
1474
bool ClassLoader::is_module_observable (const char * module_name) {
1423
1475
assert (JImageOpen != nullptr , " jimage library should have been opened" );
1424
- if (JImage_file == nullptr ) {
1476
+ if (! jimage_exists () ) {
1425
1477
struct stat st;
1426
1478
const char *path = get_exploded_module_path (module_name, true );
1427
1479
bool res = os::stat (path, &st) == 0 ;
1428
1480
FREE_C_HEAP_ARRAY (char , path);
1429
1481
return res;
1430
1482
}
1483
+ // We don't expect preview mode (i.e. --enable-preview) to affect module visibility.
1431
1484
jlong size;
1432
- const char *jimage_version = get_jimage_version_string ();
1433
- return (*JImageFindResource)(JImage_file, module_name, jimage_version, " module-info.class" , &size) != 0 ;
1485
+ return jimage_find_resource (module_name, " module-info.class" , /* is_preview */ false , &size) != 0 ;
1434
1486
}
1435
1487
1436
1488
jlong ClassLoader::classloader_time_ms () {
0 commit comments