JDK-8156930 : Bootstrapping circularity when profiling lambda-enabled code with Solaris Perf Analyzer
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:class_loading
  • Affected Version: 9
  • Priority: P3
  • Status: Resolved
  • Resolution: Duplicate
  • Submitted: 2016-05-13
  • Updated: 2016-06-08
  • Resolved: 2016-06-08
Related Reports
Relates :  
Description
This seems to fail with the stack trace similar to JDK-8155659, but this time it fails reliably when an external profiler, like Solaris Studio Perf Analyzer is attached to the process, and tests are loaded on bootclasspath. This blocks performance work.

This simple test with attached profiler fails:
$ perfanal ~/trunks/jdk9-dev/build/linux-x86_64-normal-server-release/images/jdk/bin/java -Xbootclasspath/a:. Test
$ alias perfanal='~/Install/solstudio/bin/collect -o test.1.er -S on -j on -A on '

public class Test {
        public static void main(String... args) {
                for (int c = 0; c < 1000000; c++) {
                        m(new Test()::run);
                }
        }

        static void m(Runnable r) {
                // do nothing
        }

        public void run() {
                // do nothing
        }
}

Exception in thread "main" java.lang.InternalError: java.lang.NullPointerException
	at java.lang.invoke.MethodHandles$LookupHelper.createClass(java.base@9-internal/MethodHandles.java:2204)
	at java.lang.invoke.MethodHandles$LookupHelper.access$200(java.base@9-internal/MethodHandles.java:2178)
	at java.lang.invoke.MethodHandles$LookupHelper$2.run(java.base@9-internal/MethodHandles.java:2212)
	at java.lang.invoke.MethodHandles$LookupHelper$2.run(java.base@9-internal/MethodHandles.java:2210)
	at java.security.AccessController.doPrivileged(java.base@9-internal/Native Method)
	at java.lang.invoke.MethodHandles$LookupHelper.<clinit>(java.base@9-internal/MethodHandles.java:2215)
	at java.lang.invoke.MethodHandles.publicLookup(java.base@9-internal/MethodHandles.java:140)
	at java.lang.invoke.MethodHandles$Lookup.canBeCached(java.base@9-internal/MethodHandles.java:2146)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(java.base@9-internal/MethodHandles.java:2111)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(java.base@9-internal/MethodHandleNatives.java:499)
	at Test.main(Test.java:5)
Caused by: java.lang.NullPointerException
	at java.lang.invoke.MethodHandles$Lookup.canBeCached(java.base@9-internal/MethodHandles.java:2147)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(java.base@9-internal/MethodHandles.java:2111)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(java.base@9-internal/MethodHandleNatives.java:499)
	at jdk.internal.loader.BuiltinClassLoader.findResource(java.base@9-internal/BuiltinClassLoader.java:267)
	at jdk.internal.loader.BootLoader.findResource(java.base@9-internal/BootLoader.java:136)
	at java.lang.ClassLoader.getResource(java.base@9-internal/ClassLoader.java:1299)
	at java.lang.ClassLoader.defineClass1(java.base@9-internal/Native Method)
	at java.lang.ClassLoader.defineClass(java.base@9-internal/ClassLoader.java:942)
	at java.lang.ClassLoader.defineClass(java.base@9-internal/ClassLoader.java:806)
	at java.lang.invoke.MethodHandles$LookupHelper$1.findClass(java.base@9-internal/MethodHandles.java:2198)
	at java.lang.ClassLoader.loadClass(java.base@9-internal/ClassLoader.java:486)
	at java.lang.ClassLoader.loadClass(java.base@9-internal/ClassLoader.java:419)
	at java.lang.invoke.MethodHandles$LookupHelper.createClass(java.base@9-internal/MethodHandles.java:2202)
	... 10 more

The circularity is caused by BuiltinClassLoader usage of lambdas. This particular instance happens when Main class links the lambdas, which initializes MH$LookupHelper when doing MH$Lookup.canBeCached. This leads to MH$LH.createClass, which doubles back on  BuiltinClassLoader.findResource, which has lambdas, which goes back to MH$LookupHelper... and the circle is complete.

The minimal patch that solves this particular circularity:
 http://cr.openjdk.java.net/~shade/8156930/poc.patch
Comments
The proof-of-concept patch suggested by Alan here went as part of JDK-8158851, making this issue a duplicate.
08-06-2016

After digging around, I think this is Solaris Perf Analyzer -specific issue. Unfortunately, we cannot easily tell what its agent does in JVM. I have tried to run with the next close thing that uses the same VM API (honest-profiler), and the test passes okay. Doing MH.publicLookup() early in initPhase3, as suggested by Alan, also makes the test pass: http://cr.openjdk.java.net/~shade/8156930/poc-2.patch
17-05-2016

We can drop the lambda usage in BuiltinClassLoader but I think I'd like to understand this specific issue a bit more. (It may be that we should call MH.publicLookup() at the start of initPhase3 so that we at least have publicLookup() initialised early. As I mentioned in JDK-8155659 then there will be updates to how MH works with modules but isn't there yet).
14-05-2016

I was trying to understand the same before submitting the bug, but failed to understand it yet. But I think the circularity is the same as in JDK-8155659, and we should probably try to fix that one first?
13-05-2016

Do we know what instrumentation is done to cause this? I'm asking because I don't see this with jdk9/dev.
13-05-2016