experiences with prototype

Peter Levart peter.levart at gmail.com
Sun Feb 8 10:43:20 UTC 2015


I've got it.

The problem was that Any.<int>toStringImpl() instance method was 
private. Since it is located in a specialized (Any${0=I}) class, it is 
not accessible from Any class (or specialized VM anonymous class 
generated for a specialized generic static method). The VerifyError: 
"Bad invokespecial instruction: current class isn't assignable to 
reference class." is not very informative though.

By making the method(s) package-private, my test now runs correctly.

Regards, Peter

On 02/08/2015 11:27 AM, Peter Levart wrote:
> Hi Maurizio,
>
> This is great. I replaced all new-style for loops on <any T> T[] 
> arrays with classic on-index iteration and applied your patch 
> selectively without the redundant cast in javany/util/Arrays.java:823:
>
>     a = (E[])Objects.requireNonNull(array)
>
> ... as I think your last langtools patch (99ab651be669) fixes that, right?
>
>
> Now with the following code:
>
> http://cr.openjdk.java.net/~plevart/misc/valhala-hacks/javany-src.02.jar
>
> And this test:
>
> public class Test {
>
>     static void testStrings() {
>         List<String> strings = Arrays.<String>asList("a", "b", "c");
>         System.out.println(strings);
>     }
>
>     static void testInts() {
>         List<int> ints = Arrays.<int>asList(1, 2, 3);
>         System.out.println(ints);
>     }
>
>     public static void main(String[] args) {
>         testStrings();
>         testInts();
>     }
> }
>
>
> I get:
>
> [a, b, c]
> Specializing javany.util.List${0=I}; searching for 
> javany/util/List.class (not found)
> Specializing javany.util.List${0=I}; searching for 
> javany/util/List.class (found)
> Specializing javany.util.Collection${0=I}; searching for 
> javany/util/Collection.class (not found)
> Specializing javany.util.Collection${0=I}; searching for 
> javany/util/Collection.class (found)
> Specializing javany.lang.Iterable${0=I}; searching for 
> javany/lang/Iterable.class (not found)
> Specializing javany.lang.Iterable${0=I}; searching for 
> javany/lang/Iterable.class (found)
> Specializing method 
> javany/util/Arrays$asList${0=I}.asList([Ljava/lang/Object;)Ljavany/util/List; 
> with class=[] and method=[I]
> Specializing javany.util.Arrays$ArrayList${0=I}; searching for 
> javany/util/Arrays$ArrayList.class (not found)
> Specializing javany.util.Arrays$ArrayList${0=I}; searching for 
> javany/util/Arrays$ArrayList.class (found)
> Specializing javany.util.AbstractList${0=I}; searching for 
> javany/util/AbstractList.class (not found)
> Specializing javany.util.AbstractList${0=I}; searching for 
> javany/util/AbstractList.class (found)
> Specializing javany.util.AbstractCollection${0=I}; searching for 
> javany/util/AbstractCollection.class (not found)
> Specializing javany.util.AbstractCollection${0=I}; searching for 
> javany/util/AbstractCollection.class (found)
> Specializing javany.util.Iterator${0=I}; searching for 
> javany/util/Iterator.class (not found)
> Specializing javany.util.Iterator${0=I}; searching for 
> javany/util/Iterator.class (found)
> Specializing javany.util.ListIterator${0=I}; searching for 
> javany/util/ListIterator.class (not found)
> Specializing javany.util.ListIterator${0=I}; searching for 
> javany/util/ListIterator.class (found)
> Specializing javany.util.AbstractList$Itr${0=I}; searching for 
> javany/util/AbstractList$Itr.class (not found)
> Specializing javany.util.AbstractList$Itr${0=I}; searching for 
> javany/util/AbstractList$Itr.class (found)
> Specializing method 
> javany/util/Any$toString${0=I}.toString(Ljava/lang/Object;)Ljava/lang/String; 
> with class=[] and method=[I]
> Specializing javany.util.Any${0=I}; searching for 
> javany/util/Any.class (not found)
> Specializing javany.util.Any${0=I}; searching for 
> javany/util/Any.class (found)
> Exception in thread "main" java.lang.BootstrapMethodError: call site 
> initialization exception
>         at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
>         at 
> java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
>         at 
> java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
>         at 
> javany.util.AbstractCollection${0=I}.toString(AbstractCollection.java:514)
>         at java.lang.String.valueOf(String.java:2987)
>         at java.io.PrintStream.println(PrintStream.java:821)
>         at Test.testInts(Test.java:17)
>         at Test.main(Test.java:22)
> Caused by: java.lang.VerifyError: Bad invokespecial instruction: 
> current class isn't assignable to reference class.
> Exception Details:
>   Location:
>     javany/util/Any$toString${0=I}.toString(I)Ljava/lang/String; @8: 
> invokespecial
>   Reason:
>     Error exists in the bytecode
>   Bytecode:
>     0000000: bb00 0959 b700 0d1a b700 10b0
>
>         at sun.misc.Unsafe.defineAnonymousClass(Native Method)
>         at 
> java.lang.invoke.GenericMethodSpecializer.metafactory(GenericMethodSpecializer.java:98)
>         at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
>         ... 7 more
>
>
> But looking at generated bytecode:
>
>
> Classfile 
> /home/peter/work/local/valhalla-test/dump/javany.util.Any$toString${0=I}_ERROR.class
>   Last modified Feb 8, 2015; size 321 bytes
>   MD5 checksum 7dac6f4f515394e0aa2ed1990a092697
>   Compiled from "Any.java"
> public class javany.util.Any$toString${0=I}
>   minor version: 0
>   major version: 52
>   flags: ACC_PUBLIC, ACC_SUPER
> Constant pool:
>    #1 = Utf8               javany/util/Any$toString${0=I}
>    #2 = Class              #1             // 
> "javany/util/Any$toString${0=I}"
>    #3 = Utf8               java/lang/Object
>    #4 = Class              #3             // java/lang/Object
>    #5 = Utf8               Any.java
>    #6 = Utf8               toString
>    #7 = Utf8               (I)Ljava/lang/String;
>    #8 = Utf8               javany/util/Any${0=I}
>    #9 = Class              #8             // "javany/util/Any${0=I}"
>   #10 = Utf8               <init>
>   #11 = Utf8               ()V
>   #12 = NameAndType        #10:#11        // "<init>":()V
>   #13 = Methodref          #9.#12         // 
> "javany/util/Any${0=I}"."<init>":()V
>   #14 = Utf8               toStringImpl
>   #15 = NameAndType        #14:#7         // 
> toStringImpl:(I)Ljava/lang/String;
>   #16 = Methodref          #9.#15         // 
> "javany/util/Any${0=I}".toStringImpl:(I)Ljava/lang/String;
>   #17 = Utf8               Code
>   #18 = Utf8               LineNumberTable
>   #19 = Utf8               Signature
>   #20 = Utf8               SourceFile
> {
>   public static java.lang.String toString(int);
>     descriptor: (I)Ljava/lang/String;
>     flags: ACC_PUBLIC, ACC_STATIC
>     Code:
>       stack=2, locals=1, args_size=1
>          0: new           #9                  // class 
> "javany/util/Any${0=I}"
>          3: dup
>          4: invokespecial #13                 // Method 
> "javany/util/Any${0=I}"."<init>":()V
>          7: iload_0
>          8: invokespecial #16                 // Method 
> "javany/util/Any${0=I}".toStringImpl:(I)Ljava/lang/String;
>         11: areturn
>       LineNumberTable:
>         line 31: 0
>     Signature: #7                           // (I)Ljava/lang/String;
> }
> SourceFile: "Any.java"
>
>
> Comparing it to original Any.class bytecode:
>
>
>   public static <T extends java.lang.Object> java.lang.String toString(T);
>     descriptor: (Ljava/lang/Object;)Ljava/lang/String;
>     flags: ACC_PUBLIC, ACC_STATIC
>     Code:
>       stack=2, locals=1, args_size=1
>          0: new           #3                  // class javany/util/Any
>          3: dup
>          4: invokespecial #4                  // Method "<init>":()V
>          7: aload_0
>          8: invokespecial #8                  // Method 
> toStringImpl:(Ljava/lang/Object;)Ljava/lang/String;
>         11: areturn
>       LineNumberTable:
>         line 31: 0
> Error: unknown attribute
>       BytecodeMapping: length = 0x12
>        00 04 00 00 00 8C 00 04 00 8D 00 07 00 87 00 08
>        00 9F
>     Signature: #160                         // 
> <T:Ljava/lang/Object;>(TT;)Ljava/lang/String;
> Error: unknown attribute
>       TypeVariablesMap: length = 0x9
>        01 00 A1 01 01 00 92 00 86
>
>
> And also peeking at Any${0=I}.class:
>
>
>   private java.lang.String toStringImpl(int);
>     descriptor: (I)Ljava/lang/String;
>     flags: ACC_PRIVATE
>     Code:
>       stack=2, locals=2, args_size=2
>          0: aload_0
>          1: iload_1
>          2: invokespecial #45                 // Method 
> toStringNonNullImpl:(I)Ljava/lang/String;
>          5: areturn
>       LineNumberTable:
>         line 181: 0
>     Signature: #33                          // (I)Ljava/lang/String;
>
>
> ...I can't spot what's wrong. Can you?
>
>
> Regards, Peter
>
>
> On 02/06/2015 03:38 PM, Maurizio Cimadamore wrote:
>> Peter,
>> I think I fixed most of the issues in the way; I've been able to 
>> compile and run some tests successfully.
>> Attached is a patch of the changes that are required for the code to 
>> run correctly; I had to desugar some constructs (i.e. for-each, 
>> non-static inner class) as all desugared stuff currently has an issue 
>> in that javac won't emit the special sauce that is required by the 
>> specializer to correctly specialize a class. That's an issue with 
>> timing of the compilation pipeline - we are aware of it; but, as it's 
>> a no trivial fix, it means that, for now, it's better not to rely too 
>> much of compiler-desugared code.
>>
>> Maurizio
>>
>> On 04/02/15 12:42, Maurizio Cimadamore wrote:
>>> Compiler fixes have been pushed, I will now look into the runtime 
>>> issues you are getting...
>>>
>>> Maurizio
>>>
>>> On 04/02/15 10:18, Maurizio Cimadamore wrote:
>>>> Thanks for the additional feedback, I'll try to get at the bottom 
>>>> of those issues.
>>>>
>>>> Maurizio
>>>>
>>>> On 04/02/15 08:46, Peter Levart wrote:
>>>>> Hi Maurizio,
>>>>>
>>>>> I have now managed to successfully compile the code. Here's the 
>>>>> updated source:
>>>>>
>>>>> http://cr.openjdk.java.net/~plevart/misc/valhala-hacks/javany-src.jar
>>>>>
>>>>>
>>>>> But there's a StringIndexOutOfBoundsException thrown from 
>>>>> specializer when running the following Test:
>>>>>
>>>>> public class Test {
>>>>>     public static void main(String[] args) {
>>>>>         List<int> ints = Arrays.asList(new int[]{1, 2, 3, 4, 5, 6, 
>>>>> 7, 8});
>>>>>         Iterator<int> it = ints.iterator();
>>>>>         while (it.hasNext()) {
>>>>>             System.out.println(it.next());
>>>>>         }
>>>>>     }
>>>>> }
>>>>>
>>>>>
>>>>> Specializing javany.util.List${0=I}; searching for 
>>>>> javany/util/List.class (not found)
>>>>> Specializing javany.util.List${0=I}; searching for 
>>>>> javany/util/List.class (found)
>>>>> Specializing javany.util.Collection${0=I}; searching for 
>>>>> javany/util/Collection.class (not found)
>>>>> Specializing javany.util.Collection${0=I}; searching for 
>>>>> javany/util/Collection.class (found)
>>>>> Specializing javany.lang.Iterable${0=I}; searching for 
>>>>> javany/lang/Iterable.class (not found)
>>>>> Specializing javany.lang.Iterable${0=I}; searching for 
>>>>> javany/lang/Iterable.class (found)
>>>>> Specializing method 
>>>>> javany/util/Arrays$asList${0=I}.asList([Ljava/lang/Object;)Ljavany/util/List; 
>>>>> with class=[] and method=[I]
>>>>> Specializing javany.util.Arrays$ArrayList${0=I}; searching for 
>>>>> javany/util/Arrays$ArrayList.class (not found)
>>>>> Specializing javany.util.Arrays$ArrayList${0=I}; searching for 
>>>>> javany/util/Arrays$ArrayList.class (found)
>>>>> Exception in thread "main" 
>>>>> java.lang.StringIndexOutOfBoundsException: String index out of 
>>>>> range: 0
>>>>>         at java.lang.String.charAt(String.java:646)
>>>>>         at 
>>>>> jdk.internal.org.objectweb.asm.signature.SignatureReader.accept(SignatureReader.java:107)
>>>>>         at 
>>>>> valhalla.specializer.SignatureSpecializer.forType(SignatureSpecializer.java:72)
>>>>>         at 
>>>>> valhalla.specializer.Specializer$ManglingMethodVisitor.visitInvokeDynamicInsn(Specializer.java:679)
>>>>>         at 
>>>>> jdk.internal.org.objectweb.asm.ClassReader.readCode(ClassReader.java:1507)
>>>>>         at 
>>>>> jdk.internal.org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1084)
>>>>>         at 
>>>>> jdk.internal.org.objectweb.asm.ClassReader.accept(ClassReader.java:729) 
>>>>>
>>>>>         at 
>>>>> valhalla.specializer.Specializer.specialize(Specializer.java:79)
>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:409)
>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:386)
>>>>>         at java.security.AccessController.doPrivileged(Native Method)
>>>>>         at java.net.URLClassLoader.findClass(URLClassLoader.java:385)
>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:426)
>>>>>         at 
>>>>> sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:317)
>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:359)
>>>>>         at 
>>>>> javany.util.Arrays$asList${0=I}/511754216.asList(Arrays.java:810)
>>>>>         at Test.main(Test.java:10)
>>>>>
>>>>>
>>>>> Appart from that, I learned that when the component type of vararg 
>>>>> array is an <any> type variable (for example: <any T> T[] 
>>>>> Arrays.asList(T ... a)), the invocation doesn't compile:
>>>>>
>>>>> src/Test.java:10: error: method invoked with incorrect number of 
>>>>> arguments; expected 3, found 1
>>>>>         List<int> ints = Arrays.<int>asList(1, 2, 3);
>>>>>                          ^
>>>>> 1 error
>>>>>
>>>>>
>>>>> Non-specialized code also has problems at runtime:
>>>>>
>>>>> public class Test {
>>>>>     public static void main(String[] args) {
>>>>>         List<String> strings = Arrays.<String>asList("a", "b", "c");
>>>>>         Iterator<String> it = strings.iterator();
>>>>>         while (it.hasNext()) {
>>>>>             System.out.println(it.next());
>>>>>         }
>>>>>     }
>>>>> }
>>>>>
>>>>>
>>>>> Exception in thread "main" java.lang.ClassFormatError: Absent Code 
>>>>> attribute in method that is not native or abstract in class file 
>>>>> javany/util/AbstractList
>>>>>         at java.lang.ClassLoader.defineClass1(Native Method)
>>>>>         at java.lang.ClassLoader.defineClass(ClassLoader.java:762)
>>>>>         at 
>>>>> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 
>>>>>
>>>>>         at 
>>>>> java.net.URLClassLoader.defineClass(URLClassLoader.java:537)
>>>>>         at java.net.URLClassLoader.access$300(URLClassLoader.java:78)
>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:438)
>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:386)
>>>>>         at java.security.AccessController.doPrivileged(Native Method)
>>>>>         at java.net.URLClassLoader.findClass(URLClassLoader.java:385)
>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:426)
>>>>>         at 
>>>>> sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:317)
>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:359)
>>>>>         at java.lang.ClassLoader.defineClass1(Native Method)
>>>>>         at java.lang.ClassLoader.defineClass(ClassLoader.java:762)
>>>>>         at 
>>>>> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 
>>>>>
>>>>>         at 
>>>>> java.net.URLClassLoader.defineClass(URLClassLoader.java:537)
>>>>>         at java.net.URLClassLoader.access$300(URLClassLoader.java:78)
>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:438)
>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:386)
>>>>>         at java.security.AccessController.doPrivileged(Native Method)
>>>>>         at java.net.URLClassLoader.findClass(URLClassLoader.java:385)
>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:426)
>>>>>         at 
>>>>> sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:317)
>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:359)
>>>>>         at javany.util.Arrays.asList(Arrays.java:810)
>>>>>         at Test.main(Test.java:10)
>>>>>
>>>>>
>>>>>
>>>>> Regards, Peter
>>>>>
>>>>> On 02/03/2015 10:34 PM, Maurizio Cimadamore wrote:
>>>>>>
>>>>>> On 03/02/15 21:05, Peter Levart wrote:
>>>>>>> Hi Maurizio,
>>>>>>>
>>>>>>> I see. I thought this could be a nice idiom for boxing, since 
>>>>>>> the following:
>>>>>>>
>>>>>>> (Object) 42
>>>>>>>
>>>>>>> ...is legal and results in an Integer object at runtime.
>>>>>> I'm not saying this will never work - actually the compiler is 
>>>>>> currently accepting this kind of idioms, but the specializer does 
>>>>>> nothing with it, so you'll get runtime errors.
>>>>>>>
>>>>>>> But I don't know if a checkcast is actually inserted for 
>>>>>>> (Object). Could javac redundantly do it in case casting to 
>>>>>>> Object is from expression of <any> type and also equip checkcast 
>>>>>>> with BMA indicating the type of expression so that 
>>>>>>> specialization could replace it with boxing code?
>>>>>> That will be the way forward, yes
>>>>>>
>>>>>> Maurizio
>>>>>>>
>>>>>>> Regards, Peter
>>>>>>>
>>>>>>>
>>>>>>> On 02/03/2015 08:09 PM, Maurizio Cimadamore wrote:
>>>>>>>>
>>>>>>>> On 03/02/15 18:46, Maurizio Cimadamore wrote:
>>>>>>>>> I will also investigate on the crash you are getting... 
>>>>>>>> Hi Peter,
>>>>>>>> the crash is coming from this code in AbstractCollection (see 
>>>>>>>> code in bold):
>>>>>>>>
>>>>>>>>     public boolean contains(Object o) {
>>>>>>>>         __WhereVal(E) {
>>>>>>>>             Iterator<E> it = iterator();
>>>>>>>>             if (o == null) {
>>>>>>>>                 return false;
>>>>>>>>             } else {
>>>>>>>>                 while (it.hasNext())
>>>>>>>> *if (o.equals((Object) it.next()))*
>>>>>>>>                         return true;
>>>>>>>>             }
>>>>>>>>             return false;
>>>>>>>>         }
>>>>>>>>         __WhereRef(E) {
>>>>>>>>             Iterator<E> it = iterator();
>>>>>>>>             if (o == null) {
>>>>>>>>                 while (it.hasNext())
>>>>>>>>                     if (it.next() == null)
>>>>>>>>                         return true;
>>>>>>>>             } else {
>>>>>>>>                 while (it.hasNext())
>>>>>>>>                     if (o.equals(it.next()))
>>>>>>>>                         return true;
>>>>>>>>             }
>>>>>>>>             return false;
>>>>>>>>         }
>>>>>>>>     }
>>>>>>>>
>>>>>>>> I believe that, apart from the obvious javac bug, the code has 
>>>>>>>> an issue, as it.next() is supposed to return a value there, but 
>>>>>>>> you are casting to Object?
>>>>>>>>
>>>>>>>> For the records - a simpler test case for the bug is this:
>>>>>>>>
>>>>>>>> class Foo<any E> {
>>>>>>>>     E e;
>>>>>>>>     E get() { return e; }
>>>>>>>>
>>>>>>>>     void test() {
>>>>>>>>         __WhereVal(E) {
>>>>>>>>             Object o = (Object)get();
>>>>>>>>         }
>>>>>>>>     }
>>>>>>>> }
>>>>>>>>
>>>>>>>> Maurizio
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>



More information about the valhalla-dev mailing list