changeset 54956:07dbd5da612f intrinsics-project

ldc the result of XXX.format invocations if all argumens are constants
author vromero
date Wed, 20 Feb 2019 15:38:32 -0500
parents 0996a11ae3e3
children 9159a3d00041
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IntrinsicsVisitor.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/FormatterProcessor.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/HashProcessor.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessor.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/Intrinsics.java
diffstat 6 files changed, 151 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java	Tue Feb 19 21:20:07 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java	Wed Feb 20 15:38:32 2019 -0500
@@ -42,36 +42,36 @@
 public enum TypeTag {
     /** The tag of the basic type `byte'.
      */
-    BYTE(BYTE_CLASS, BYTE_SUPERCLASSES, true),
+    BYTE(BYTE_CLASS, BYTE_SUPERCLASSES, true, byte.class),
 
     /** The tag of the basic type `char'.
      */
-    CHAR(CHAR_CLASS, CHAR_SUPERCLASSES, true),
+    CHAR(CHAR_CLASS, CHAR_SUPERCLASSES, true, char.class),
 
     /** The tag of the basic type `short'.
      */
-    SHORT(SHORT_CLASS, SHORT_SUPERCLASSES, true),
+    SHORT(SHORT_CLASS, SHORT_SUPERCLASSES, true, short.class),
 
     /** The tag of the basic type `long'.
      */
-    LONG(LONG_CLASS, LONG_SUPERCLASSES, true),
+    LONG(LONG_CLASS, LONG_SUPERCLASSES, true, long.class),
 
     /** The tag of the basic type `float'.
      */
-    FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, true),
+    FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, true, float.class),
     /** The tag of the basic type `int'.
      */
-    INT(INT_CLASS, INT_SUPERCLASSES, true),
+    INT(INT_CLASS, INT_SUPERCLASSES, true, int.class),
     /** The tag of the basic type `double'.
      */
-    DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, true),
+    DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, true, double.class),
     /** The tag of the basic type `boolean'.
      */
-    BOOLEAN(0, 0, true),
+    BOOLEAN(0, 0, true, boolean.class),
 
     /** The tag of the type `void'.
      */
-    VOID,
+    VOID(0, 0, false, void.class),
 
     /** The tag of all class and interface types.
      */
@@ -138,15 +138,17 @@
     final int superClasses;
     final int numericClass;
     final boolean isPrimitive;
+    public final Class<?> theClass;
 
     private TypeTag() {
-        this(0, 0, false);
+        this(0, 0, false, null);
     }
 
