Ok, I extended my "benchmark" to support a method handle with spread args, and this part slower than everything else :(
Note: I use Object[] for spread arguments, because in my real-world scenario, as mentioned before, I would need any possible method signature to work. Sadly, I still couldn't figure out, what John meant with "calling Lookup.findVirtual on MethodHandle.invokeExact", and I wonder if it would speed things up. = = = = = = = = = = CODE = = = = = = = = = = import java.lang.reflect.*; import java.text.*; import java.dyn.*; /* * CAN ONLY BE COMPILED AND RAN OUTSIDE NETBEANS */ public class _BenchmarkDyn_onefile { static abstract class Test { final String name; Test(String name) { this.name = name; } abstract void run() throws Throwable; } private final static int N_REPEATS = 10; private final static long INNER_LOOP = 5 * 1000 * 1000; private static long counter = 0; private final static Object[] CACHED_ARGS_ARRAY = new Object[2]; private final static Method method; private final static MethodHandle mhNormal; private final static MethodHandle mhSpread; private volatile static int DEOPTIMIZED_INT = System.getProperties().size(); public static void staticMethod(int i1, int i2) { counter += i1; counter += i2; } private static int deoptimizedInt() { return DEOPTIMIZED_INT; } static { try { method = _BenchmarkDyn_onefile.class.getMethod( "staticMethod", int.class, int.class); Linkage.registerBootstrapMethod("bootstrap"); mhNormal = MethodHandles.lookup().findStatic( _BenchmarkDyn_onefile.class, "staticMethod", MethodType.methodType(void.class, int.class, int.class)); mhSpread = MethodHandles.spreadArguments(mhNormal, MethodType.methodType(void.class, Object[].class)); } catch (Exception ex) { throw new Error(ex); } } private static CallSite bootstrap(Class<?> declaring, String name, MethodType type) { System.out.println(declaring + "." + name + " : " + type); CallSite cs = new CallSite(); cs.setTarget(mhNormal); return cs; } private static void doUsual() { if (deoptimizedInt() >= 0) { staticMethod(-1, +2); } } private static void doDynSyntax() throws Throwable { if (deoptimizedInt() >= 0) { InvokeDynamic.anyName((int) -1, (int) +2); } } private static void doDynExact() throws Throwable { if (deoptimizedInt() >= 0) { mhNormal.invokeExact((int) -1, (int) +2); } } private static void doDynVarargs() throws Throwable { if (deoptimizedInt() >= 0) { // bug: when using on a M.H. without args, null is allowed for invokeVarargs, but fails CACHED_ARGS_ARRAY[0] = -1; CACHED_ARGS_ARRAY[1] = 2; mhNormal.invokeVarargs(CACHED_ARGS_ARRAY); } } private static void doDynSpread() throws Throwable { if (deoptimizedInt() >= 0) { CACHED_ARGS_ARRAY[0] = -1; CACHED_ARGS_ARRAY[1] = 2; // invokeExact and invokeGeneric both equally "fast" mhSpread.invokeExact(CACHED_ARGS_ARRAY); } } private static void doReflect() throws Throwable { if (deoptimizedInt() >= 0) { CACHED_ARGS_ARRAY[0] = -1; CACHED_ARGS_ARRAY[1] = 2; method.invoke(null, CACHED_ARGS_ARRAY); } } private static void tests(Test[] tt) { DecimalFormat format = new DecimalFormat("#0.00"); System.out.println("wait...\n"); double[] times = new double[tt.length]; for (int t = 0; t < N_REPEATS; ++t) { for (int i = 0; i < tt.length; ++i) { times[i] += test(tt[i]); } System.out.print("."); System.out.flush(); } System.out.println("done!\n"); for (int i = 0; i < tt.length; ++i) { System.out.println(tt[i].name + "\n\t" + format.format(times[i]) + "s"); } } private static double test(Test t) { counter = 0; long start = System.currentTimeMillis(); try { t.run(); } catch (Throwable thr) { throw new Error(thr); } long end = System.currentTimeMillis(); if (counter != INNER_LOOP) { throw new AssertionError("counter != " + INNER_LOOP); } return (end - start) / 1000.0; } public static void main(String... args) { Test[] tt = new Test[]{ new Test("usual method invocation") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doUsual(); } } }, new Test("invoke dynamic: using InvokeDynamic.anyName") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynSyntax(); } } }, new Test("invoke dynamic: using invokeExact with real args") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynExact(); } } }, new Test("invoke dynamic: using invokeVarargs") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynVarargs(); } } }, new Test("invoke dynamic: using invokeExact with spread args array") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynSpread(); } } }, new Test("reflection: using Method.invoke(...)") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doReflect(); } } } }; tests(tt); } } = = = = = = = = = = OUTPUT = = = = = = = = = = usual method invocation 0.10s invoke dynamic: using InvokeDynamic.anyName 0.12s invoke dynamic: using invokeExact with real args 0.79s invoke dynamic: using invokeVarargs 8.72s invoke dynamic: using invokeExact with spread args array 15.20s reflection: using Method.invoke(...) 0.82s _______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev