Last active
January 14, 2017 16:08
-
-
Save hoat4/b459938cf7ae93e64bba3208c69af567 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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