Fork me on GitHub
#clojure-dev
<
2019-01-18
>
cfleming00:01:10

Oh, I see what he means by visibility now. When the debugger has a reference to a classloader in the debugged JVM, it can call visibleClasses() to get a list of classes visible to the classloader. Unfortunately all this seems to be in a com.sun.tools.jdi package which is not part of the public JDI API.

cfleming00:01:03

Yeah, debugging that, it’s getting down to the wire protocol level. But according to that call, the DCL only has 13 classes visible, and it sounds like it should have all the JDK classes as well.

ghadi00:01:58

@cfleming but before alpha5 all classes were visible?

cfleming00:01:17

Just checking that now…

cfleming00:01:31

@ghadi So… no. But there are more classes visible, including Object.

cfleming00:01:48

0 = {com.sun.tools.jdi.ClassTypeImpl@39806} "class user$eval147$fn__148 (loaded by instance of clojure.lang.DynamicClassLoader(id=2791))"
1 = {com.sun.tools.jdi.ClassTypeImpl@39826} "class java.lang.Object (no class loader)"
2 = {com.sun.tools.jdi.ArrayTypeImpl@39827} "array class java.lang.Object[] (no class loader)"
3 = {com.sun.tools.jdi.ArrayTypeImpl@39828} "array class java.lang.Object[][] (no class loader)"
4 = {com.sun.tools.jdi.ClassTypeImpl@39829} "class clojure.lang.AFunction (loaded by instance of sun.misc.Launcher$AppClassLoader(id=2675))"
5 = {com.sun.tools.jdi.ClassTypeImpl@39830} "class user$eval147 (loaded by instance of clojure.lang.DynamicClassLoader(id=2791))"
6 = {com.sun.tools.jdi.ArrayTypeImpl@39831} "array class boolean[] (no class loader)"
7 = {com.sun.tools.jdi.ArrayTypeImpl@39832} "array class byte[] (no class loader)"
8 = {com.sun.tools.jdi.ArrayTypeImpl@39833} "array class byte[][] (no class loader)"
9 = {com.sun.tools.jdi.ArrayTypeImpl@39834} "array class char[] (no class loader)"
10 = {com.sun.tools.jdi.ArrayTypeImpl@39835} "array class int[] (no class loader)"
11 = {com.sun.tools.jdi.ArrayTypeImpl@39836} "array class short[] (no class loader)"
12 = {com.sun.tools.jdi.ArrayTypeImpl@39837} "array class long[] (no class loader)"
13 = {com.sun.tools.jdi.ArrayTypeImpl@39838} "array class long[][] (no class loader)"
14 = {com.sun.tools.jdi.ArrayTypeImpl@39839} "array class float[] (no class loader)"
15 = {com.sun.tools.jdi.ArrayTypeImpl@39840} "array class double[] (no class loader)"

cfleming00:01:54

That’s before

cfleming00:01:04

0 = {com.sun.tools.jdi.ClassTypeImpl@40142} "class user$eval147 (loaded by instance of clojure.lang.DynamicClassLoader(id=2790))"
1 = {com.sun.tools.jdi.ClassTypeImpl@40143} "class clojure.lang.AFunction (loaded by instance of sun.misc.Launcher$AppClassLoader(id=2677))"
2 = {com.sun.tools.jdi.ClassTypeImpl@40133} "class user$eval147$fn__148 (loaded by instance of clojure.lang.DynamicClassLoader(id=2790))"
3 = {com.sun.tools.jdi.ArrayTypeImpl@40144} "array class boolean[] (no class loader)"
4 = {com.sun.tools.jdi.ArrayTypeImpl@40145} "array class byte[] (no class loader)"
5 = {com.sun.tools.jdi.ArrayTypeImpl@40146} "array class byte[][] (no class loader)"
6 = {com.sun.tools.jdi.ArrayTypeImpl@40147} "array class char[] (no class loader)"
7 = {com.sun.tools.jdi.ArrayTypeImpl@40148} "array class int[] (no class loader)"
8 = {com.sun.tools.jdi.ArrayTypeImpl@40149} "array class short[] (no class loader)"
9 = {com.sun.tools.jdi.ArrayTypeImpl@40150} "array class long[] (no class loader)"
10 = {com.sun.tools.jdi.ArrayTypeImpl@40151} "array class long[][] (no class loader)"
11 = {com.sun.tools.jdi.ArrayTypeImpl@40152} "array class float[] (no class loader)"
12 = {com.sun.tools.jdi.ArrayTypeImpl@40153} "array class double[] (no class loader)"

cfleming00:01:08

That’s after.

cfleming00:01:47

I assume the classes with “no class loader” have been loaded by JDI when required rather than by the app, but I’m only guessing.

cfleming00:01:04

This is getting down to the black magic level unfortunately.

cfleming00:01:51

Here’s the javadoc of the exception. It’s pretty clear that it is normal for classes not to be visible - this is why they do the evaluation in a loop. https://docs.oracle.com/javase/8/docs/jdk/api/jpda/jdi/com/sun/jdi/ClassNotLoadedException.html

cfleming00:01:59

But I don’t understand why the DCL can’t see Object - Object must obviously be loaded, I provoke this bug after executing Clojure code so all the basic classes must be there.

seancorfield01:01:10

Object, Object[], and Object[][] all disappear.

seancorfield01:01:41

(watching this debugging discussion is quite fascinating -- thank you for doing this out in the open)

5
cfleming01:01:47

No worries, I’m just hoping someone else sees something I’ve missed 🙂

cfleming01:01:11

I’m basically stuck at the “needs someone who actually understands this bit” stage now.

cfleming01:01:46

I suspect there are like a dozen people in the world who understand JDI at this level - I’m hoping Egor is one of them.

cfleming02:01:57

Which version of ASM is vendored in at the moment?

dpsutton02:01:27

"vendor asm to sha 88a0aa8a79df7370cd178281bdf690ac2361c19a" but i actually can't find that commit in their tree

cfleming20:01:21

The issue seems to be with how Compiler.eval switches classloaders - it’s Saturday here and I haven’t had time to investigate properly, but I’ll report back later. The good thing is there seems to be a workaround on the Cursive side, but I guess any other JDI interface would have to do the same. It does seem like the classes Clojure generates are suspect under some circumstances, perhaps due to the new (well, new in Java 6) verifier.

Alex Miller (Clojure team)21:01:53

we should be using bytecode version 52 though now (java 1.8)?

Alex Miller (Clojure team)21:01:12

oh, he just means that’s when it starts failing

Alex Miller (Clojure team)21:01:58

we’re just using ASM in pretty normal ways so not sure what we’re doing that’s weird