Lambda class names no longer reported when listening for JVMTI_EVENT_CLASS_FILE_LOAD events
Frost, Gary
Gary.Frost at amd.com
Fri Jan 24 08:47:46 PST 2014
So is this an artifact of using the hash code of the class as the /XXXXXX
suffix.
As I mentioned below the classname in the bytes representing these VM
anonymous classes do not contain the suffix whereas the reflected name
does.
At first I was surprised, until I realized how non-trivial it was to
create class bytes for a class whose name depends on the hashcode of the
name of the class. It hurt my head thinking of this.
I really think that the reflected name of all classes should match the
name inside the classfile. Aparapi can¹t be the only byte code inspection
tool which makes this assumption.
Gary
On 1/24/14, 10:26 AM, "Joel Borggrén-Franck" <joel.franck at oracle.com>
wrote:
>Hi Peter,
>
>Back then I filed https://bugs.openjdk.java.net/browse/JDK-8029100
>
>feel free to assign to you if you have a fix.
>
>cheers
>/Joel
>
>On 24 Jan 2014, at 17:07, Peter Levart <peter.levart at gmail.com> wrote:
>
>> On 01/24/2014 12:48 AM, John Rose wrote:
>>> Background on anonymous classes:
>>>
>>> They are a private feature of the HotSpot JVM implementation.
>>>Naturally, compilers and other tightly-coupled tools have to know about
>>>them.
>>>
>>> They don't have names, at least in the sense of something you could
>>>use to look up via a class loader. What names they display are (as you
>>>see) derived from their bytecodes, but they do not function as regular
>>>class names.
>>>
>>> Specifically, if someone tries to use the supposed name of an
>>>anonymous class with Class.forName or ClassLoader.loadClass, the result
>>>will be ClassNotFoundException.
>>>
>>> The mangled suffix /XXXXX on Class.getName string provides an extra
>>>hint as to what is wrong. (The XXXXX value happens to be the class's
>>>hash code, which makes it easier to distinguish classes with the same
>>>supposed name.) Since slash '/' is an illegal element of class names,
>>>there's no ambiguity about how the name got that way.
>>>
>>> HTH
>>>
>>> ‹ John
>>
>> Hi John,
>>
>> Not long ago I found a special corner case where the following
>>expression:
>>
>>
>> Class.forName(clazz.getName(), clazz.getClassLoader()) == clazz
>>
>>
>> ...evaluates to false. Here's an example that demonstrates this:
>>
>>
>> public class AnnonClassTest {
>>
>> static class C {}
>>
>> public static void main(String[] args) throws Exception {
>> String cClassResourceName = C.class.getName().replace('.', '/')
>> + ".class";
>> URL cClassUrl =
>> C.class.getClassLoader().getResource(cClassResourceName);
>> byte[] bytes = new byte[4096];
>> try (InputStream in = cClassUrl.openStream();
>> ByteArrayOutputStream out = new ByteArrayOutputStream()) {
>> for (int nread = in.read(bytes); nread >= 0; nread =
>> in.read(bytes)) {
>> out.write(bytes, 0, nread);
>> }
>> bytes = out.toByteArray();
>> }
>>
>> Field uf = Unsafe.class.getDeclaredField("theUnsafe");
>> uf.setAccessible(true);
>> Unsafe u = (Unsafe) uf.get(null);
>>
>> Class<?> cAnnonClass = u.defineAnonymousClass(C.class, bytes,
>> new Object[0]);
>>
>> System.out.println(C.class.getName());
>> System.out.println(cAnnonClass.getName());
>> System.out.println(C.class == cAnnonClass);
>> System.out.println();
>>
>> Class<?> cArrayClass = C[].class;
>> Class<?> cAnnonArrayClass = Array.newInstance(cAnnonClass,
>> 0).getClass();
>>
>> System.out.println(cArrayClass.getName());
>> System.out.println(cAnnonArrayClass.getName());
>> System.out.println(cArrayClass == cAnnonArrayClass);
>> System.out.println();
>>
>> Class<?> whichArrayClass =
>> Class.forName(cAnnonArrayClass.getName());
>> System.out.println(whichArrayClass == cArrayClass);
>> System.out.println(whichArrayClass == cAnnonArrayClass);
>> }
>> }
>>
>>
>>
>> This prints the following:
>>
>>
>> AnnonClassTest$C
>> AnnonClassTest$C/2101973421
>> false
>>
>> [LAnnonClassTest$C;
>> [LAnnonClassTest$C;
>> false
>>
>> true
>> false
>>
>>
>> Do you agree it would be more correct if the name of the array of the
>> anonymous class in above example was:
>>
>>
>> [LAnnonClassTest$C/2101973421;
>>
>>
>> This would work more consistently then (throwing ClassNotFoundException
>> when trying to obtain such class by name).
>>
>>
>> Regards, Peter
>>
>>
>>>
>>>> Gary
>>>>
>>>> ________________________________________
>>>> From: Brian Goetz [brian.goetz at oracle.com]
>>>> Sent: Thursday, January 23, 2014 7:48 AM
>>>> To: Frost, Gary
>>>> Cc: lambda-dev at openjdk.java.net
>>>> Subject: Re: Lambda class names no longer reported when listening for
>>>>JVMTI_EVENT_CLASS_FILE_LOAD events
>>>>
>>>> Yes. We moved to "anonymous classes" (in the sense of
>>>>Unsafe.defineAnonymousClass, not anonymous inner classes), for reasons
>>>>of both security and performance. This is an unfortunate side effect.
>>>>
>>>> On Jan 22, 2014, at 5:33 PM, Frost, Gary wrote:
>>>>
>>>>> Not sure when this change came about but I just started using
>>>>>
>>>>> java version "1.8.0-ea"
>>>>> Java(TM) SE Runtime Environment (build 1.8.0-ea-b124)
>>>>>
>>>>> I noticed that the JVMTI agent I use to listen for
>>>>>JVMTI_EVENT_CLASS_FILE_LOAD events is no longer seeing events for the
>>>>>dynamically create classes created to encapsulate 'captured' args.
>>>>>Or possibly the class events are triggeted, but the 'name' is NULL. I
>>>>>am seeing an increase in the number of a events reported NULL as the
>>>>>name.
>>>>>
>>>>> The Aparapi project listens for these events so we can determine the
>>>>>captured args for a given lambda. These are the synthetic classes
>>>>>created on the fly by the method handle factory.
>>>>>
>>>>> This had been working fine until recently. Is there a reason we
>>>>>would stop generating these, or is this just a regression?
>>>>>
>>>>> Gary
>>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>
>
More information about the lambda-dev
mailing list