Few questions about invokeDynamic

assembling signals assembling.signals at yandex.ru
Sun Nov 7 09:48:35 PST 2010


07.11.10, 14:58, "Rémi Forax" <forax at univ-mlv.fr>:

>  Works with javac. Do you use it ?

Hm, strange, I thought Netbeans would use the usual javac, but now I guess it uses
some API calls to compile files. Because using javac from command line works indeed!

>  Why do you want to call a method with a signature which is unknown
>  prior runtime ?
>  You want to write an interpreter ?

Something like that ;)

>  In that case, you can generate bytecode at runtime ane becuase you do that
>  at runtime you know at least the number of parameter.

Well, personally I, can't generate bytecode at runtime ;)
Was I be able to do this, I wouldn't experiment with invokedynamic in first place ;)

Can you please comment on invokeVarargs' performance?
An other benchmark (now rewritten to be copy-and-past-able here) shows even
less performance than Method.invoke! (Output is at the end)

Here is the code (in one file):

= = = = = = = = = =
CODE
= = = = = = = = = =

import java.lang.reflect.*;
import java.text.*;
import java.dyn.*;

public class _BenchmarkDyn {

	static abstract class Test {

		final String name;

		Test(String name) {
			this.name = name;
		}

		abstract void run()
				throws Throwable;

	}

	final static int N_REPEATS = 10;
	final static long INNER_LOOP = 5 * 1000 * 1000;
	private static long counter = 0;
	private final static Object[] CACHED_EMPTY_ARGS_ARRAY = new Object[]{};
	private final static Method method;
	private final static MethodHandle methodHandle;
	private volatile static int DEOPTIMIZED_INT = System.getProperties().size();

	public static void staticMethod() {
		++counter;
	}

	private static int deoptimizedInt() {
		return DEOPTIMIZED_INT;
	}

	static {
		try {
			method = _BenchmarkDyn.class.getMethod("staticMethod");
			Linkage.registerBootstrapMethod("bootstrap");
			methodHandle = MethodHandles.lookup().findStatic(
					_BenchmarkDyn.class, "staticMethod",
					MethodType.methodType(void.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(methodHandle);
		return cs;
	}

	private static void doUsual() {
		if (deoptimizedInt() >= 0) {
			staticMethod();
		}
	}

	private static void doDynSyntax()
			throws Throwable {
		if (deoptimizedInt() >= 0) {
			InvokeDynamic.anyName();
		}
	}

	private static void doDynExact()
			throws Throwable {
		if (deoptimizedInt() >= 0) {
			methodHandle.invokeExact();
		}
	}

	private static void doDynVarargs()
			throws Throwable {
		if (deoptimizedInt() >= 0) {
			methodHandle.invokeVarargs(CACHED_EMPTY_ARGS_ARRAY);
		}
	}

	private static void doReflect()
			throws Throwable {
		if (deoptimizedInt() >= 0) {
			method.invoke(CACHED_EMPTY_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.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();
		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(...)") {

				@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("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.14s
invoke dynamic: using invokeExact(...)
        1.05s
invoke dynamic: using invokeVarargs(...)
        7.33s
reflection: using Method.invoke(...)
        0.90s


More information about the mlvm-dev mailing list