changeset 52752:e8be92b72e89 jep-334

Add Kind::valueOf methods tin DirectMethodHandleDesc
author briangoetz
date Mon, 01 Oct 2018 14:49:31 -0400
parents 0bcf1413c14f
children 9bb1a300931e
files src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java test/jdk/java/lang/constant/MethodHandleDescTest.java
diffstat 2 files changed, 119 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java	Mon Oct 01 12:06:29 2018 -0400
+++ b/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java	Mon Oct 01 14:49:31 2018 -0400
@@ -26,6 +26,10 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandleInfo;
+import java.util.OptionalInt;
+import java.util.stream.Stream;
+
+import jdk.internal.vm.annotation.Stable;
 
 import static java.lang.invoke.MethodHandleInfo.REF_getField;
 import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
@@ -88,7 +92,98 @@
         }
 
         Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
+
+        /**
+         * Find the enumeration member with the given {@code refKind} field.
+         * Behaves as if {@code valueOf(refKind, false)}.  As a special case,
+         * if {@code refKind} is {@code REF_invokeInterface} (9) then the
+         * {@code isInterface} field will be true.
+         *
+         * @param refKind refKind of desired member
+         * @return the matching enumeration member
+         * @throws IllegalArgumentException if there is no such member
+         */
+        public static Kind valueOf(int refKind) {
+            return valueOf(refKind, false);
+        }
+
+        /**
+         * Find the enumeration member with the given {@code refKind} and
+         * {@code isInterface} fields. If {@code isInterface} is true and there
+         * is no such enumeration member, return the member, if any, with the
+         * same {@code refKind} and a false {@code isInterface} field. If
+         * {@code isInterface} is true but there is no such enumeration member,
+         * then the result of {@code valueOf(refKind, false)} is returned.  As
+         * a special case, if {@code refKind} is {@code REF_invokeVirtual} (5) and
+         * {@code isInterface} is true, then the result of
+         * {@code valueOf(REF_invokeInterface, false)} is returned, and if
+         * {@code isInterface} is false and {@code refKind} is {@code REF_invokeInterface},
+         * {@code INTERFACE_VIRTUAL} is returned.
+         *
+         * @param refKind refKind of desired member
+         * @param isInterface whether desired member is for interface methods
+         * @return the matching enumeration member
+         * @throws IllegalArgumentException if there is no such member
+         */
+        public static Kind valueOf(int refKind, boolean isInterface) {
+            int i = tableIndex(refKind, isInterface);
+            if (i >= 0 && i < TABLE.length) {
+                Kind kind = TABLE[i];
+                if (kind.refKind == refKind && kind.isInterface == isInterface) {
+                    return kind;
+                }
+            }
+            if (isInterface)
+                return valueOf(refKind);
+            else if (refKind == REF_invokeInterface)
+                return INTERFACE_VIRTUAL;
+            else
+                throw new IllegalArgumentException(String.format("refKind=%d", refKind));
+        }
+
+        private static int tableIndex(int refKind, boolean isInterface) {
+            if (refKind < 0)  return refKind;
+            return (refKind * 2) + (isInterface ? 1 : 0);
+        }
+
+        private static final @Stable Kind[] TABLE;
+
+        static {
+            // Pack the static table.
+            int max = 0;
+            for (Kind k : values())
+                max = Math.max(max, tableIndex(k.refKind, k.isInterface));
+
+            TABLE = new Kind[max+1];
+            for (Kind kind : values()) {
+                int i = tableIndex(kind.refKind, kind.isInterface);
+                if (i >= TABLE.length || TABLE[i] != null)
+                    throw new AssertionError("TABLE entry for " + kind);
+                TABLE[i] = kind;
+            }
+
+            // Pack in some aliases also.
+            int ii = tableIndex(REF_invokeInterface, false);
+            if (TABLE[ii] != null)
+                throw new AssertionError("TABLE entry for (invokeInterface, false) used by " + TABLE[ii]);
+            TABLE[ii] = INTERFACE_VIRTUAL;
+
+            for (Kind kind : values()) {
+                if (!kind.isInterface) {
+                    // Add extra cache entry to alias the isInterface case.
+                    // For example, (REF_getStatic, X) will produce STATIC_GETTER
+                    // for either truth value of X.
+                    int i = tableIndex(kind.refKind, true);
+                    if (TABLE[i] == null) {
+                        // There is not a specific Kind for interfaces
+                        if (kind == VIRTUAL)  kind = INTERFACE_VIRTUAL;
+                        if (TABLE[i] == null)  TABLE[i] = kind;
+                    }
+                }
+            }
+        }
     }
