Few questions about invokeDynamic
assembling signals
assembling.signals at yandex.ru
Mon Nov 8 11:52:21 PST 2010
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
More information about the mlvm-dev
mailing list