@@ -97,9 +97,18 @@ static JImageClose_t JImageClose = nullptr;
97
97
static JImageFindResource_t JImageFindResource = nullptr ;
98
98
static JImageGetResource_t JImageGetResource = nullptr ;
99
99
100
- // JimageFile pointer, or null if exploded JDK build.
100
+ // JImageFile pointer, or null if exploded JDK build.
101
101
static JImageFile* JImage_file = nullptr ;
102
102
103
+ // JImageMode status to control preview behaviour. JImage_file is unusable
104
+ // for normal lookup until (JImage_mode != JIMAGE_MODE_UNINITIALIZED).
105
+ enum JImageMode {
106
+ JIMAGE_MODE_UNINITIALIZED = 0 ,
107
+ JIMAGE_MODE_DEFAULT = 1 ,
108
+ JIMAGE_MODE_ENABLE_PREVIEW = 2
109
+ };
110
+ static JImageMode JImage_mode = JIMAGE_MODE_UNINITIALIZED;
111
+
103
112
// Globals
104
113
105
114
PerfCounter* ClassLoader::_perf_accumulated_time = nullptr ;
@@ -154,7 +163,7 @@ void ClassLoader::print_counters(outputStream *st) {
154
163
155
164
GrowableArray<ModuleClassPathList*>* ClassLoader::_patch_mod_entries = nullptr ;
156
165
GrowableArray<ModuleClassPathList*>* ClassLoader::_exploded_entries = nullptr ;
157
- ClassPathEntry * ClassLoader::_jrt_entry = nullptr ;
166
+ ClassPathImageEntry * ClassLoader::_jrt_entry = nullptr ;
158
167
159
168
ClassPathEntry* volatile ClassLoader::_first_append_entry_list = nullptr ;
160
169
ClassPathEntry* volatile ClassLoader::_last_append_entry = nullptr ;
@@ -234,6 +243,74 @@ Symbol* ClassLoader::package_from_class_name(const Symbol* name, bool* bad_class
234
243
return SymbolTable::new_symbol (name, pointer_delta_as_int (start, base), pointer_delta_as_int (end, base));
235
244
}
236
245
246
+ // --------------------------------
247
+ // The following jimage_xxx static functions encapsulate all JImage_file and JImage_mode access.
248
+ // This is done to make it easy to reason about the JImage file state (exists vs initialized etc.).
249
+
250
+ // Opens the named JImage file and sets the JImage file reference.
251
+ // Returns true if opening the JImage file was successful (see also jimage_exists()).
252
+ static bool jimage_open (const char * modules_path) {
253
+ // Currently 'error' is not set to anything useful, so ignore it here.
254
+ jint error;
255
+ JImage_file = (*JImageOpen)(modules_path, &error);
256
+ return JImage_file != nullptr ;
257
+ }
258
+
259
+ // Closes and clears the JImage file reference (this will only be called during shutdown).
260
+ static void jimage_close () {
261
+ if (JImage_file != nullptr ) {
262
+ (*JImageClose)(JImage_file);
263
+ JImage_file = nullptr ;
264
+ }
265
+ }
266
+
267
+ // Returns whether a JImage file was opened (but NOT whether it was initialized yet).
268
+ static bool jimage_exists () {
269
+ return JImage_file != nullptr ;
270
+ }
271
+
272
+ // Returns the JImage file reference (which may or may not be initialized).
273
+ static JImageFile* jimage_non_null () {
274
+ assert (jimage_exists (), " should have been opened by ClassLoader::lookup_vm_options "
275
+ " and remained throughout normal JVM lifetime" );
276
+ return JImage_file;
277
+ }
278
+
279
+ // Called once to set the access mode for resource (i.e. preview or non-preview) before
280
+ // general resource lookup can occur.
281
+ static void jimage_init (bool enable_preview) {
282
+ assert (JImage_mode == JIMAGE_MODE_UNINITIALIZED, " jimage_init must not be called twice" );
283
+ JImage_mode = enable_preview ? JIMAGE_MODE_ENABLE_PREVIEW : JIMAGE_MODE_DEFAULT;
284
+ }
285
+
286
+ // Returns true if jimage_init() has been called. Once the JImage file is initialized,
287
+ // jimage_is_preview_enabled() can be called to correctly determine the access mode.
288
+ static bool jimage_is_initialized () {
289
+ return jimage_exists () && JImage_mode != JIMAGE_MODE_UNINITIALIZED;
290
+ }
291
+
292
+ // Returns the access mode for an initialized JImage file (reflects --enable-preview).
293
+ static bool jimage_is_preview_enabled () {
294
+ assert (jimage_is_initialized (), " jimage is not initialized" );
295
+ return JImage_mode == JIMAGE_MODE_ENABLE_PREVIEW;
296
+ }
297
+
298
+ // Looks up the location of a named JImage resource. This "raw" lookup function allows
299
+ // the preview mode to be manually specified, so must not be accessible outside this
300
+ // class. ClassPathImageEntry manages all calls for resources after startup is complete.
301
+ static JImageLocationRef jimage_find_resource (const char * module_name,
302
+ const char * file_name,
303
+ bool is_preview,
304
+ jlong *size) {
305
+ return ((*JImageFindResource)(jimage_non_null (),
306
+ module_name,
307
+ get_jimage_version_string (),
308
+ file_name,
309
+ is_preview,
310
+ size));
311
+ }
312
+ // --------------------------------
313
+
237
314
// Given a fully qualified package name, find its defining package in the class loader's
238
315
// package entry table.
239
316
PackageEntry* ClassLoader::get_package_entry (Symbol* pkg_name, ClassLoaderData* loader_data) {
@@ -358,28 +435,15 @@ ClassFileStream* ClassPathZipEntry::open_stream(JavaThread* current, const char*
358
435
359
436
DEBUG_ONLY (ClassPathImageEntry* ClassPathImageEntry::_singleton = nullptr ;)
360
437
361
- JImageFile* ClassPathImageEntry::jimage() const {
362
- return JImage_file;
363
- }
364
-
365
- JImageFile* ClassPathImageEntry::jimage_non_null () const {
366
- assert (ClassLoader::has_jrt_entry (), " must be" );
367
- assert (jimage () != nullptr , " should have been opened by ClassLoader::lookup_vm_options "
368
- " and remained throughout normal JVM lifetime" );
369
- return jimage ();
370
- }
371
-
372
438
void ClassPathImageEntry::close_jimage() {
373
- if (jimage () != nullptr ) {
374
- (*JImageClose)(jimage ());
375
- JImage_file = nullptr ;
376
- }
439
+ jimage_close ();
377
440
}
378
441
379
- ClassPathImageEntry::ClassPathImageEntry (JImageFile* jimage, const char * name) :
442
+ ClassPathImageEntry::ClassPathImageEntry (const char * name) :
380
443
ClassPathEntry() {
381
- guarantee (jimage != nullptr , " jimage file is null " );
444
+ guarantee (jimage_is_initialized () , " jimage is not initialized " );
382
445
guarantee (name != nullptr , " jimage file name is null" );
446
+
383
447
assert (_singleton == nullptr , " VM supports only one jimage" );
384
448
DEBUG_ONLY (_singleton = this );
385
449
size_t len = strlen (name) + 1 ;
@@ -398,16 +462,18 @@ ClassFileStream* ClassPathImageEntry::open_stream(JavaThread* current, const cha
398
462
// 2. A package is in at most one module in the jimage file.
399
463
//
400
464
ClassFileStream* ClassPathImageEntry::open_stream_for_loader (JavaThread* current, const char * name, ClassLoaderData* loader_data) {
465
+ bool is_preview = jimage_is_preview_enabled ();
466
+
401
467
jlong size;
402
- JImageLocationRef location = (*JImageFindResource)( jimage_non_null (), " " , get_jimage_version_string (), name , &size);
468
+ JImageLocationRef location = jimage_find_resource ( " " , name, is_preview , &size);
403
469
404
470
if (location == 0 ) {
405
471
TempNewSymbol class_name = SymbolTable::new_symbol (name);
406
472
TempNewSymbol pkg_name = ClassLoader::package_from_class_name (class_name);
407
473
408
474
if (pkg_name != nullptr ) {
409
475
if (!Universe::is_module_initialized ()) {
410
- location = (*JImageFindResource)( jimage_non_null (), JAVA_BASE_NAME, get_jimage_version_string (), name , &size);
476
+ location = jimage_find_resource ( JAVA_BASE_NAME, name, is_preview , &size);
411
477
} else {
412
478
PackageEntry* package_entry = ClassLoader::get_package_entry (pkg_name, loader_data);
413
479
if (package_entry != nullptr ) {
@@ -418,7 +484,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
418
484
assert (module ->is_named (), " Boot classLoader package is in unnamed module" );
419
485
const char * module_name = module ->name ()->as_C_string ();
420
486
if (module_name != nullptr ) {
421
- location = (*JImageFindResource)( jimage_non_null (), module_name, get_jimage_version_string (), name , &size);
487
+ location = jimage_find_resource ( module_name, name, is_preview , &size);
422
488
}
423
489
}
424
490
}
@@ -431,7 +497,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
431
497
char * data = NEW_RESOURCE_ARRAY (char , size);
432
498
(*JImageGetResource)(jimage_non_null (), location, data, size);
433
499
// Resource allocated
434
- assert (this == (ClassPathImageEntry*) ClassLoader::get_jrt_entry (), " must be" );
500
+ assert (this == ClassLoader::get_jrt_entry (), " must be" );
435
501
return new ClassFileStream ((u1*)data,
436
502
checked_cast<int >(size),
437
503
_name,
@@ -441,16 +507,9 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
441
507
return nullptr ;
442
508
}
443
509
444
- JImageLocationRef ClassLoader::jimage_find_resource (JImageFile* jf,
445
- const char * module_name,
446
- const char * file_name,
447
- jlong &size) {
448
- return ((*JImageFindResource)(jf, module_name, get_jimage_version_string (), file_name, &size));
449
- }
450
-
451
510
bool ClassPathImageEntry::is_modules_image () const {
452
511
assert (this == _singleton, " VM supports a single jimage" );
453
- assert (this == (ClassPathImageEntry*) ClassLoader::get_jrt_entry (), " must be used for jrt entry" );
512
+ assert (this == ClassLoader::get_jrt_entry (), " must be used for jrt entry" );
454
513
return true ;
455
514
}
456
515
@@ -605,14 +664,15 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
605
664
struct stat st;
606
665
if (os::stat (path, &st) == 0 ) {
607
666
// Directory found
608
- if (JImage_file != nullptr ) {
667
+ if (jimage_exists () ) {
609
668
assert (Arguments::has_jimage (), " sanity check" );
610
669
const char * canonical_path = get_canonical_path (path, current);
611
670
assert (canonical_path != nullptr , " canonical_path issue" );
612
671
613
- _jrt_entry = new ClassPathImageEntry (JImage_file, canonical_path);
672
+ // Hand over lifecycle control of the JImage file to the _jrt_entry singleton
673
+ // (see ClassPathImageEntry::close_jimage). The image must be initialized by now.
674
+ _jrt_entry = new ClassPathImageEntry (canonical_path);
614
675
assert (_jrt_entry != nullptr && _jrt_entry->is_modules_image (), " No java runtime image present" );
615
- assert (_jrt_entry->jimage () != nullptr , " No java runtime image" );
616
676
} // else it's an exploded build.
617
677
} else {
618
678
// If path does not exist, exit
@@ -1384,49 +1444,51 @@ void ClassLoader::initialize(TRAPS) {
1384
1444
setup_bootstrap_search_path (THREAD);
1385
1445
}
1386
1446
1387
- static char * lookup_vm_resource (JImageFile *jimage, const char *jimage_version, const char *path) {
1388
- jlong size;
1389
- JImageLocationRef location = (*JImageFindResource)(jimage, " java.base" , jimage_version, path, &size);
1390
- if (location == 0 )
1391
- return nullptr ;
1392
- char *val = NEW_C_HEAP_ARRAY (char , size+1 , mtClass);
1393
- (*JImageGetResource)(jimage, location, val, size);
1394
- val[size] = ' \0 ' ;
1395
- return val;
1396
- }
1397
-
1398
1447
// Lookup VM options embedded in the modules jimage file
1399
1448
char * ClassLoader::lookup_vm_options () {
1400
- jint error;
1401
1449
char modules_path[JVM_MAXPATHLEN];
1402
1450
const char * fileSep = os::file_separator ();
1403
1451
1404
1452
// Initialize jimage library entry points
1405
1453
load_jimage_library ();
1406
1454
1407
1455
jio_snprintf (modules_path, JVM_MAXPATHLEN, " %s%slib%smodules" , Arguments::get_java_home (), fileSep, fileSep);
1408
- JImage_file =(*JImageOpen)(modules_path, &error);
1409
- if (JImage_file == nullptr ) {
1410
- return nullptr ;
1456
+ if (jimage_open (modules_path)) {
1457
+ // Special case where we lookup the options string *before* calling jimage_init().
1458
+ // Since VM arguments have not been parsed, and the ClassPathImageEntry singleton
1459
+ // has not been created yet, we access the JImage file directly in non-preview mode.
1460
+ jlong size;
1461
+ JImageLocationRef location =
1462
+ jimage_find_resource (JAVA_BASE_NAME, " jdk/internal/vm/options" , /* is_preview */ false , &size);
1463
+ if (location != 0 ) {
1464
+ char *options = NEW_C_HEAP_ARRAY (char , size+1 , mtClass);
1465
+ (*JImageGetResource)(jimage_non_null (), location, options, size);
1466
+ options[size] = ' \0 ' ;
1467
+ return options;
1468
+ }
1411
1469
}
1470
+ return nullptr ;
1471
+ }
1412
1472
1413
- const char *jimage_version = get_jimage_version_string ();
1414
- char *options = lookup_vm_resource (JImage_file, jimage_version, " jdk/internal/vm/options" );
1415
- return options;
1473
+ // Finishes initializing the JImageFile (if present) by setting the access mode.
1474
+ void ClassLoader::init_jimage (bool enable_preview) {
1475
+ if (jimage_exists ()) {
1476
+ jimage_init (enable_preview);
1477
+ }
1416
1478
}
1417
1479
1418
1480
bool ClassLoader::is_module_observable (const char * module_name) {
1419
1481
assert (JImageOpen != nullptr , " jimage library should have been opened" );
1420
- if (JImage_file == nullptr ) {
1482
+ if (! jimage_exists () ) {
1421
1483
struct stat st;
1422
1484
const char *path = get_exploded_module_path (module_name, true );
1423
1485
bool res = os::stat (path, &st) == 0 ;
1424
1486
FREE_C_HEAP_ARRAY (char , path);
1425
1487
return res;
1426
1488
}
1489
+ // We don't expect preview mode (i.e. --enable-preview) to affect module visibility.
1427
1490
jlong size;
1428
- const char *jimage_version = get_jimage_version_string ();
1429
- return (*JImageFindResource)(JImage_file, module_name, jimage_version, " module-info.class" , &size) != 0 ;
1491
+ return jimage_find_resource (module_name, " module-info.class" , /* is_preview */ false , &size) != 0 ;
1430
1492
}
1431
1493
1432
1494
jlong ClassLoader::classloader_time_ms () {
0 commit comments