"Model 2" prototype implementation
Rémi Forax
forax at univ-mlv.fr
Fri Aug 7 18:01:34 UTC 2015
Hi Brian,
why do you need the interface Box$any and not use Object and send Box.class as a bootstrap argument to the indy call ?
Rémi
Le 7 août 2015 17:49:31 CEST, Brian Goetz <brian.goetz at oracle.com> a écrit :
>Great question. We're working on a writeup of the translation details;
>
>we announced the prototype before the writeup was ready, because we
>didn't want to keep early adopters from trying it out any further, but
>there's a writeup coming.
>
>Here's a very brief taste (but you'll have to wait for the writeup, or
>use javap on the output of javac, for more). Imagine the function
>
> R : Type -> Class
>
>which maps a compile-time type to a runtime class. In Java 5 generics,
>
>for a class Foo<T>, the R mapping is very simple -- everything is
>erased:
>
>R(Foo<String>) = Foo
>R(Foo<?>) = Foo
>R(Foo) = Foo
>
>In Valhalla, for a class Foo<any T>, the mapping is more complex:
>
>Compatibility demands we adopt the above mappings:
>R(Foo<String>) = Foo
>R(Foo<ref>) = Foo
>R(Foo<raw>) = Foo
>
>And we get some new ones:
>R(Foo<int>) = Foo${0=I} *
>R(Foo<any>) = Foo$any **
>
>*Name mangling is temporary; something better is in the works.
>**Foo$any is a synthetic *interface* generated by javac, which can be
>implemented by Foo<int> and Foo<String> alike (using boxing in the API
>where necessary).
>
>Because Foo$any is an interface, it can't have fields. So we lift the
>fields of Foo to (possibly boxing) accessors on Foo$any (VM help is
>needed for nonpublic members here), and we convert field accesses
>(through receivers of type Foo<any> only!) to invocations of those
>accessors. (Field access through concretely-typed receivers
>(Foo<String> or Foo<int>) are still translated with straight
>getfield/putfield, so the boxing penalty is only paid by wildcard
>users.)
>
>Here's your example:
>
> public static void main(String[] args) {
> Box<int> box = new Box<int>(3);
> Box<any> box_any = box;
> System.out.println(box_any.get());
> System.out.println(box_any.t);
> }
>
>And the bytecode (which works as expected):
>
>public static void main(java.lang.String[]);
> Code:
> 0: new #2 // class "Box${0=I}"
> 3: dup
> 4: iconst_3
> 5: invokespecial #3 // Method
>"Box${0=I}"."<init>":(I)V
> 8: astore_1
> 9: aload_1
> 10: astore_2
> 11: getstatic #4 // Field
>java/lang/System.out:Ljava/io/PrintStream;
> 14: aload_2
> 15: invokedynamic #5, 0 // InvokeDynamic
>#0:get:(LBox$$any;)Ljava/lang/Object;
> 20: invokevirtual #6 // Method
>java/io/PrintStream.println:(Ljava/lang/Object;)V
> 23: getstatic #4 // Field
>java/lang/System.out:Ljava/io/PrintStream;
> 26: aload_2
> 27: invokedynamic #7, 0 // InvokeDynamic
>#1:t$get:(LBox$$any;)Ljava/lang/Object;
> 32: invokevirtual #6 // Method
>java/io/PrintStream.println:(Ljava/lang/Object;)V
> 35: return
>
>BootstrapMethods:
> 0: #26 invokestatic
>java/lang/invoke/VirtualAccess.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
> Method arguments:
> #27 invokeinterface Box$$any.get:()Ljava/lang/Object;
> 1: #26 invokestatic
>java/lang/invoke/VirtualAccess.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
> Method arguments:
> #31 invokeinterface Box$$any.t$get:()Ljava/lang/Object;
>
>The invokedynamic at bci=15 and 27 invoke the get() and t$get() methods
>
>of the Foo$any interface. We use invokedynamic instead of
>invokeinterface because it allows us to do some boxing adaptations more
>
>easily than statically generating yet more bridge methods. (The
>VirtualAccess bootstrap simply does a MethodHandle.asType adaptation of
>
>the provided MH; in the current program, there is no difference in the
>signatures so it's as if we did an invokeinterface of Box$$any.get() or
>
>.t$get() directly.)
>
>
>> I’m wondering how will the implementation work?
>> Specifically, in this example, which assumes a specialized |Box|
>class
>> defined here
>>
><web.archive.org/web/20150801070114/http://cr.openjdk.java.net/~briangoetz/valhalla/specialization.html#erasure-example-a-simple-box-class>:
>>
>> |Box<int> box = new Box<int>(4); Box<any> box_any = box; // what does
>> get() return? and how does it return it?
>> System.out.println(box_any.get()); // even more interesting, how does
>> this work: System.out.println(box_any.t /* assuming the box value is
>> visible */); |
>>
>> How do you translate the method calls and field accesses? Do they
>return
>> boxed values?
>>
>> Thanks,
>> Vlad
>>
>> PS: Shameless advertising — I recently worked on a paper describing
>the
>> pitfalls I’ve encountered in miniboxing <http://scala-miniboxing.org>
>> when using erased views (and specialized views) and how to mitigate
>> them, which has been accepted for PPPJ 2015. In case you’re
>interested,
>> an earlier draft is available here
>> <http://infoscience.epfl.ch/record/208797?ln=en>.
>>
>>
More information about the valhalla-dev
mailing list