Skip to content

Instantly share code, notes, and snippets.

@forax
Created February 20, 2018 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forax/7bf08669f58804991fd45656a671c381 to your computer and use it in GitHub Desktop.
Save forax/7bf08669f58804991fd45656a671c381 to your computer and use it in GitHub Desktop.
an invoker that cache up to 'depth' method handles allowing to inline call to them
import static java.lang.invoke.MethodHandles.exactInvoker;
import static java.lang.invoke.MethodHandles.foldArguments;
import static java.lang.invoke.MethodHandles.lookup;
import static java.lang.invoke.MethodType.methodType;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
public class InliningCacheInvoker {
private InliningCacheInvoker() {
throw new AssertionError();
}
public static MethodHandle inliningCacheInvoker(int depth, MethodType type) {
if (depth < 0) {
throw new IllegalArgumentException("depth should be positive");
}
return new InliningCacheCallSite(type.insertParameterTypes(0, MethodHandle.class), depth).dynamicInvoker();
}
private static class InliningCacheCallSite extends MutableCallSite {
private static final MethodHandle FALLBACK, TYPECHECK;
static {
Lookup lookup = lookup();
try {
FALLBACK = lookup.findVirtual(InliningCacheCallSite.class, "fallback",
methodType(MethodHandle.class, MethodHandle.class));
TYPECHECK = lookup.findStatic(InliningCacheCallSite.class, "typecheck",
methodType(boolean.class, MethodHandle.class, MethodHandle.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new AssertionError(e);
}
}
private final InliningCacheCallSite head;
private final int depth;
InliningCacheCallSite(MethodType type, int depth) {
super(type);
head = this;
this.depth = depth;
setTarget(foldArguments(exactInvoker(type), FALLBACK.bindTo(this)));
}
InliningCacheCallSite(MethodType type, InliningCacheCallSite head, int depth) {
super(type);
this.head = head;
this.depth = depth;
setTarget(foldArguments(exactInvoker(type), FALLBACK.bindTo(this)));
}
@SuppressWarnings("unused")
private MethodHandle fallback(MethodHandle mh) {
MethodHandle target = MethodHandles.dropArguments(mh, 0, MethodHandle.class);
if (depth == 0) { // inlining too deep
head.setTarget(exactInvoker(type().dropParameterTypes(0, 1)));
return target;
}
setTarget(MethodHandles.guardWithTest(TYPECHECK.bindTo(mh),
target,
new InliningCacheCallSite(type(), head, depth - 1).dynamicInvoker()));
return target;
}
@SuppressWarnings("unused")
private static boolean typecheck(MethodHandle mh1, MethodHandle mh2) {
return mh1 == mh2;
}
}
// ---
private static final MethodHandle INVOKER = inliningCacheInvoker(3, methodType(String.class, String.class, String.class));
private static String test(MethodHandle mh) throws Throwable {
return (String)INVOKER.invokeExact(mh, "hello ", "invoker");
}
public static void main(String[] args) throws Throwable {
MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
int sum = 0;
for(int i = 0; i < 10_000_000; i++) {
String s = test(mh);
sum += s.length();
}
System.out.println(sum);
}
}
@cowwoc
Copy link

cowwoc commented Dec 28, 2018

Remi,

I read http://mail.openjdk.java.net/pipermail/mlvm-dev/2018-February/006832.html but I still don't understand how this works. Are you able to break this down for us laymen? :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment