Created
February 20, 2018 13:21
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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? :)