changeset 425:17b551da7237

meth-lazy: adjust for reviewer comments (name bare constants)
author jrose
date Mon, 13 Aug 2012 17:34:45 -0700
parents 38a9d08784f5
children 3f168634278e
files meth.patch
diffstat 1 files changed, 72 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/meth.patch	Sat Aug 11 21:23:05 2012 -0700
+++ b/meth.patch	Mon Aug 13 17:34:45 2012 -0700
@@ -76,7 +76,7 @@
 diff --git a/src/share/classes/java/lang/invoke/Invokers.java b/src/share/classes/java/lang/invoke/Invokers.java
 --- a/src/share/classes/java/lang/invoke/Invokers.java
 +++ b/src/share/classes/java/lang/invoke/Invokers.java
-@@ -74,8 +74,15 @@
+@@ -74,8 +74,18 @@
          MethodHandle invoker = exactInvoker;
          if (invoker != null)  return invoker;
          MethodType mtype = targetType;
@@ -84,17 +84,20 @@
 -        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
 +        MethodType invokerType = mtype.invokerType();
 +        LambdaForm lform;
-+        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY-2) {
++        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
++        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - MTYPE_ARG_APPENDED) {
 +            lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_INVOKER);
 +            invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
 +        } else {
++            // At maximum arity, we cannot afford an extra mtype argument,
++            // so build a fully customized (non-cached) invoker form.
 +            lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
 +            invoker = SimpleMethodHandle.make(invokerType, lform);
 +        }
          assert(checkInvoker(invoker));
          exactInvoker = invoker;
          return invoker;
-@@ -85,9 +92,16 @@
+@@ -85,9 +95,20 @@
          MethodHandle invoker = generalInvoker;
          if (invoker != null)  return invoker;
          MethodType mtype = targetType;
@@ -103,18 +106,22 @@
 -        invoker = BoundMethodHandle.bindSingle(mtype.invokerType(), lform, mtype);
 +        MethodType invokerType = mtype.invokerType();
 +        LambdaForm lform;
-+        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY-3) {
++        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
++        assert(GENERIC_INVOKER_SLOP >= MTYPE_ARG_APPENDED);
++        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY - GENERIC_INVOKER_SLOP) {
 +            prepareForGenericCall(mtype);
 +            lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_INVOKER);
 +            invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype);
 +        } else {
++            // At maximum arity, we cannot afford an extra mtype argument,
++            // so build a fully customized (non-cached) invoker form.
 +            lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
 +            invoker = SimpleMethodHandle.make(invokerType, lform);
 +        }
          assert(checkInvoker(invoker));
          generalInvoker = invoker;
          return invoker;
-@@ -102,6 +116,7 @@
+@@ -102,6 +123,7 @@
      }
  
      static MemberName invokeBasicMethod(MethodType type) {
@@ -122,7 +129,7 @@
          String name = "invokeBasic";
          try {
              //Lookup.findVirtual(MethodHandle.class, name, type);
-@@ -135,9 +150,34 @@
+@@ -135,9 +157,31 @@
      /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) {
          MethodHandle vaInvoker = spreadInvokers[leadingArgCount];
          if (vaInvoker != null)  return vaInvoker;
@@ -131,7 +138,7 @@
 -        vaInvoker = gInvoker.asSpreader(Object[].class, spreadArgCount);
 +        MethodType spreadInvokerType = targetType
 +            .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class);
-+        if (targetType.parameterSlotCount() <= MethodType.MAX_MH_ARITY-1) {
++        if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) {
 +            // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a)
 +            // where ginvoker.invoke(mh, a*) => mh.invoke(a*).
 +            MethodHandle genInvoker = generalInvoker();
@@ -152,14 +159,11 @@
 +            makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount);
 +            vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader);
 +        }
-+        assert(vaInvoker.type().equals(spreadInvokerType.invokerType()))
-+                // [0, (MethodHandle,Object[])Object, (Object[])Object] //@@
-+                : Arrays.asList(leadingArgCount, vaInvoker.type(), spreadInvokerType)//@@
-+                ;
++        assert(vaInvoker.type().equals(spreadInvokerType.invokerType()));
          spreadInvokers[leadingArgCount] = vaInvoker;
          return vaInvoker;
      }
-@@ -171,7 +211,7 @@
+@@ -171,7 +215,7 @@
                      .findStatic(CallSite.class, "uninitializedCallSite",
                                  MethodType.methodType(Empty.class));
              } catch (ReflectiveOperationException ex) {
@@ -168,7 +172,7 @@
              }
          }
          invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType()));
-@@ -185,30 +225,37 @@
+@@ -185,30 +229,39 @@
          return "Invokers"+targetType;
      }
  
@@ -185,7 +189,8 @@
 -        appendixResult[0] = mtype;
 +    static MemberName exactInvokerMethod(MethodType mtype, Object[] appendixResult) {
 +        LambdaForm lform;
-+        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY-1) {
++        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
++        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MTYPE_ARG_APPENDED) {
 +            lform = invokeForm(mtype, false, MethodTypeForm.LF_EX_LINKER);
 +            appendixResult[0] = mtype;
 +        } else {
@@ -201,7 +206,8 @@
 -        appendixResult[0] = mtype;
 +    static MemberName genericInvokerMethod(MethodType mtype, Object[] appendixResult) {
 +        LambdaForm lform;
-+        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY-3) {
++        final int MTYPE_ARG_APPENDED = 1;  // argument count for appended mtype value
++        if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - (MTYPE_ARG_APPENDED + GENERIC_INVOKER_SLOP)) {
 +            lform = invokeForm(mtype, false, MethodTypeForm.LF_GEN_LINKER);
 +            appendixResult[0] = mtype;
 +            prepareForGenericCall(mtype);
@@ -224,7 +230,7 @@
          boolean isLinker, isGeneric;
          String debugName;
          switch (which) {
-@@ -218,27 +265,32 @@
+@@ -218,27 +271,32 @@
          case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true;  debugName = "invoker"; break;
          default: throw new InternalError();
          }
@@ -263,7 +269,7 @@
          if (MTYPE_ARG >= INARG_LIMIT) {
              assert(names[MTYPE_ARG] == null);
              names[MTYPE_ARG] = BoundMethodHandle.getSpeciesData("L").getterName(names[THIS_MH], 0);
-@@ -248,13 +300,21 @@
+@@ -248,31 +306,42 @@
          // Make the final call.  If isGeneric, then prepend the result of type checking.
          MethodType outCallType;
          Object[] outArgs;
@@ -287,7 +293,9 @@
              // mh.invokeGeneric(a*):R =>
              //  let mt=TYPEOF(a*:R), gamh=checkGenericType(mh, mt);
              //    gamh.invokeBasic(mt, mh, a*)
-@@ -263,14 +323,15 @@
+             final int PREPEND_GAMH = 0, PREPEND_MT = 1, PREPEND_COUNT = 2;
++            assert(GENERIC_INVOKER_SLOP == PREPEND_COUNT);
+             outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT + PREPEND_COUNT, Object[].class);
              // prepend arguments:
              System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT);
              outArgs[PREPEND_GAMH] = names[CHECK_TYPE];
@@ -304,8 +312,11 @@
 +            lform = mtype.form().setCachedLambdaForm(which, lform);
          return lform;
      }
++    private static final int GENERIC_INVOKER_SLOP = 2;  // used elsewhere to avoid arity problems
  
-@@ -370,6 +431,7 @@
+     /*non-public*/ static
+     WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) {
+@@ -370,6 +439,7 @@
      // Local constant functions:
      private static final NamedFunction NF_checkExactType;
      private static final NamedFunction NF_checkGenericType;
@@ -313,7 +324,7 @@
      private static final NamedFunction NF_getCallSiteTarget;
      static {
          try {
-@@ -377,6 +439,8 @@
+@@ -377,6 +447,8 @@
                      .getDeclaredMethod("checkExactType", Object.class, Object.class));
              NF_checkGenericType = new NamedFunction(Invokers.class
                      .getDeclaredMethod("checkGenericType", Object.class, Object.class));
@@ -686,16 +697,54 @@
 diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java
 --- a/src/share/classes/java/lang/invoke/MethodType.java
 +++ b/src/share/classes/java/lang/invoke/MethodType.java
-@@ -111,6 +111,9 @@
+@@ -111,6 +111,36 @@
  
      void setForm(MethodTypeForm f) { form = f; }
  
-+    /*non-public*/ static final int MAX_ARITY = 255;  // this is mandated by the JVM spec.
-+    /*non-public*/ static final int MAX_MH_ARITY = MAX_ARITY-1;  // deduct one for mh receiver
++    /** This number, mandated by the JVM spec as 255,
++     *  is the maximum number of <em>slots</em>
++     *  that any Java method can receive in its argument list.
++     *  It limits both JVM signatures and method type objects.
++     *  The longest possible invocation will look like
++     *  {@code staticMethod(arg1, arg2, ..., arg255)} or
++     *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
++     */
++    /*non-public*/ static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.
++
++    /** This number is the maximum arity of a method handle, 254.
++     *  It is derived from the absolute JVM-imposed arity by subtracting one,
++     *  which is the slot occupied by the method handle itself at the
++     *  beginning of the argument list used to invoke the method handle.
++     *  The longest possible invocation will look like
++     *  {@code mh.invoke(arg1, arg2, ..., arg254)}.
++     */
++    // Issue:  Should we allow MH.invokeWithArguments to go to the full 255?
++    /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1;  // deduct one for mh receiver
++
++    /** This number is the maximum arity of a method handle invoker, 253.
++     *  It is derived from the absolute JVM-imposed arity by subtracting two,
++     *  which are the slots occupied by invoke method handle, and the the
++     *  target method handle, which are both at the beginning of the argument
++     *  list used to invoke the target method handle.
++     *  The longest possible invocation will look like
++     *  {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
++     */
++    /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker
 +
      private static void checkRtype(Class<?> rtype) {
          rtype.equals(rtype);  // null check
      }
+@@ -131,7 +161,9 @@
+         return slots;
+     }
+     static void checkSlotCount(int count) {
+-        if ((count & 0xFF) != count)
++        assert((MAX_JVM_ARITY & (MAX_JVM_ARITY+1)) == 0);
++        // MAX_JVM_ARITY must be power of 2 minus 1 for following code trick to work:
++        if ((count & MAX_JVM_ARITY) != count)
+             throw newIllegalArgumentException("bad parameter count "+count);
+     }
+     private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
 diff --git a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
 --- a/src/share/classes/java/lang/invoke/SimpleMethodHandle.java
 +++ b/src/share/classes/java/lang/invoke/SimpleMethodHandle.java