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

Tagir Valeev amaembo at gmail.com
Fri Apr 21 05:31:36 UTC 2017


I also tried to create more sophisticated example, a fancy indy-based
singleton. Seeing that class literals conversion is unstable I don't use
them.
I tried to follow IndyCodeGenerationTest sample. Nevertheless it does not
work for me: it dies the following way:

$ javac -XDdoConstantFold Singleton.java
An exception has occurred in the compiler (10-internal). Please file a bug
against the Java compiler via the Java bug reporting page (
http://bugreport.java.com) after checking the Bug Database (
http://bugs.java.com) for duplicates. Include your program and the
following diagnostic in your report. Thank you.
java.lang.AssertionError: Invalid type of constant pool entry: class
java.lang.invoke.Constables$BootstrapSpecifier
at jdk.compiler/com.sun.tools.javac.jvm.Code.typeForPool(Code.java:928)
at jdk.compiler/com.sun.tools.javac.jvm.Code.emitop1(Code.java:904)
at jdk.compiler/com.sun.tools.javac.jvm.Code.emitLdc(Code.java:391)
at
jdk.compiler/com.sun.tools.javac.jvm.Items$ImmediateItem.ldc(Items.java:575)
at
jdk.compiler/com.sun.tools.javac.jvm.Items$ImmediateItem.load(Items.java:615)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitTypeCast(Gen.java:2190)
at
jdk.compiler/com.sun.tools.javac.tree.JCTree$JCTypeCast.accept(JCTree.java:2012)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:868)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitReturn(Gen.java:1801)
at
jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1540)

The full source code follows (Singleton.java):

import java.util.*;
import java.lang.reflect.*;
import java.lang.invoke.*;
import java.lang.invoke.Constables.*;

public class Singleton {
  static final MethodHandleConstant FACTORY =
    MethodHandleConstant.ofStatic(ClassConstant.of("LSingleton;"),
    "singletonFactory",
       MethodTypeConstant.of(
          ClassConstant.of("Ljava/lang/invoke/CallSite;"),
          ClassConstant.of("Ljava/lang/invoke/MethodHandles$Lookup;"),
          ClassConstant.of("Ljava/lang/String;"),
          ClassConstant.of("Ljava/lang/invoke/MethodType;"),
          ClassConstant.of("Ljava/lang/invoke/MethodHandle;")));

  public static CallSite singletonFactory(
    MethodHandles.Lookup lookup, String name,
    MethodType type, MethodHandle ctor) throws Throwable {
    Object singleton = ctor.invokeExact();
    return new ConstantCallSite(MethodHandles.constant(type.returnType(),
singleton));
  }

  private Singleton() {
    System.out.println("Created!");
  }

  public static Singleton instance() throws Throwable {
    BootstrapSpecifier indyDescr = BootstrapSpecifier.of(
              FACTORY, "singletonFactory",
              MethodTypeConstant.of(ClassConstant.of("LSingleton;")),

MethodHandleConstant.ofConstructor(ClassConstant.of("LSingleton;"),
                 MethodTypeConstant.of(ClassConstant.of("V"))));

    return (Singleton)Intrinsics.invokedynamic(indyDescr);
  }

  public static void main(String[] args) throws Throwable {
    Set<Singleton> set = new HashSet<>();
    for(int i=0; i<100; i++) {
      set.add(instance());
    }
    System.out.println(set.size());
  }
}

I'm not 100% sure whether the code is correct, but the error reporting
surely should be improved for further experiments.

By the way seems that indy intrinsification is not fully optioned out by
-XDdoConstantFold. Without this option javac dies with another exception:

An exception has occurred in the compiler (10-internal). Please file a bug
against the Java compiler via the Java bug reporting page (
http://bugreport.java.com) after checking the Bug Database (
http://bugs.java.com) for duplicates. Include your program and the
following diagnostic in your report. Thank you.
java.lang.NullPointerException
at
jdk.compiler/com.sun.tools.javac.jvm.Gen.invokeInstanceMethod(Gen.java:944)
at
jdk.compiler/com.sun.tools.javac.jvm.Gen.invokeInstanceMethod(Gen.java:933)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.generateIndy(Gen.java:959)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:865)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitTypeCast(Gen.java:2190)
at
jdk.compiler/com.sun.tools.javac.tree.JCTree$JCTypeCast.accept(JCTree.java:2012)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:868)
at jdk.compiler/com.sun.tools.javac.jvm.Gen.visitReturn(Gen.java:1801)


With best regards,
Tagir Valeev.

On Fri, Apr 21, 2017 at 12:03 PM, Tagir Valeev <amaembo at gmail.com> 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/
> lang/invoke/Constables$ClassConstant;[Ljava/lang/invoke/Constables$
> 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