RFR(S): 8185694: Replace SystemDictionaryShared::_java_platform_loader with SystemDictionary::is_platform_class_loader()

David Holmes david.holmes at oracle.com
Fri Oct 6 05:38:39 UTC 2017


On 6/10/2017 3:28 PM, Calvin Cheung wrote:
> On 10/5/17, 6:33 PM, David Holmes wrote:
>> Hi Coleen, Calvin,
>>
>> On 6/10/2017 6:54 AM, coleen.phillimore at oracle.com wrote:
>>> So if you use -Djava.system.loader=myLoader on the command line, 
>>> setting _java_system_loader, then does that mean that the classes 
>>> loaded by 
>>> SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() 
>>> are not in the system loader?  ie. they can be unloaded?  What is the 
>>> result of the call to SystemDictionary::is_system_class_loader() used 
>>> for?   I guess same question applies to the platform class loader.
>>
>> The classloading delegation hierarchy (as of JDK 9) is:
>> - boot loader (native)
>>   - platform loader (built-in)
>>     - system (aka application) loader (built-in)
>>
>> If the user specifies a custom class for the system loader then it is 
>> loaded by an instance of the default system loader and becomes a 
>> fourth level in the hierarchy, and it is then technically the "system 
>> loader". None of these loaders, or the classes they load can be unloaded.
>>
>> Which is presumably why the code checks both:
>>
>>  180 bool SystemDictionary::is_system_class_loader(oop class_loader) {
>>  181   if (class_loader == NULL) {
>>  182     return false;
>>  183   }
>>  184   return (class_loader->klass() == 
>> SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() 
>> ||
>>  185           class_loader == _java_system_loader);
>>  186 }
>>
>> because we need to treat both of these instances as the "system 
>> loader" from a VM perspective? The same does not apply to the platform 
>> loader.
> We're obtaining the _java_system_loader after initPhase3 even before 
> this change. Roughly, the calling sequence of initPhase3 is as follows:
> 
> call_initPhase3()
>      -> ClassLoader.initPhase3()
>          -> ClassLoader.initSystemClassLoader()  which contains the 
> following code:
> 
>          String cn = System.getProperty("java.system.class.loader");
>          if (cn != null) {
>              try {
>                  // custom class loader is only supported to be loaded 
> from unnamed module
>                  Constructor<?> ctor = Class.forName(cn, false, 
> builtinLoader)
> .getDeclaredConstructor(ClassLoader.class);
>                  scl = (ClassLoader) ctor.newInstance(builtinLoader);
>              } catch (Exception e) {
>                  throw new Error(e);
>              }
>          } else {
>              scl = builtinLoader;
>          }
>          return scl;
> 
>          So initSystemClassLoader() will either return the built-in 
> system loader or a custom loader if it exists.
> 
> We use the getSystemClassLoader API to obtain the _java_system_loader:
> 
>      public static ClassLoader getSystemClassLoader() {
>          switch (VM.initLevel()) {
>              case 0:
>              case 1:
>              case 2:
>                  // the system class loader is the built-in app class 
> loader during startup
>                  return getBuiltinAppClassLoader();
>              case 3:
>                  String msg = "getSystemClassLoader should only be 
> called after VM booted";
>                  throw new InternalError(msg);
>              case 4:
>                  // system fully initialized
>                  assert VM.isBooted() && scl != null;
>                  SecurityManager sm = System.getSecurityManager();
>                  if (sm != null) {
>                      checkClassLoaderPermission(scl, 
> Reflection.getCallerClass());
>                  }
>                  return scl;
>              default:
>                  throw new InternalError("should not reach here");
>          }
>      }
> 
>      So the _java_system_loader will either be the built-in system 
> loader or a custom loader. (case 4 in the above)
> 
>      I don't quite understand why the check in line 184 is required?
>      Is it for checking if a given class_loader is the same type (like 
> an instanceof) as the built-in system loader?

I believe it is checking if the loader is the built-in default system 
loader, both to account for the case where/if 
SystemDictionary::is_system_class_loader is called prior to initPhase3 
completing; and also to account for encountering the default-built-in 
loader when the custom system loader delegates to it.

I'd have to examine every call path to 
SystemDictionary::is_system_class_loader to check all the details.

David
-----

> thanks,
> Calvin
>>
>> David
>> -----
>>
>>> thanks,
>>> Coleen
>>>
>>>>
>>>>> The implementation is in closed source.
>>>> Please clean up the closed code to remove those.
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Jiangli
>>>>
>>>>>> Is this new java_platform_loader function used anywhere?
>>>>> Yes, it is being used in closed source.
>>>>>> Currently 
>>>>>> SystemDictionary::jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass 
>>>>>> is preloaded.  Shouldn't this be removed?  What about 
>>>>>> jdk_internal_loader_ClassLoaders_AppClassLoader?
>>>>> They're being used in lines 184 and 193 in systemDictionary.cpp and 
>>>>> also in closed source.
>>>>>> thread.cpp
>>>>>>
>>>>>> 3752 SystemDictionary::compute_java_loaders(CHECK_(JNI_ERR));
>>>>>>
>>>>>> What is the difference between CHECK_(JNI_ERR) vs CHECK_JNI_ERR? 
>>>>>> Should it simply use CHECK_JNI_ERR as in other places?
>>>>> They are the same, in utilities/exceptions.hpp:
>>>>> #define CHECK_JNI_ERR                            CHECK_(JNI_ERR)
>>>>>
>>>>> and it expands to the following:
>>>>> __the_thread__); if 
>>>>> ((((ThreadShadow*)__the_thread__)->has_pending_exception())) return 
>>>>> (-1); (void)(0
>>>>>
>>>>> I can change it to CHECK_JNI_ERR.
>>>>>
>>>>> thanks,
>>>>> Calvin
>>>>>> Mandy
>>>


More information about the hotspot-runtime-dev mailing list