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

Reply via email to