Skip to content

Instantly share code, notes, and snippets.

@hoat4
Last active January 14, 2017 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hoat4/b459938cf7ae93e64bba3208c69af567 to your computer and use it in GitHub Desktop.
Save hoat4/b459938cf7ae93e64bba3208c69af567 to your computer and use it in GitHub Desktop.
--- jdk_MethodHandle.java 2017-01-14 12:15:24.000000000 +0100
+++ "src\\java\\lang\\invoke\\MethodHandle.java" 2017-01-14 17:09:49.224884600 +0100
@@ -29,6 +29,7 @@
import java.util.*;
import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodType.methodType;
/**
* A method handle is a typed, directly executable reference to an underlying method,
@@ -623,10 +624,68 @@
* @see MethodHandles#spreadInvoker
*/
public Object invokeWithArguments(Object... arguments) throws Throwable {
- MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
- return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
+ if(spreaderCache == null)
+ return setupSpreader(arguments);
+ return spreaderCache.invokeBasic(this, arguments);
}
-
+
+ private @Stable MethodHandle spreaderCache;
+
+ private Object setupSpreader(Object... arguments) throws Throwable {
+ MethodHandle mh;
+
+ if (isVarargsCollector()) {
+ mh = VarargsSupport.MH_invokeVarargs.bindTo(
+ new VarargsSupport(arguments.length+5));
+ } else {
+ // fast-path for fixed-arity method handles
+ MethodType invocationType = MethodType.genericMethodType(type.parameterCount());
+ mh = invocationType.invokers().spreadInvoker(0);
+ }
+
+ spreaderCache = mh;
+ return mh.invokeExact(this, arguments);
+ }
+
+ // a cache for spreadInvokers, keyed by the argument count
+ private static class VarargsSupport {
+
+ public static final MethodHandle MH_invokeVarargs;
+
+ static {
+ try {
+ MH_invokeVarargs = MethodHandles.Lookup.IMPL_LOOKUP.
+ findVirtual(VarargsSupport.class, "invokeVarargs",
+ methodType(Object.class, MethodHandle.class, Object[].class));
+ } catch (Exception ex) {
+ throw new InternalError(ex);
+ }
+ }
+
+ private MethodHandle[] spreaders;
+
+ public VarargsSupport(int initialCapacity) {
+ spreaders = new MethodHandle[initialCapacity];
+ }
+
+ private Object invokeVarargs(MethodHandle mh, Object... arguments)
+ throws Throwable {
+ int n = arguments.length;
+ if (n >= spreaders.length) {
+ MethodHandle[] bigger = new MethodHandle[spreaders.length*2];
+ System.arraycopy(spreaders, 0, bigger, 0, spreaders.length);
+ this.spreaders = bigger;
+ }
+
+ MethodHandle spreadInvoker = spreaders[n];
+ if(spreadInvoker == null) {
+ MethodType invocationType = MethodType.genericMethodType(n);
+ spreadInvoker = spreaders[n] = invocationType.invokers().spreadInvoker(0);
+ }
+ return spreadInvoker.invokeExact(mh, arguments);
+ }
+ }
+
/**
* Performs a variable arity invocation, passing the arguments in the given array
* to the method handle, as if via an inexact {@link #invoke invoke} from a call site
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment