@@ -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
@@ -1439,49 +1489,51 @@ void ClassLoader::initialize(TRAPS) {
14391489  setup_bootstrap_search_path (THREAD);
14401490}
14411491
1442- static  char * lookup_vm_resource (JImageFile *jimage, const  char  *jimage_version, const  char  *path) {
1443-   jlong size;
1444-   JImageLocationRef location = (*JImageFindResource)(jimage, " java.base"  , jimage_version, path, &size);
1445-   if  (location == 0 )
1446-     return  nullptr ;
1447-   char  *val = NEW_C_HEAP_ARRAY (char , size+1 , mtClass);
1448-   (*JImageGetResource)(jimage, location, val, size);
1449-   val[size] = ' \0 '  ;
1450-   return  val;
1451- }
1452- 
14531492//  Lookup VM options embedded in the modules jimage file
14541493char * ClassLoader::lookup_vm_options () {
1455-   jint error;
14561494  char  modules_path[JVM_MAXPATHLEN];
14571495  const  char * fileSep = os::file_separator ();
14581496
14591497  //  Initialize jimage library entry points
14601498  load_jimage_library ();
14611499
14621500  jio_snprintf (modules_path, JVM_MAXPATHLEN, " %s%slib%smodules"  , Arguments::get_java_home (), fileSep, fileSep);
1463-   JImage_file =(*JImageOpen)(modules_path, &error);
1464-   if  (JImage_file == nullptr ) {
1465-     return  nullptr ;
1501+   if  (jimage_open (modules_path)) {
1502+     //  Special case where we lookup the options string *before* calling jimage_init().
1503+     //  Since VM arguments have not been parsed, and the ClassPathImageEntry singleton
1504+     //  has not been created yet, we access the JImage file directly in non-preview mode.
1505+     jlong size;
1506+     JImageLocationRef location =
1507+             jimage_find_resource (JAVA_BASE_NAME, " jdk/internal/vm/options"  , /*  is_preview */   false , &size);
1508+     if  (location != 0 ) {
1509+       char  *options = NEW_C_HEAP_ARRAY (char , size+1 , mtClass);
1510+       (*JImageGetResource)(jimage_non_null (), location, options, size);
1511+       options[size] = ' \0 '  ;
1512+       return  options;
1513+     }
14661514  }
1515+   return  nullptr ;
1516+ }
14671517
1468-   const  char  *jimage_version = get_jimage_version_string ();
1469-   char  *options = lookup_vm_resource (JImage_file, jimage_version, " jdk/internal/vm/options"  );
1470-   return  options;
1518+ //  Finishes initializing the JImageFile (if present) by setting the access mode.
1519+ void  ClassLoader::init_jimage (bool  enable_preview) {
1520+   if  (jimage_exists ()) {
1521+     jimage_init (enable_preview);
1522+   }
14711523}
14721524
14731525bool  ClassLoader::is_module_observable (const  char * module_name) {
14741526  assert (JImageOpen != nullptr , " jimage library should have been opened"  );
1475-   if  (JImage_file ==  nullptr ) {
1527+   if  (! jimage_exists () ) {
14761528    struct  stat  st;
14771529    const  char  *path = get_exploded_module_path (module_name, true );
14781530    bool  res = os::stat (path, &st) == 0 ;
14791531    FREE_C_HEAP_ARRAY (char , path);
14801532    return  res;
14811533  }
1534+   //  We don't expect preview mode (i.e. --enable-preview) to affect module visibility.
14821535  jlong size;
1483-   const  char  *jimage_version = get_jimage_version_string ();
1484-   return  (*JImageFindResource)(JImage_file, module_name, jimage_version, " module-info.class"  , &size) != 0 ;
1536+   return  jimage_find_resource (module_name, " module-info.class"  , /*  is_preview */   false , &size) != 0 ;
14851537}
14861538
14871539jlong ClassLoader::classloader_time_ms () {
0 commit comments