Adopting JEP 303 (Intrinsics for LDC and INVOKEDYNAMIC) into Amber

Remi Forax forax at univ-mlv.fr
Mon Apr 24 21:03:52 UTC 2017


Hi Vicente,
The problem of letting intermediary construction is that you keep link to classes that are present at compile time (to represent intermediary states) but may not be present at runtime.

cheers,
Rémi
 

----- Mail original -----
> De: "Vicente Romero" <vicente.romero at oracle.com>
> À: "Tagir Valeev" <amaembo at gmail.com>, amber-dev at openjdk.java.net
> Envoyé: Lundi 24 Avril 2017 15:28:55
> Objet: Re: Adopting JEP 303 (Intrinsics for LDC and INVOKEDYNAMIC) into Amber

> Hi Tagir,
> 
> On 04/24/2017 12:57 AM, Tagir Valeev wrote:
>> Hello!
>>
>>> Does it work if you get rid of the class literals, and use strings?
>> Yes, if I change code the following way:
>>
>> MethodTypeConstant mtc = MethodTypeConstant.of(ClassConstant.of("V"));
>> MethodHandleConstant mhc = MethodHandleConstant.ofStatic(
>> ClassConstant.of("LTestConst;"), "test", mtc);
>> MethodHandle mh = Intrinsics.ldc(mhc);
>>
>> Then it compiles and runs correctly. Of course, bytecode still contains
>> these constants created explicitly:
>>
>>   0: ldc           #2   // String V
>>   2: invokestatic  #3   // Method j/l/i/Constables$ClassConstant.of
>>   5: iconst_0
>>   6: anewarray     #4   // class j/l/i/Constables$ClassConstant
>>   9: invokestatic  #5   // Method j/l/i/Constables$MethodTypeConstant.of
>> 12: astore_1
>> 13: ldc           #6   // String LTestConst;
>> 15: invokestatic  #3   // Method j/l/i/Constables$ClassConstant.of
>> 18: ldc           #7   // String test
>> 20: aload_1
>> 21: invokestatic  #8   // Method j/l/i/Constables$
>> MethodHandleConstant.ofStatic
>> 24: astore_2
>> 25: ldc           #9   // MethodHandle REF_invokeStatic TestConst.test:()V
>> 27: astore_3
>> 28: aload_3
>> 29: invokevirtual #10  // Method j/l/i/MethodHandle.invokeExact:()V
>> 32: return
>>
>> Of these only bytecodes after offset 25 are actually needed. Though
>> probably optimizing out intermediate constables is too much...
> 
> we decided not to optimize the intermediate constables because we wanted
> to be explicit about the fact that the magic would happen only for ldc()
> or invokedynamic(). Clearing up all the code and reducing it to an ldc
> or indy invocation was considered too magical.
> 
>>
>> With best regards,
>> Tagir Valeev.
> 
> Thanks,
> Vicente
> 
>>
>>
>> On Fri, Apr 21, 2017 at 6:37 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
>>
>>> Does it work if you get rid of the class literals, and use strings?
>>>
>>> On 4/21/2017 1:03 AM, Tagir Valeev wrote:
>>>
>>> Seems that it does not work if I use intermediate variable for
>>> MethodTypeConstant. Consider the following code:
>>>
>>> import java.lang.invoke.*;
>>> import static java.lang.invoke.Constables.*;
>>> import static java.lang.invoke.Intrinsics.*;
>>>
>>> public class TestConst {
>>>      public static void main(String[] args) throws Throwable {
>>>          MethodTypeConstant mtc = MethodTypeConstant.of(void.class);
>>>          MethodHandleConstant mhc = MethodHandleConstant.ofStatic(TestConst.class,
>>> "test", mtc);
>>>          MethodHandle mh = Intrinsics.ldc(mhc);
>>>          mh.invokeExact();
>>>      }
>>>
>>>      static void test() {
>>>          System.out.println("Hello");
>>>      }
>>> }
>>>
>>> It's compiled without errors and ldc intrinsic is generated correctly.
>>> However for non-intrinsified variables class type is not wrapped into
>>> ClassConstant:
>>>
>>>         0: getstatic     #2                  // Field
>>> void.class:Ljava/lang/Class;
>>>         3: iconst_0
>>>         4: anewarray     #3                  // class
>>> java/lang/invoke/Constables$ClassConstant
>>>         7: invokestatic  #4                  // Method
>>> java/lang/invoke/Constables$MethodTypeConstant.of:(Ljava/lan
>>> g/invoke/Constables$ClassConstant;[Ljava/lang/invoke/Constab
>>> les$ClassConstant;)Ljava/lang/invoke/Constables$MethodTypeConstant;
>>>
>>> This, of course, results in verification errors:
>>>
>>> Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
>>> Exception Details:
>>>    Location:
>>>      TestConst.main([Ljava/lang/String;)V @7: invokestatic
>>>    Reason:
>>>      Type 'java/lang/Class' (current frame, stack[0]) is not assignable to
>>> 'java/lang/invoke/Constables$ClassConstant'
>>>    Current Frame:
>>>      bci: @7
>>>      flags: { }
>>>      locals: { '[Ljava/lang/String;' }
>>>      stack: { 'java/lang/Class', '[Ljava/lang/invoke/Constables$ClassConstant;'
>>> }
>>>
>>> Probably it would be easier to declare class Class<T> as implements
>>> Constable<Class<T>> and replace ClassConstant with Constable<Class<?>> in
>>> method signatures where applicable? Or introduce some intermediate
>>> interface?
>>>
>>> With best regards,
>>> Tagir Valeev.
>>>
>>>
>>> On Fri, Apr 21, 2017 at 10:47 AM, Tagir Valeev <amaembo at gmail.com> wrote:
>>>
>>>> Thanks! Works fine for me.
>>>>
>>>> With best regards,
>>>> Tagir Valeev.
>>>>
>>>> On Thu, Apr 20, 2017 at 8:37 PM, Vicente Romero <
>>>> vicente.romero at oracle.com> wrote:
>>>>
>>>>> Hi all,
>>>>>
>>>>> I have just pushed a patch that converts class literals into a poly
>>>>> expression. Meaning that now you can pass a class literal where a
>>>>> ClassConstant is expected. This will simplify the use of the API making the
>>>>> user code less verbose. Taking as an example the test case sent by Tagir,
>>>>> it could be now rewritten as:
>>>>>
>>>>> import java.lang.invoke.*;
>>>>> import java.lang.invoke.Constables.*;
>>>>> import java.lang.reflect.*;
>>>>>
>>>>> public class MH {
>>>>>    private static void test() {
>>>>>      System.out.println("Hello");
>>>>>    }
>>>>>
>>>>>    public static void main(String[] args) throws Throwable {
>>>>>      final MethodHandle handle = Intrinsics.ldc(
>>>>>       MethodHandleConstant.ofStatic(MH.class, "test",
>>>>> MethodTypeConstant.of(void.class)));
>>>>>      handle.invokeExact();
>>>>>    }
>>>>> }
>>>>>
>>>>> Thanks,
>>>>> Vicente
>>>>>
>>>>>
>>>>>
>>>>> On 04/18/2017 11:14 PM, Tagir Valeev wrote:
>>>>>
>>>>> Thank you for the hint! It also seems that ClassConstant.of(MH.class)
>>>>> does not work either and VarHandles are not supported yet. However the
>>>>> following sample finally worked for me:
>>>>>
>>>>>
>>>>> import java.lang.invoke.*;
>>>>> import java.lang.invoke.Constables.*;
>>>>> import java.lang.reflect.*;
>>>>>
>>>>> public class MH {
>>>>>    private static void test() {
>>>>>      System.out.println("Hello");
>>>>>    }
>>>>>
>>>>>    public static void main(String[] args) throws Throwable {
>>>>>      final MethodHandle handle = Intrinsics.ldc(
>>>>>       MethodHandleConstant.ofStatic(ClassConstant.of("LMH;"), "test",
>>>>> MethodTypeConstant.of(ClassConstant.of("V"))));
>>>>>      handle.invokeExact();
>>>>>    }
>>>>> }
>>>>>
>>>>> With best regards,
>>>>> Tagir Valeev.
>>>>>
>>>>>
>>>>> On Tue, Apr 18, 2017 at 9:13 PM, Brian Goetz <brian.goetz at oracle.com>
>>>>> wrote:
>>>>>
>>>>>> The primitive fields (Constables.VOID and friends) are not yet hooked
>>>>>> up; for the time being, replace with ClassConstant.of("V").
>>>>>>
>>>>>>
>>>>>> On 4/18/2017 2:17 AM, Tagir Valeev wrote:
>>>>>>
>>>>>>> Hello!
>>>>>>>
>>>>>>> I tried to play with this, but still no success. Fresh build from
>>>>>>> constant-folding branch. I tried to compile the following files:
>>>>>>>
>>>>>>> // MH.java
>>>>>>>
>>>>>>> import java.lang.invoke.*;
>>>>>>> import java.lang.invoke.Constables.*;
>>>>>>> import java.lang.reflect.*;
>>>>>>>
>>>>>>> public class MH {
>>>>>>>     private static void test() {
>>>>>>>       System.out.println("Hello");
>>>>>>>     }
>>>>>>>
>>>>>>>
>>>>>>>     public static void main(String[] args) throws Throwable {
>>>>>>>       final MethodHandle handle = Intrinsics.ldc(
>>>>>>>        MethodHandleConstant.ofStatic(ClassConstant.of(MH.class),
>>>>>>> "test",
>>>>>>> MethodTypeConstant.of(Constables.VOID)));
>>>>>>>       handle.invokeExact();
>>>>>>>     }
>>>>>>>
>>>>>>> }
>>>>>>>
>>>>>>> // VH.java
>>>>>>> import java.lang.invoke.*;
>>>>>>> import java.lang.invoke.Constables.*;
>>>>>>> import java.lang.reflect.*;
>>>>>>>
>>>>>>> public class VH {
>>>>>>>     private static volatile int counter;
>>>>>>>
>>>>>>>     private static final VarHandle COUNTER = Intrinsics.ldc(
>>>>>>>        VarHandleConstant.ofStaticField(ClassConstant.of(VH.class),
>>>>>>> "counter",
>>>>>>> Constables.INT));
>>>>>>>
>>>>>>>     public static void main(String[] args) {
>>>>>>>       System.out.println(COUNTER.getAndAdd(1));
>>>>>>>       System.out.println(COUNTER.getAndAdd(1));
>>>>>>>     }
>>>>>>> }
>>>>>>>
>>>>>>> Building with "javac -XDdoConstantFold=true MH.java" or "javac
>>>>>>> -XDdoConstantFold=true VH.java",
>>>>>>> javac silently exists without producing .class file or reporting any
>>>>>>> error.
>>>>>>> Tried with -verbose, the output ends like this:
>>>>>>>
>>>>>>> [loading /modules/java.base/java/lang/annotation/RetentionPolicy.clas
>>>>>>> s]
>>>>>>> [loading /modules/java.base/java/lang/annotation/Target.class]
>>>>>>> [loading /modules/java.base/java/lang/annotation/ElementType.class]
>>>>>>> [checking VH]
>>>>>>> [loading /modules/java.base/java/io/Serializable.class]
>>>>>>> [loading /modules/java.base/java/lang/AutoCloseable.class]
>>>>>>> [loading /modules/java.base/java/lang/Class.class]
>>>>>>> [loading /modules/java.base/java/lang/invoke/Constable.class]
>>>>>>> [loading /modules/java.base/java/lang/invoke/Intrinsics.class]
>>>>>>> [total 1484ms]
>>>>>>>
>>>>>>> Without  -XDdoConstantFold=true the class file is produced and dies
>>>>>>> like
>>>>>>>
>>>>>>> Exception in thread "main" java.lang.UnsupportedOperationException: no
>>>>>>> reflective access
>>>>>>> at java.base/java.lang.invoke.Intrinsics.ldc(Intrinsics.java:42)
>>>>>>> at MH.main(MH.java:12)
>>>>>>>
>>>>>>> Which is expected behavior, I guess.
>>>>>>>
>>>>>>> Am I doing something wrong? Could you compile these files on your side?
>>>>>>> Sorry if my tries look lame: I'm very new to this.
>>>>>>>
>>>>>>> With best regards,
>>>>>>> Tagir Valeev.
>>>>>>>
>>>>>>> On Tue, Apr 18, 2017 at 9:07 AM, Vicente Romero <
>>>>>>> vicente.romero at oracle.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>> Support for JEP 303 has been pushed in the amber repo [1, 2] (branch
>>>>>>>> name
>>>>>>>> is 'constant-folding'). The development is mature although there are
>>>>>>>> some
>>>>>>>> fresh areas like using reflection for accessing the API methods.
>>>>>>>> Reflection
>>>>>>>> is needed as the classes defined in the API see [1] are not available
>>>>>>>> in
>>>>>>>> the boot JDK. There is still some ongoing research so some changes to
>>>>>>>> the
>>>>>>>> API and the code are to be expected in the near future,
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Vicente
>>>>>>>>
>>>>>>>>
>>>>>>>> [1] http://hg.openjdk.java.net/amber/amber/jdk/rev/2eeb80b82c9c
>>>>>>>> [2] http://hg.openjdk.java.net/amber/amber/langtools/rev/7be70b52c760
>>>>>>>>
>>>>>>>>
>>>>>>>> On 04/17/2017 04:22 PM, Brian Goetz wrote:
>>>>>>>>
>>>>>>>> JEP 303 (Intrinsics for LDC and INVOKEDYNAMIC) is hereby adopted into
>>>>>>>>> Project Amber.
>>>>>>>>>
>>>>>>>>> A first draft of the API can be found at:
>>>>>>>>>
>>>>>>>>>       http://cr.openjdk.java.net/~briangoetz/JDK-8178320/webrev/
>>>>>>>>>
>>>>>>>>> Prototype implementation coming soon.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>


More information about the amber-dev mailing list