+
     /**
      * Return the {@code kind} of the method handle described by this nominal
      * descriptor.
--- a/test/jdk/java/lang/constant/MethodHandleDescTest.java	Mon Oct 01 12:06:29 2018 -0400
+++ b/test/jdk/java/lang/constant/MethodHandleDescTest.java	Mon Oct 01 14:49:31 2018 -0400
@@ -41,6 +41,7 @@
 
 import org.testng.annotations.Test;
 
+import static java.lang.constant.DirectMethodHandleDesc.*;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.GETTER;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.SETTER;
 import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC_GETTER;
@@ -108,19 +109,19 @@
     }
 
     public void testSimpleMHs() throws ReflectiveOperationException {
-        testMethodHandleRef(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.VIRTUAL, CR_String, "isEmpty", "()Z"),
+        testMethodHandleRef(MethodHandleDesc.of(Kind.VIRTUAL, CR_String, "isEmpty", "()Z"),
                             LOOKUP.findVirtual(String.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)));
-        testMethodHandleRef(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, CR_String, "format", CR_String, CR_String, CR_Object.arrayType()),
+        testMethodHandleRef(MethodHandleDesc.of(Kind.STATIC, CR_String, "format", CR_String, CR_String, CR_Object.arrayType()),
                             LOOKUP.findStatic(String.class, "format", MethodType.methodType(String.class, String.class, Object[].class)));
-        testMethodHandleRef(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CR_List, "isEmpty", "()Z"),
+        testMethodHandleRef(MethodHandleDesc.of(Kind.INTERFACE_VIRTUAL, CR_List, "isEmpty", "()Z"),
                             LOOKUP.findVirtual(List.class, "isEmpty", MethodType.fromMethodDescriptorString("()Z", null)));
-        testMethodHandleRef(MethodHandleDesc.of(DirectMethodHandleDesc.Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", CR_void),
+        testMethodHandleRef(MethodHandleDesc.of(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", CR_void),
                             LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class)));
         testMethodHandleRef(MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList")),
                             LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class)));
         // bad constructor non void return type
         try {
-            MethodHandleDesc.of(DirectMethodHandleDesc.Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", CR_int);
+            MethodHandleDesc.of(Kind.CONSTRUCTOR, ClassDesc.of("java.util.ArrayList"), "<init>", CR_int);
             fail("should have failed: non void return type for constructor");
         } catch (IllegalArgumentException ex) {
             // good
@@ -128,7 +129,7 @@
     }
 
     public void testAsType() throws Throwable {
-        MethodHandleDesc mhr = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, ClassDesc.of("java.lang.Integer"), "valueOf",
+        MethodHandleDesc mhr = MethodHandleDesc.of(Kind.STATIC, ClassDesc.of("java.lang.Integer"), "valueOf",
                                                    MethodTypeDesc.of(CR_Integer, CR_int));
         MethodHandleDesc takesInteger = mhr.asType(MethodTypeDesc.of(CR_Integer, CR_Integer));
         testMethodHandleRef(takesInteger);
@@ -160,17 +161,17 @@
     }
 
     public void testMethodHandleRef() throws Throwable {
-        MethodHandleDesc ctorRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.CONSTRUCTOR, testClass, "<ignored!>", CR_void);
-        MethodHandleDesc staticMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, testClass, "sm", "(I)I");
-        MethodHandleDesc staticIMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, testInterface, "sm", "(I)I");
-        MethodHandleDesc instanceMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.VIRTUAL, testClass, "m", "(I)I");
-        MethodHandleDesc instanceIMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, testInterface, "m", "(I)I");
-        MethodHandleDesc superMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.SPECIAL, testSuperclass, "m", "(I)I");
-        MethodHandleDesc superIMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, testInterface, "m", "(I)I");
-        MethodHandleDesc privateMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.SPECIAL, testClass, "pm", "(I)I");
-        MethodHandleDesc privateIMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, testInterface, "pm", "(I)I");
-        MethodHandleDesc privateStaticMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.STATIC, testClass, "psm", "(I)I");
-        MethodHandleDesc privateStaticIMethodRef = MethodHandleDesc.of(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, testInterface, "psm", "(I)I");
+        MethodHandleDesc ctorRef = MethodHandleDesc.of(Kind.CONSTRUCTOR, testClass, "<ignored!>", CR_void);
+        MethodHandleDesc staticMethodRef = MethodHandleDesc.of(Kind.STATIC, testClass, "sm", "(I)I");
+        MethodHandleDesc staticIMethodRef = MethodHandleDesc.of(Kind.INTERFACE_STATIC, testInterface, "sm", "(I)I");
+        MethodHandleDesc instanceMethodRef = MethodHandleDesc.of(Kind.VIRTUAL, testClass, "m", "(I)I");
+        MethodHandleDesc instanceIMethodRef = MethodHandleDesc.of(Kind.INTERFACE_VIRTUAL, testInterface, "m", "(I)I");
+        MethodHandleDesc superMethodRef = MethodHandleDesc.of(Kind.SPECIAL, testSuperclass, "m", "(I)I");
+        MethodHandleDesc superIMethodRef = MethodHandleDesc.of(Kind.INTERFACE_SPECIAL, testInterface, "m", "(I)I");
+        MethodHandleDesc privateMethodRef = MethodHandleDesc.of(Kind.SPECIAL, testClass, "pm", "(I)I");
+        MethodHandleDesc privateIMethodRef = MethodHandleDesc.of(Kind.INTERFACE_SPECIAL, testInterface, "pm", "(I)I");
+        MethodHandleDesc privateStaticMethodRef = MethodHandleDesc.of(Kind.STATIC, testClass, "psm", "(I)I");
+        MethodHandleDesc privateStaticIMethodRef = MethodHandleDesc.of(Kind.INTERFACE_STATIC, testInterface, "psm", "(I)I");
 
         for (MethodHandleDesc r : List.of(ctorRef, staticMethodRef, staticIMethodRef, instanceMethodRef, instanceIMethodRef))
             testMethodHandleRef(r);
@@ -292,4 +293,10 @@
 
         assertTrue(tested > 0);
     }
+
+    public void testKind() {
+        for (Kind k : Kind.values()) {
+            assertEquals(Kind.valueOf(k.refKind, k.isInterface), k);
+        }
+    }
 }