"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