@@ -96,9 +96,18 @@ static JImageClose_t JImageClose = nullptr;
9696static JImageFindResource_t JImageFindResource = nullptr ;
9797static JImageGetResource_t JImageGetResource = nullptr ;
9898
99- // JimageFile pointer, or null if exploded JDK build.
99+ // JImageFile pointer, or null if exploded JDK build.
100100static JImageFile* JImage_file = nullptr ;
101101
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+
102111// Globals
103112
104113PerfCounter* ClassLoader::_perf_accumulated_time = nullptr ;
@@ -153,7 +162,7 @@ void ClassLoader::print_counters(outputStream *st) {
153162
154163GrowableArray<ModuleClassPathList*>* ClassLoader::_patch_mod_entries = nullptr ;
155164GrowableArray<ModuleClassPathList*>* ClassLoader::_exploded_entries = nullptr ;
156- ClassPathEntry * ClassLoader::_jrt_entry = nullptr ;
165+ ClassPathImageEntry * ClassLoader::_jrt_entry = nullptr ;
157166
158167ClassPathEntry* volatile ClassLoader::_first_append_entry_list = nullptr ;
159168ClassPathEntry* volatile ClassLoader::_last_append_entry = nullptr ;
@@ -170,15 +179,6 @@ static bool string_starts_with(const char* str, const char* str_to_find) {
170179}
171180#endif
172181
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-
182182bool ClassLoader::string_ends_with (const char * str, const char * str_to_find) {
183183 size_t str_len = strlen (str);
184184 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
233233 return SymbolTable::new_symbol (name, pointer_delta_as_int (start, base), pointer_delta_as_int (end, base));
234234}
235235
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+
236303// Given a fully qualified package name, find its defining package in the class loader's
237304// package entry table.
238305PackageEntry* ClassLoader::get_package_entry (Symbol* pkg_name, ClassLoaderData* loader_data) {
@@ -371,28 +438,15 @@ ClassFileStream* ClassPathZipEntry::open_stream(JavaThread* current, const char*
371438
372439DEBUG_ONLY (ClassPathImageEntry* ClassPathImageEntry::_singleton = nullptr ;)
373440
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-
385441void ClassPathImageEntry::close_jimage() {
386- if (jimage () != nullptr ) {
387- (*JImageClose)(jimage ());
388- JImage_file = nullptr ;
389- }
442+ jimage_close ();
390443}
391444
392- ClassPathImageEntry::ClassPathImageEntry (JImageFile* jimage, const char * name) :
445+ ClassPathImageEntry::ClassPathImageEntry (const char * name) :
393446 ClassPathEntry() {
394- guarantee (jimage != nullptr , " jimage file is null " );
447+ guarantee (jimage_is_initialized () , " jimage is not initialized " );
395448 guarantee (name != nullptr , " jimage file name is null" );
449+
396450 assert (_singleton == nullptr , " VM supports only one jimage" );
397451 DEBUG_ONLY (_singleton = this );
398452 size_t len = strlen (name) + 1 ;
@@ -411,16 +465,18 @@ ClassFileStream* ClassPathImageEntry::open_stream(JavaThread* current, const cha
411465// 2. A package is in at most one module in the jimage file.
412466//
413467ClassFileStream* ClassPathImageEntry::open_stream_for_loader (JavaThread* current, const char * name, ClassLoaderData* loader_data) {
468+ bool is_preview = jimage_is_preview_enabled ();
469+
414470 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);
416472
417473 if (location == 0 ) {
418474 TempNewSymbol class_name = SymbolTable::new_symbol (name);
419475 TempNewSymbol pkg_name = ClassLoader::package_from_class_name (class_name);
420476
421477 if (pkg_name != nullptr ) {
422478 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);
424480 } else {
425481 PackageEntry* package_entry = ClassLoader::get_package_entry (pkg_name, loader_data);
426482 if (package_entry != nullptr ) {
@@ -431,7 +487,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
431487 assert (module ->is_named (), " Boot classLoader package is in unnamed module" );
432488 const char * module_name = module ->name ()->as_C_string ();
433489 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);
435491 }
436492 }
437493 }
@@ -444,7 +500,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
444500 char * data = NEW_RESOURCE_ARRAY (char , size);
445501 (*JImageGetResource)(jimage_non_null (), location, data, size);
446502 // Resource allocated
447- assert (this == (ClassPathImageEntry*) ClassLoader::get_jrt_entry (), " must be" );
503+ assert (this == ClassLoader::get_jrt_entry (), " must be" );
448504 return new ClassFileStream ((u1*)data,
449505 checked_cast<int >(size),
450506 _name,
@@ -454,16 +510,9 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
454510 return nullptr ;
455511}
456512
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-
464513bool ClassPathImageEntry::is_modules_image () const {
465514 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" );
467516 return true ;
468517}
469518
@@ -618,14 +667,15 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
618667 struct stat st;
619668 if (os::stat (path, &st) == 0 ) {
620669 // Directory found
621- if (JImage_file != nullptr ) {
670+ if (jimage_exists () ) {
622671 assert (Arguments::has_jimage (), " sanity check" );
623672 const char * canonical_path = get_canonical_path (path, current);
624673 assert (canonical_path != nullptr , " canonical_path issue" );
625674
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);
627678 assert (_jrt_entry != nullptr && _jrt_entry->is_modules_image (), " No java runtime image present" );
628- assert (_jrt_entry->jimage () != nullptr , " No java runtime image" );
629679 } // else it's an exploded build.
630680 } else {
631681 // If path does not exist, exit
@@ -1388,49 +1438,51 @@ void ClassLoader::initialize(TRAPS) {
13881438 setup_bootstrap_search_path (THREAD);
13891439}
13901440
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-
14021441// Lookup VM options embedded in the modules jimage file
14031442char * ClassLoader::lookup_vm_options () {
1404- jint error;
14051443 char modules_path[JVM_MAXPATHLEN];
14061444 const char * fileSep = os::file_separator ();
14071445
14081446 // Initialize jimage library entry points
14091447 load_jimage_library ();
14101448
14111449 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+ }
14151463 }
1464+ return nullptr ;
1465+ }
14161466
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+ }
14201472}
14211473
14221474bool ClassLoader::is_module_observable (const char * module_name) {
14231475 assert (JImageOpen != nullptr , " jimage library should have been opened" );
1424- if (JImage_file == nullptr ) {
1476+ if (! jimage_exists () ) {
14251477 struct stat st;
14261478 const char *path = get_exploded_module_path (module_name, true );
14271479 bool res = os::stat (path, &st) == 0 ;
14281480 FREE_C_HEAP_ARRAY (char , path);
14291481 return res;
14301482 }
1483+ // We don't expect preview mode (i.e. --enable-preview) to affect module visibility.
14311484 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 ;
14341486}
14351487
14361488jlong ClassLoader::classloader_time_ms () {
0 commit comments