-    private TypeTag(int numericClass, int superClasses, boolean isPrimitive) {
+    private TypeTag(int numericClass, int superClasses, boolean isPrimitive, Class<?> theClass) {
         this.superClasses = superClasses;
         this.numericClass = numericClass;
         this.isPrimitive = isPrimitive;
+        this.theClass = theClass;
     }
 
     public static class NumericClasses {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IntrinsicsVisitor.java	Tue Feb 19 21:20:07 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IntrinsicsVisitor.java	Wed Feb 20 15:38:32 2019 -0500
@@ -195,6 +195,7 @@
 
             // Compiler env object
             Result result = intrinsics.tryIntrinsify(
+                    tree,
                     owner,
                     methodName,
                     methodTypeDesc,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/FormatterProcessor.java	Tue Feb 19 21:20:07 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/FormatterProcessor.java	Wed Feb 20 15:38:32 2019 -0500
@@ -25,6 +25,13 @@
 
 package com.sun.tools.javac.intrinsics;
 
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.lang.constant.ClassDesc;
@@ -32,9 +39,15 @@
 import java.lang.constant.ConstantDescs;
 import java.lang.constant.DynamicCallSiteDesc;
 import java.lang.constant.MethodTypeDesc;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
 import java.util.Formatter;
 import java.util.Locale;
 
+import static com.sun.tools.javac.code.TypeTag.ARRAY;
+import static com.sun.tools.javac.tree.JCTree.Tag.SELECT;
 import static java.lang.constant.ConstantDescs.CD_CallSite;
 import static java.lang.constant.ConstantDescs.CD_String;
 
@@ -110,7 +123,8 @@
     private static final ClassDesc CD_IntrinsicFactory = ClassDesc.of("java.lang.invoke.IntrinsicFactory");
 
     @Override
-    public Result tryIntrinsify(ClassDesc ownerDesc,
+    public Result tryIntrinsify(JCTree.JCMethodInvocation invocation,
+                                ClassDesc ownerDesc,
                                 String methodName,
                                 MethodTypeDesc methodType,
                                 boolean isStatic,
@@ -121,13 +135,13 @@
         }
 
         boolean hasLocale = CD_Locale.equals(methodType.parameterType(0));
-        int formatArg = hasLocale ? 2 : 1;
+        int formatArgPos = hasLocale ? 2 : 1;
 
         if (CD_String.equals(ownerDesc)) {
-            formatArg = isStatic && hasLocale ? 1 : 0;
+            formatArgPos = isStatic && hasLocale ? 1 : 0;
         }
 
-        ConstantDesc constantFormat = constantArgs[formatArg];
+        ConstantDesc constantFormat = constantArgs[formatArgPos];
 
         if (constantFormat == null) {
             return new Result.None();
@@ -141,9 +155,17 @@
             return new Result.Ldc(((String)constantFormat).replaceAll("%%", "%"));
         }
 
+        boolean allConstants = Arrays.stream(constantArgs).allMatch(c -> c != null);
+        if (allConstants && isStatic && !hasLocale) {
+            String formatted = (String)invokeMethodReflectively(invocation, Arrays.stream(constantArgs).collect(List.collector()));
+            if (formatted != null) {
+                return new Result.Ldc(formatted);
+            }
+        }
+
         String bsmName = getBSMName(ownerDesc, methodName, isStatic, hasLocale);
 
-        MethodTypeDesc methodTypeLessFormat = methodType.dropParameterTypes(formatArg, formatArg + 1);
+        MethodTypeDesc methodTypeLessFormat = methodType.dropParameterTypes(formatArgPos, formatArgPos + 1);
 
         return new Result.Indy(
                 DynamicCallSiteDesc.of(
@@ -155,7 +177,96 @@
                         methodName,
                         methodTypeLessFormat,
                         new ConstantDesc[] { constantFormat }),
-                        intrinsics.dropArg(argClassDescs.length, formatArg)
+                        intrinsics.dropArg(argClassDescs.length, formatArgPos)
         );
     }
- }
+
+    Object invokeMethodReflectively(
+            final JCTree.JCMethodInvocation tree,
+            List<Object> constantArgumentValues) {
+        try {
+            Symbol msym = TreeInfo.symbol(tree.meth);
+            JCTree qualifierTree = (tree.meth.hasTag(SELECT))
+                    ? ((JCTree.JCFieldAccess) tree.meth).selected
+                    : null;
+            String className = msym.owner.type.tsym.flatName().toString();
+            Name methodName = msym.name;
+            Class<?> ownerClass = Class.forName(className, false, null);
+            Type.MethodType mt = msym.type.asMethodType();
+            java.util.List<Class<?>> argumentTypes =
+                    mt.argtypes.stream().map(t -> getClassForType(t)).collect(List.collector());
+            Method theMethod = ownerClass.getDeclaredMethod(methodName.toString(),
+                    argumentTypes.toArray(new Class<?>[argumentTypes.size()]));
+            int modifiers = theMethod.getModifiers();
+            Object[] args = boxArgs(
+                    mt.argtypes,
+                    constantArgumentValues,
+                    tree.varargsElement);
+            return theMethod.invoke(null, args);
+        } catch (ClassNotFoundException |
+                SecurityException |
+                NoSuchMethodException |
+                IllegalAccessException |
+                IllegalArgumentException |
+                InvocationTargetException ex) {
+            return null;
+        }
+    }
+
+    Class<?> getClassForType(Type t) {
+        try {
+            if (t.isPrimitiveOrVoid()) {
+                return t.getTag().theClass;
+            } else {
+                return Class.forName(getFlatName(t), false, null);
+            }
+        } catch (ClassNotFoundException ex) {
+            return null;
+        }
+    }
+
+    String getFlatName(Type t) {
+        String flatName = t.tsym.flatName().toString();
+        if (t.hasTag(ARRAY)) {
+            flatName = "";
+            while (t.hasTag(ARRAY)) {
+                Type.ArrayType at = (Type.ArrayType)t;
+                flatName += "[";
+                t = at.elemtype;
+            }
+            flatName += "L" + t.tsym.flatName().toString() + ';';
+        }
+        return flatName;
+    }
+
+    Object[] boxArgs(List<Type> parameters, List<Object> _args, Type varargsElement) {
+        java.util.List<Object> result = new java.util.ArrayList<>();
+        List<Object> args = _args;
+        if (parameters.isEmpty()) return new Object[0];
+        while (parameters.tail.nonEmpty()) {
+            result.add(args.head);
+            args = args.tail;
+            parameters = parameters.tail;
+        }
+        if (varargsElement != null) {
+            java.util.List<Object> elems = new java.util.ArrayList<>();
+            while (args.nonEmpty()) {
+                elems.add(args.head);
+                args = args.tail;
+            }
+            Class<?> arrayClass = null;
+            try {
+                arrayClass = Class.forName(getFlatName(varargsElement), false, null);
+            } catch (ClassNotFoundException ex) {}
+            Object arr = Array.newInstance(arrayClass, elems.size());
+            for (int i = 0; i < elems.size(); i++) {
+                Array.set(arr, i, elems.get(i));
+            }
+            result.add(arr);
+        } else {
+            if (args.length() != 1) throw new AssertionError(args);
+            result.add(args.head);
+        }
+        return result.toArray();
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/HashProcessor.java	Tue Feb 19 21:20:07 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/HashProcessor.java	Wed Feb 20 15:38:32 2019 -0500
@@ -25,6 +25,8 @@
 
 package com.sun.tools.javac.intrinsics;
 
+import com.sun.tools.javac.tree.JCTree;
+
 import java.lang.constant.ClassDesc;
 import java.lang.constant.ConstantDesc;
 import java.lang.constant.ConstantDescs;
@@ -53,7 +55,8 @@
     private static final ClassDesc CD_IntrinsicFactory = ClassDesc.of("java.lang.invoke.IntrinsicFactory");
 
     @Override
-    public Result tryIntrinsify(ClassDesc ownerDesc,
+    public Result tryIntrinsify(JCTree.JCMethodInvocation invocation,
+                                ClassDesc ownerDesc,
                                 String methodName,
                                 MethodTypeDesc methodType,
                                 boolean isStatic,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessor.java	Tue Feb 19 21:20:07 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessor.java	Wed Feb 20 15:38:32 2019 -0500
@@ -25,6 +25,8 @@
 
 package com.sun.tools.javac.intrinsics;
 
+import com.sun.tools.javac.tree.JCTree;
+
 import java.lang.constant.ClassDesc;
 import java.lang.constant.ConstantDesc;
 import java.lang.constant.DynamicCallSiteDesc;
@@ -116,6 +118,7 @@
     public void register(Intrinsics intrinsics);
 
     /**
+     * @param invocation      the invocation to be intrinsified
      * @param ownerDesc       method owner
      * @param methodName      method name
      * @param methodType      method type descriptor
@@ -124,7 +127,8 @@
      * @param constantArgs    constant value for each argument (includes receiver), null means unknown
      * @return IntrinsicProcessor.Result value
      */
-    public Result tryIntrinsify(ClassDesc ownerDesc,
+    public Result tryIntrinsify(JCTree.JCMethodInvocation invocation,
+                                ClassDesc ownerDesc,
                                 String methodName,
                                 MethodTypeDesc methodType,
                                 boolean isStatic,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/Intrinsics.java	Tue Feb 19 21:20:07 2019 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/Intrinsics.java	Wed Feb 20 15:38:32 2019 -0500
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.intrinsics;
 
+import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Options;
 
@@ -185,6 +186,7 @@
     }
 
     /**
+     * @param invocation      the invocation to be intrinsified
      * @param ownerDesc       method owner
      * @param methodName      method name
      * @param methodType      method type descriptor
@@ -192,16 +194,18 @@
      * @param constantArgs    constant value for each argument (includes receiver), null means unknown
      * @return IntrinsicProcessor.Result value
      */
-    public IntrinsicProcessor.Result tryIntrinsify(ClassDesc ownerDesc,
-                                                          String methodName,
-                                                          MethodTypeDesc methodType,
-                                                          boolean isStatic,
-                                                          ClassDesc[] argClassDescs,
-                                                          ConstantDesc[] constantArgs) {
+    public IntrinsicProcessor.Result tryIntrinsify(JCTree.JCMethodInvocation invocation,
+                                                   ClassDesc ownerDesc,
+                                                   String methodName,
+                                                   MethodTypeDesc methodType,
+                                                   boolean isStatic,
+                                                   ClassDesc[] argClassDescs,
+                                                   ConstantDesc[] constantArgs) {
         EntryKey key = new EntryKey(ownerDesc, methodName, methodType);
         IntrinsicProcessor processor = registry.get(key);
         if (processor != null) {
             return processor.tryIntrinsify(
+                    invocation,
                     ownerDesc,
                     methodName,
                     methodType,