jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 38376 08549412f0dc
parent 37674 763f704393cf
child 38422 638589997770
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon May 16 11:42:31 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed May 18 10:42:29 2016 +0200
@@ -66,25 +66,28 @@
 
     /// Factory methods to create method handles:
 
-    static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
-        if (arrayClass == Object[].class)
-            return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER);
+    static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, ArrayAccess access) {
+        if (arrayClass == Object[].class) {
+            return ArrayAccess.objectAccessor(access);
+        }
         if (!arrayClass.isArray())
             throw newIllegalArgumentException("not an array: "+arrayClass);
         MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass);
-        int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX);
+        int cacheIndex = ArrayAccess.cacheIndex(access);
         MethodHandle mh = cache[cacheIndex];
         if (mh != null)  return mh;
-        mh = ArrayAccessor.getAccessor(arrayClass, isSetter);
-        MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter);
+        mh = ArrayAccessor.getAccessor(arrayClass, access);
+        MethodType correctType = ArrayAccessor.correctType(arrayClass, access);
         if (mh.type() != correctType) {
             assert(mh.type().parameterType(0) == Object[].class);
-            assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class);
-            assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType());
+            /* if access == SET */ assert(access != ArrayAccess.SET || mh.type().parameterType(2) == Object.class);
+            /* if access == GET */ assert(access != ArrayAccess.GET ||
+                    (mh.type().returnType() == Object.class &&
+                     correctType.parameterType(0).getComponentType() == correctType.returnType()));
             // safe to view non-strictly, because element type follows from array type
             mh = mh.viewAsType(correctType, false);
         }
-        mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD));
+        mh = makeIntrinsic(mh, ArrayAccess.intrinsic(access));
         // Atomically update accessor cache.
         synchronized(cache) {
             if (cache[cacheIndex] == null) {
@@ -97,9 +100,52 @@
         return mh;
     }
 
+    enum ArrayAccess {
+        GET, SET, LENGTH;
+
+        // As ArrayAccess and ArrayAccessor have a circular dependency, the ArrayAccess properties cannot be stored in
+        // final fields.
+
+        static String opName(ArrayAccess a) {
+            switch (a) {
+                case GET: return "getElement";
+                case SET: return "setElement";
+                case LENGTH: return "length";
+            }
+            throw new AssertionError();
+        }
+
+        static MethodHandle objectAccessor(ArrayAccess a) {
+            switch (a) {
+                case GET: return ArrayAccessor.OBJECT_ARRAY_GETTER;
+                case SET: return ArrayAccessor.OBJECT_ARRAY_SETTER;
+                case LENGTH: return ArrayAccessor.OBJECT_ARRAY_LENGTH;
+            }
+            throw new AssertionError();
+        }
+
+        static int cacheIndex(ArrayAccess a) {
+            switch (a) {
+                case GET: return ArrayAccessor.GETTER_INDEX;
+                case SET: return ArrayAccessor.SETTER_INDEX;
+                case LENGTH: return ArrayAccessor.LENGTH_INDEX;
+            }
+            throw new AssertionError();
+        }
+
+        static Intrinsic intrinsic(ArrayAccess a) {
+            switch (a) {
+                case GET: return Intrinsic.ARRAY_LOAD;
+                case SET: return Intrinsic.ARRAY_STORE;
+                case LENGTH: return Intrinsic.ARRAY_LENGTH;
+            }
+            throw new AssertionError();
+        }
+    }
+
     static final class ArrayAccessor {
-        /// Support for array element access
-        static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2;
+        /// Support for array element and length access
+        static final int GETTER_INDEX = 0, SETTER_INDEX = 1, LENGTH_INDEX = 2, INDEX_LIMIT = 3;
         static final ClassValue<MethodHandle[]> TYPED_ACCESSORS
                 = new ClassValue<MethodHandle[]>() {
                     @Override
@@ -107,14 +153,16 @@
                         return new MethodHandle[INDEX_LIMIT];
                     }
                 };
-        static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER;
+        static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER, OBJECT_ARRAY_LENGTH;
         static {
             MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
-            cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD);
-            cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true),  Intrinsic.ARRAY_STORE);
+            cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, ArrayAccess.GET),    Intrinsic.ARRAY_LOAD);
+            cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, ArrayAccess.SET),    Intrinsic.ARRAY_STORE);
+            cache[LENGTH_INDEX] = OBJECT_ARRAY_LENGTH = makeIntrinsic(getAccessor(Object[].class, ArrayAccess.LENGTH), Intrinsic.ARRAY_LENGTH);
 
             assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName()));
             assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName()));
+            assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_LENGTH.internalMemberName()));
         }
 
         static int     getElementI(int[]     a, int i)            { return              a[i]; }
@@ -137,31 +185,47 @@
         static void    setElementC(char[]    a, int i, char    x) {              a[i] = x; }
         static void    setElementL(Object[]  a, int i, Object  x) {              a[i] = x; }
 
-        static String name(Class<?> arrayClass, boolean isSetter) {
+        static int     lengthI(int[]     a)                       { return a.length; }
+        static int     lengthJ(long[]    a)                       { return a.length; }
+        static int     lengthF(float[]   a)                       { return a.length; }
+        static int     lengthD(double[]  a)                       { return a.length; }
+        static int     lengthZ(boolean[] a)                       { return a.length; }
+        static int     lengthB(byte[]    a)                       { return a.length; }
+        static int     lengthS(short[]   a)                       { return a.length; }
+        static int     lengthC(char[]    a)                       { return a.length; }
+        static int     lengthL(Object[]  a)                       { return a.length; }
+
+        static String name(Class<?> arrayClass, ArrayAccess access) {
             Class<?> elemClass = arrayClass.getComponentType();
             if (elemClass == null)  throw newIllegalArgumentException("not an array", arrayClass);
-            return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
+            return ArrayAccess.opName(access) + Wrapper.basicTypeChar(elemClass);
         }
-        static MethodType type(Class<?> arrayClass, boolean isSetter) {
+        static MethodType type(Class<?> arrayClass, ArrayAccess access) {
             Class<?> elemClass = arrayClass.getComponentType();
             Class<?> arrayArgClass = arrayClass;
             if (!elemClass.isPrimitive()) {
                 arrayArgClass = Object[].class;
                 elemClass = Object.class;
             }
-            return !isSetter ?
-                    MethodType.methodType(elemClass,  arrayArgClass, int.class) :
-                    MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
+            switch (access) {
+                case GET:    return MethodType.methodType(elemClass,  arrayArgClass, int.class);
+                case SET:    return MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
+                case LENGTH: return MethodType.methodType(int.class,  arrayArgClass);
+            }
+            throw new IllegalStateException("should not reach here");
         }
-        static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
+        static MethodType correctType(Class<?> arrayClass, ArrayAccess access) {
             Class<?> elemClass = arrayClass.getComponentType();
-            return !isSetter ?
-                    MethodType.methodType(elemClass,  arrayClass, int.class) :
-                    MethodType.methodType(void.class, arrayClass, int.class, elemClass);
+            switch (access) {
+                case GET:    return MethodType.methodType(elemClass,  arrayClass, int.class);
+                case SET:    return MethodType.methodType(void.class, arrayClass, int.class, elemClass);
+                case LENGTH: return MethodType.methodType(int.class,  arrayClass);
+            }
+            throw new IllegalStateException("should not reach here");
         }
-        static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
-            String     name = name(arrayClass, isSetter);
-            MethodType type = type(arrayClass, isSetter);
+        static MethodHandle getAccessor(Class<?> arrayClass, ArrayAccess access) {
+            String     name = name(arrayClass, access);
+            MethodType type = type(arrayClass, access);
             try {
                 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
             } catch (ReflectiveOperationException ex) {
@@ -1282,6 +1346,7 @@
         NEW_ARRAY,
         ARRAY_LOAD,
         ARRAY_STORE,
+        ARRAY_LENGTH,
         IDENTITY,
         ZERO,
         NONE // no intrinsic associated