experiences with prototype

Peter Levart peter.levart at gmail.com
Sun Feb 8 10:27:42 UTC 2015


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