JDK-8265605 : Cannot call BootLoader::loadClassOrNull before initPhase2
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 17
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2021-04-20
  • Updated: 2021-05-20
  • Resolved: 2021-05-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 17
17 b23Fixed
Related Reports
Relates :  
Description
test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodType* tests fail with an empty ArchivedClassLoaders::packageToModule when running with [1].

java.util.ServiceConfigurationError: Locale provider adapter "CLDR"cannot be instantiated.
	at java.base/sun.util.locale.provider.LocaleProviderAdapter.forType(LocaleProviderAdapter.java:199)
	at java.base/sun.util.locale.provider.LocaleProviderAdapter.findAdapter(LocaleProviderAdapter.java:287)
	at java.base/sun.util.locale.provider.LocaleProviderAdapter.getAdapter(LocaleProviderAdapter.java:258)
	at java.base/java.util.Calendar.createCalendar(Calendar.java:1693)
	at java.base/java.util.Calendar.getInstance(Calendar.java:1661)
	at java.base/java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:680)
	at java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:624)
	at java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:603)
	at org.testng.reporters.XMLReporter.addDurationAttributes(XMLReporter.java:180)
	at org.testng.reporters.XMLReporter.getSuiteAttributes(XMLReporter.java:171)
	at org.testng.reporters.XMLReporter.writeSuiteToBuffer(XMLReporter.java:114)
	at org.testng.reporters.XMLReporter.writeSuite(XMLReporter.java:86)
	at org.testng.reporters.XMLReporter.generateReport(XMLReporter.java:63)
	at org.testng.TestNG.generateReports(TestNG.java:1076)
	at org.testng.TestNG.run(TestNG.java:1035)
	at com.sun.javatest.regtest.agent.TestNGRunner.main(TestNGRunner.java:94)
	at com.sun.javatest.regtest.agent.TestNGRunner.main(TestNGRunner.java:54)
	at java.base/jdk.internal.reflect.DirectMethodAccessorImpl$StaticMethodAccessor.invoke(DirectMethodAccessorImpl.java:150)
	at java.base/java.lang.reflect.Method.invoke(Method.java:574)
	at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127)
	at java.base/java.lang.Thread.run(Thread.java:831)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.DirectConstructorAccessorImpl.newInstance(DirectConstructorAccessorImpl.java:91)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
	at java.base/sun.util.locale.provider.LocaleProviderAdapter.forType(LocaleProviderAdapter.java:188)
	... 20 more
Caused by: java.util.ServiceConfigurationError: sun.util.locale.provider.LocaleDataMetaInfo: Provider sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo not found
	at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589)
	at java.base/java.util.ServiceLoader.loadProvider(ServiceLoader.java:868)
	at java.base/java.util.ServiceLoader$ModuleServicesLookupIterator.hasNext(ServiceLoader.java:1076)
	at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299)
	at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1383)
	at java.base/sun.util.cldr.CLDRLocaleProviderAdapter$1.run(CLDRLocaleProviderAdapter.java:89)
	at java.base/sun.util.cldr.CLDRLocaleProviderAdapter$1.run(CLDRLocaleProviderAdapter.java:86)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:554)
	at java.base/sun.util.cldr.CLDRLocaleProviderAdapter.<init>(CLDRLocaleProviderAdapter.java:86)
	at java.base/jdk.internal.reflect.DirectConstructorAccessorImpl.newInstance(DirectConstructorAccessorImpl.java:79)
	... 23 more

It happens only when -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true is set (fastdebug build).

The tests pass when running with -Xshare:off or  disable the archived module graph by setting "-Djdk.module.showModuleResolution" when disabled the archive module graph but no trace output.

[1] https://github.com/openjdk/jdk/compare/master...mlchung:method-invoke-4
Comments
Changeset: 1e0ecd6d Author: Ioi Lam <iklam@openjdk.org> Date: 2021-05-14 06:26:41 +0000 URL: https://git.openjdk.java.net/jdk/commit/1e0ecd6d56541c948e0d120295f5008d3248598f
14-05-2021

After discussion with Mandy, I think we can fix it by changing BootLoader.loadClassOrNull to do this: protected Class<?> loadClassOrNull(String cn, boolean resolve) { return JLA.findBootstrapClassOrNull(cn); } also, change BootLoader.SERVICES_CATALOG to be initialized inside ClassLoaders.<clinit> (similar to app/platform loaders) https://github.com/iklam/jdk/compare/db0d644701d6e4232cceb3a083d7d78d66800dbe...e4720a6a32019d32024bf1bdfd03182e95f4b40a
04-05-2021

