src/java.base/share/classes/java/lang/invoke/MethodHandles.java
changeset 52486 6f5948597697
parent 52427 3c6aa484536c
child 53018 8bf9268df0e2
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Sat Nov 10 20:47:28 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Sun Nov 11 21:24:46 2018 +0100
@@ -3864,18 +3864,63 @@
      */
     public static
     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
+        // In method types arguments start at index 0, while the LF
+        // editor have the MH receiver at position 0 - adjust appropriately.
+        final int MH_RECEIVER_OFFSET = 1;
         filterArgumentsCheckArity(target, pos, filters);
         MethodHandle adapter = target;
+
+        // keep track of currently matched filters, as to optimize repeated filters
+        int index = 0;
+        int[] positions = new int[filters.length];
+        MethodHandle filter = null;
+
         // process filters in reverse order so that the invocation of
         // the resulting adapter will invoke the filters in left-to-right order
         for (int i = filters.length - 1; i >= 0; --i) {
-            MethodHandle filter = filters[i];
-            if (filter == null)  continue;  // ignore null elements of filters
-            adapter = filterArgument(adapter, pos + i, filter);
+            MethodHandle newFilter = filters[i];
+            if (newFilter == null) continue;  // ignore null elements of filters
+
+            // flush changes on update
+            if (filter != newFilter) {
+                if (filter != null) {
+                    if (index > 1) {
+                        adapter = filterRepeatedArgument(adapter, filter, Arrays.copyOf(positions, index));
+                    } else {
+                        adapter = filterArgument(adapter, positions[0] - 1, filter);
+                    }
+                }
+                filter = newFilter;
+                index = 0;
+            }
+
+            filterArgumentChecks(target, pos + i, newFilter);
+            positions[index++] = pos + i + MH_RECEIVER_OFFSET;
+        }
+        if (index > 1) {
+            adapter = filterRepeatedArgument(adapter, filter, Arrays.copyOf(positions, index));
+        } else if (index == 1) {
+            adapter = filterArgument(adapter, positions[0] - 1, filter);
         }
         return adapter;
     }
 
+    private static MethodHandle filterRepeatedArgument(MethodHandle adapter, MethodHandle filter, int[] positions) {
+        MethodType targetType = adapter.type();
+        MethodType filterType = filter.type();
+        BoundMethodHandle result = adapter.rebind();
+        Class<?> newParamType = filterType.parameterType(0);
+
+        Class<?>[] ptypes = targetType.ptypes().clone();
+        for (int pos : positions) {
+            ptypes[pos - 1] = newParamType;
+        }
+        MethodType newType = MethodType.makeImpl(targetType.rtype(), ptypes, true);
+
+        LambdaForm lform = result.editor().filterRepeatedArgumentForm(BasicType.basicType(newParamType), positions);
+        return result.copyWithExtendL(newType, lform, filter);
+    }
+
     /*non-public*/ static
     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
         filterArgumentChecks(target, pos, filter);