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