My recommendation for fixing this issue is to avoid accessing the BootLoader before the module system is initialized: https://github.com/iklam/jdk/commit/dcd0100b9f84600def401418a3d93e480dd9bedc S loadSpecies(S speciesData) { String className = speciesData.deriveClassName(); assert(className.indexOf('/') < 0) : className; Class<?> salvage = null; try { if (VM.isModuleSystemInited()) { salvage = BootLoader.loadClassOrNull(className); } else { salvage = JLA.findBootstrapClassOrNull(null, className); } With the above fix, my minimal test cases passes, as well as all tests under test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodType*
04-05-2021

I found that it would be very difficult to make BootLoader accessible to ClassSpecializer$Factory.loadSpecies() before the archived module graph is loaded: https://github.com/iklam/jdk/blame/db0d644701d6e4232cceb3a083d7d78d66800dbe/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java#L477 S loadSpecies(S speciesData) { String className = speciesData.deriveClassName(); assert(className.indexOf('/') < 0) : className; Class<?> salvage = null; try { salvage = BootLoader.loadClassOrNull(className); This would cause the following to be executed: class BootLoader { public static Class<?> loadClassOrNull(String name) { return ClassLoaders.bootLoader().loadClassOrNull(name); <<<<< } So ClassLoaders will be initialized: https://github.com/openjdk/jdk/blob/3544a9d0e4a071ad9c82aa17ab113e0101b4020b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java#L63 static { ArchivedClassLoaders archivedClassLoaders = ArchivedClassLoaders.get(); if (archivedClassLoaders != null) { // assert VM.getSavedProperty("jdk.boot.class.path.append") == null BOOT_LOADER = (BootClassLoader) archivedClassLoaders.bootLoader(); But this BOOT_LOADER contains initialized states for loaded modules. These states will not be consistent with the rest of the module system (such as the boot layer, which has not be initialized) The archived module graph must be initialized at a fixed order: https://github.com/openjdk/jdk/blob/3544a9d0e4a071ad9c82aa17ab113e0101b4020b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java#L167 if (archivedBootLayer != null) { assert canUseArchivedBootLayer(); bootLayer = archivedBootLayer.bootLayer(); BootLoader.getUnnamedModule(); // trigger <clinit> of BootLoader. CDS.defineArchivedModules(ClassLoaders.platformClassLoader(), ClassLoaders.appClassLoader()); // assume boot layer has at least one module providing a service // that is mapped to the application class loader. JLA.bindToLoader(bootLayer, ClassLoaders.appClassLoader()); So trying to access BootLoader before the above happens will not be safe.
04-05-2021

To recap the discussion Ioi and I had. The stacktrace shows that BootLoader is not useable prior to module system initialization with the archived module graph. ArchivedClassLoaders::packageToMap is empty if it's called prior to initPhase2. The fix for JDK-6824466 changes the core reflection to use method handles as soon as java.lang.invoke is initialized. This change considers that java.lang.invoke is fully initialized right before MethodHandleNatives::verifyConstants is called. At that point Field::get will use VarHandle to access fields. The java.lang.invoke implementation uses BootLoader::loadClassOrNull to find if species has been loaded. Prior to the CDS support to archive module graph, BootLoader is usable during early VM initialization since it delegates the class loading to VM via JavaLangAccess::findBootstrapClassOrNull. ArchivedClassLoaders, ArchivedBootLayer etc have changed the dependency that BuiltinClassLoader cannot be used before initPhase2. This restriction needs to be revisited. at java.base/java.lang.Thread.dumpStack(Thread.java:1377) at java.base/jdk.internal.loader.BuiltinClassLoader.<clinit>(BuiltinClassLoader.java:168) at java.base/jdk.internal.misc.CDS.initializeFromArchive(Native Method) at java.base/jdk.internal.loader.ArchivedClassLoaders.<clinit>(ArchivedClassLoaders.java:94) at java.base/jdk.internal.loader.BootLoader.<clinit>(BootLoader.java:70) at java.base/java.lang.invoke.ClassSpecializer$Factory.loadSpecies(ClassSpecializer.java:477) at java.base/java.lang.invoke.ClassSpecializer.findSpecies(ClassSpecializer.java:195) at java.base/java.lang.invoke.ClassSpecializer.<init>(ClassSpecializer.java:129) at java.base/java.lang.invoke.BoundMethodHandle$Specializer.<init>(BoundMethodHandle.java:404) at java.base/java.lang.invoke.BoundMethodHandle.<clinit>(BoundMethodHandle.java:382) at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method) at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1155) at java.base/java.lang.invoke.LambdaForm.createFormsFor(LambdaForm.java:1688) at java.base/java.lang.invoke.LambdaForm.identityForm(LambdaForm.java:1646) at java.base/java.lang.invoke.MethodHandles.makeIdentity(MethodHandles.java:5094) at java.base/java.lang.invoke.MethodHandles.identity(MethodHandles.java:5036) at java.base/java.lang.invoke.VarHandles.maybeAdapt(VarHandles.java:354) at java.base/java.lang.invoke.VarHandles.makeFieldHandle(VarHandles.java:150) at java.base/java.lang.invoke.MethodHandles$Lookup.getFieldVarHandleCommon(MethodHandles.java:4096) at java.base/java.lang.invoke.MethodHandles$Lookup.getFieldVarHandleNoSecurityManager(MethodHandles.java:4062) at java.base/java.lang.invoke.MethodHandles$Lookup.unreflectVarHandle(MethodHandles.java:3594) at java.base/java.lang.invoke.MethodHandleImpl$1.unreflectVarHandle(MethodHandleImpl.java:1845) at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.newFieldAccessor(MethodHandleAccessorFactory.java:112) at java.base/jdk.internal.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:181) at java.base/java.lang.reflect.Field.acquireFieldAccessor(Field.java:1128) at java.base/java.lang.reflect.Field.getFieldAccessor(Field.java:1109) at java.base/java.lang.reflect.Field.getInt(Field.java:597) at java.base/java.lang.invoke.MethodHandleNatives.verifyConstants(MethodHandleNatives.java:231) at java.base/java.lang.invoke.MethodHandleNatives.<clinit>(MethodHandleNatives.java:250)
23-04-2021

I can narrow down a minimal reproducer. The two -D options, as well as -esa, are required for the failure. public class SimpleDateFormatTester { public static void main(String args[]) { System.out.println(new java.text.SimpleDateFormat()); } } $ mach5/jdk-17/fastdebug/bin/java -showversion \ -esa \ -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true \ -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true \ -cp . SimpleDateFormatTester java version "17-internal" 2021-09-14 LTS Java(TM) SE Runtime Environment (fastdebug build 17-internal+0-LTS-2021-04-20-1945480.mandy.chung.closed) Java HotSpot(TM) 64-Bit Server VM (fastdebug build 17-internal+0-LTS-2021-04-20-1945480.mandy.chung.closed, mixed mode, sharing) Exception in thread "main" java.util.ServiceConfigurationError: Locale provider adapter "CLDR"cannot be instantiated. at java.base/sun.util.locale.provider.LocaleProviderAdapter.forType(LocaleProviderAdapter.java:199) at java.base/sun.util.locale.provider.LocaleProviderAdapter.findAdapter(LocaleProviderAdapter.java:287) at java.base/sun.util.locale.provider.LocaleProviderAdapter.getAdapter(LocaleProviderAdapter.java:258) at java.base/java.util.Calendar.createCalendar(Calendar.java:1693) at java.base/java.util.Calendar.getInstance(Calendar.java:1661) at java.base/java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:680) at java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:624) at java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:579) at SimpleDateFormatTester.main(SimpleDateFormatTester.java:3) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.DirectConstructorAccessorImpl.newInstance(DirectConstructorAccessorImpl.java:91) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) at java.base/sun.util.locale.provider.LocaleProviderAdapter.forType(LocaleProviderAdapter.java:188) ... 8 more Caused by: java.util.ServiceConfigurationError: sun.util.locale.provider.LocaleDataMetaInfo: Provider sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo not found at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:589) at java.base/java.util.ServiceLoader.loadProvider(ServiceLoader.java:868) at java.base/java.util.ServiceLoader$ModuleServicesLookupIterator.hasNext(ServiceLoader.java:1076) at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1299) at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1383) at java.base/sun.util.cldr.CLDRLocaleProviderAdapter$1.run(CLDRLocaleProviderAdapter.java:89) at java.base/sun.util.cldr.CLDRLocaleProviderAdapter$1.run(CLDRLocaleProviderAdapter.java:86) at java.base/java.security.AccessController.doPrivileged(AccessController.java:554) at java.base/sun.util.cldr.CLDRLocaleProviderAdapter.<init>(CLDRLocaleProviderAdapter.java:86) at java.base/jdk.internal.reflect.DirectConstructorAccessorImpl.newInstance(DirectConstructorAccessorImpl.java:79) ... 11 more
20-04-2021