changeset 14153:fe806038ae74

8153637: MethodHandles.countedLoop/3 initialises loop counter to 1 instead of 0 Reviewed-by: psandoz, redestad
author mhaupt
date Wed, 13 Apr 2016 09:20:22 +0200
parents c11d4a8cc37e
children 502aa22b0e33
files src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java src/java.base/share/classes/java/lang/invoke/MethodHandles.java test/java/lang/invoke/LoopCombinatorTest.java
diffstat 3 files changed, 46 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Apr 13 00:00:39 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Apr 13 09:20:22 2016 +0200
@@ -1754,6 +1754,18 @@
     }
 
     /**
+     * This method is bound as a filter in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle, MethodHandle,
+     * MethodHandle) counting loops} to pass the correct counter value to the body.
+     *
+     * @param counter the loop counter.
+     *
+     * @return the loop counter decremented by 1.
+     */
+    static int decrementCounter(int counter) {
+        return counter - 1;
+    }
+
+    /**
      * This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}.
      *
      * @param it the {@link Iterable} over which the loop iterates.
@@ -1879,7 +1891,8 @@
             MH_iterateNext           = 11,
             MH_tryFinallyExec        = 12,
             MH_tryFinallyVoidExec    = 13,
-            MH_LIMIT                 = 14;
+            MH_decrementCounter      = 14,
+            MH_LIMIT                 = 15;
 
     static MethodHandle getConstantHandle(int idx) {
         MethodHandle handle = HANDLES[idx];
@@ -1949,6 +1962,9 @@
                 case MH_tryFinallyVoidExec:
                     return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "tryFinallyVoidExecutor",
                             MethodType.methodType(void.class, MethodHandle.class, MethodHandle.class, Object[].class));
+                case MH_decrementCounter:
+                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "decrementCounter",
+                            MethodType.methodType(int.class, int.class));
             }
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Apr 13 00:00:39 2016 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Apr 13 09:20:22 2016 +0200
@@ -4322,11 +4322,13 @@
      * <blockquote><pre>{@code
      * MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
      *     MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
-     *     // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int
+     *     // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int,
+     *     // assume MH_decrement is a handle to x-1 of type int
      *     MethodHandle[]
      *         indexVar = {start, MH_increment}, // i = start; i = i+1
      *         loopLimit = {end, null, MH_lessThan, returnVar }, // i<end
-     *         bodyClause = {init, dropArguments(body, 1, int.class)};  // v = body(i, v);
+     *         bodyClause = {init,
+     *                       filterArgument(dropArguments(body, 1, int.class), 0, MH_decrement}; // v = body(i-1, v)
      *     return loop(indexVar, loopLimit, bodyClause);
      * }
      * }</pre></blockquote>
@@ -4351,7 +4353,9 @@
                 0, int.class, int.class);
         MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
         MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
-        MethodHandle[] bodyClause = {init, dropArguments(body, 1, int.class)};
+        MethodHandle[] bodyClause = {init,
+                filterArgument(dropArguments(body, 1, int.class), 0,
+                        MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_decrementCounter))};
         return loop(indexVar, loopLimit, bodyClause);
     }
 
--- a/test/java/lang/invoke/LoopCombinatorTest.java	Wed Apr 13 00:00:39 2016 -0700
+++ b/test/java/lang/invoke/LoopCombinatorTest.java	Wed Apr 13 09:20:22 2016 +0200
@@ -26,6 +26,8 @@
 /* @test
  * @bug 8139885
  * @bug 8150635
+ * @bug 8150957
+ * @bug 8153637
  * @run testng/othervm -ea -esa test.java.lang.invoke.LoopCombinatorTest
  */
 
@@ -302,6 +304,18 @@
     }
 
     @Test
+    public static void testCountedLoopCounterInit() throws Throwable {
+        // int x = 0; for (int i = 0; i < 5; ++i) { x += i; } return x; => 10
+        // (only if counter's first value in body is 0)
+        MethodHandle iter = MethodHandles.constant(int.class, 5);
+        MethodHandle init = MethodHandles.constant(int.class, 0);
+        MethodHandle body = Counted.MH_addCounter;
+        MethodHandle loop = MethodHandles.countedLoop(iter, init, body);
+        assertEquals(Counted.MT_counterInit, loop.type());
+        assertEquals(10, loop.invoke());
+    }
+
+    @Test
     public static void testIterateSum() throws Throwable {
         // Integer[] a = new Integer[]{1,2,3,4,5,6}; int sum = 0; for (int e : a) { sum += e; } return sum; => 21
         MethodHandle loop = MethodHandles.iteratedLoop(Iterate.MH_sumIterator, Iterate.MH_sumInit, Iterate.MH_sumStep);
@@ -667,12 +681,17 @@
             System.out.print("hello");
         }
 
+        static int addCounter(int counter, int x) {
+            return x + counter;
+        }
+
         static final Class<Counted> COUNTED = Counted.class;
 
         static final MethodType MT_start = methodType(String.class, String.class);
         static final MethodType MT_step = methodType(String.class, int.class, String.class, String.class);
         static final MethodType MT_stepUpdateArray = methodType(void.class, int.class, int[].class);
         static final MethodType MT_printHello = methodType(void.class, int.class);
+        static final MethodType MT_addCounter = methodType(int.class, int.class, int.class);
 
         static final MethodHandle MH_13;
         static final MethodHandle MH_m5;
@@ -681,10 +700,12 @@
         static final MethodHandle MH_step;
         static final MethodHandle MH_stepUpdateArray;
         static final MethodHandle MH_printHello;
+        static final MethodHandle MH_addCounter;
 
         static final MethodType MT_counted = methodType(String.class, String.class);
         static final MethodType MT_arrayCounted = methodType(void.class, int[].class);
         static final MethodType MT_countedPrinting = methodType(void.class);
+        static final MethodType MT_counterInit = methodType(int.class);
 
         static {
             try {
@@ -695,6 +716,7 @@
                 MH_step = LOOKUP.findStatic(COUNTED, "step", MT_step);
                 MH_stepUpdateArray = LOOKUP.findStatic(COUNTED, "stepUpdateArray", MT_stepUpdateArray);
                 MH_printHello = LOOKUP.findStatic(COUNTED, "printHello", MT_printHello);
+                MH_addCounter = LOOKUP.findStatic(COUNTED, "addCounter", MT_addCounter);
             } catch (Exception e) {
                 throw new ExceptionInInitializerError(e);
             }