Remi, with your suggestion and the workaround the bug (by returning int), here the updated "benchmark". Works, but still much slower than usual reflection.
The new code is under doDynSyntaxSpread() and displayed as "invoke dynamic syntax: spread". Output is at the end. = = = = = = = = = = 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 = 2 * 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 int staticMethod(int i1, int i2) { counter += i1; counter += i2; return 0; } 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(int.class, int.class, int.class)); mhSpread = MethodHandles.spreadArguments(mhNormal, MethodType.methodType(int.class, Object[].class)); } catch (Exception ex) { throw new Error(ex); } } private static CallSite bootstrap(Class<?> declaring, String name, MethodType type) { CallSite cs = new CallSite(); System.out.println(declaring + "." + name + " : " + type); switch (name) { case "nonSpread": cs.setTarget(mhNormal); break; case "spread": cs.setTarget(mhSpread); break; default: throw new IllegalArgumentException(name); } return cs; } private static void doUsual() { if (deoptimizedInt() >= 0) { staticMethod(-1, +2); } } private static void doDynSyntaxUsual() throws Throwable { if (deoptimizedInt() >= 0) { int x; x = (int) InvokeDynamic.nonSpread((int) -1, (int) +2); } } private static void doDynSyntaxSpread() 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; int x; x = (int) InvokeDynamic.spread(CACHED_ARGS_ARRAY); } } private static void doDynApiExactUsual() throws Throwable { if (deoptimizedInt() >= 0) { int x; x = (int) mhNormal.invokeExact((int) -1, (int) +2); } } private static void doDynApiExectSpread() throws Throwable { if (deoptimizedInt() >= 0) { CACHED_ARGS_ARRAY[0] = -1; CACHED_ARGS_ARRAY[1] = 2; // invokeExact and invokeGeneric both equally "fast" int x; x = (int) 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("doing " + INNER_LOOP + " loop iterations " + N_REPEATS + " times...\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 syntax: usual") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynSyntaxUsual(); } } }, new Test("invoke dynamic syntax: spread") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynSyntaxSpread(); } } }, new Test("invoke dynamic api: invokeExact usual") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynApiExactUsual(); } } }, new Test("invoke dynamic api: invokeExact spread") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doDynApiExectSpread(); } } }, new Test("reflection: using Method.invoke(...)") { @Override void run() throws Throwable { for (long i = 0; i < INNER_LOOP; ++i) { doReflect(); } } } }; tests(tt); } } = = = = = = = = = = OUTPUT = = = = = = = = = = doing 2000000 loop iterations 10 times... class javabenchmarks._BenchmarkDyn_onefile.nonSpread : (int,int)int class javabenchmarks._BenchmarkDyn_onefile.spread : (java.lang.Object[])int .........done! usual method invocation 0.07s invoke dynamic syntax: usual 0.09s invoke dynamic syntax: spread 4.79s invoke dynamic api: invokeExact usual 0.52s invoke dynamic api: invokeExact spread 8.15s reflection: using Method.invoke(...) 0.88s _______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev