Created
July 29, 2016 14:57
-
-
Save forax/5876d900cad800d3445f7a07d2daef52 to your computer and use it in GitHub Desktop.
Create a polymorphic inline cache that doesn't deoptimize a lot
This file contains 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.guardWithTest; | |
import static java.lang.invoke.MethodHandles.insertArguments; | |
import static java.lang.invoke.MethodHandles.lookup; | |
import static java.lang.invoke.MethodHandles.publicLookup; | |
import static java.lang.invoke.MethodType.methodType; | |
import java.lang.invoke.MethodHandle; | |
import java.lang.invoke.MethodType; | |
import java.lang.invoke.MutableCallSite; | |
import java.net.URI; | |
import java.net.URISyntaxException; | |
import java.util.function.Function; | |
// java -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+PrintCompilation -cp ../classes FunPIC2 | |
public class FunPIC2 { | |
public interface Control { | |
void setTarget(MethodHandle test, MethodHandle target); | |
} | |
public interface Deopt { | |
MethodHandle deopt(Control control, Object receiver); | |
} | |
static final MethodHandle DEOPT; | |
static { | |
try { | |
DEOPT = publicLookup().findVirtual(Deopt.class, "deopt", methodType(MethodHandle.class, Control.class, Object.class)); | |
} catch (NoSuchMethodException | IllegalAccessException e) { | |
throw new AssertionError(e); | |
} | |
} | |
static class DeoptCallSite extends MutableCallSite { | |
public DeoptCallSite(MethodType type, Function<MutableCallSite, MethodHandle> fun) { | |
super(type); | |
setTarget(fun.apply(this)); | |
} | |
} | |
public static MethodHandle createPIC(MethodType type, Deopt deopt) { | |
return new DeoptCallSite(type, cs -> { | |
Control control = (test, target) -> { | |
cs.setTarget(guardWithTest(test, target, createPIC(type, deopt))); | |
}; | |
MethodHandle target = insertArguments(DEOPT, 0, deopt, control); | |
target = target.asType(methodType(MethodHandle.class, type.parameterType(0))); | |
return foldArguments(exactInvoker(type), target); | |
}).dynamicInvoker(); | |
} | |
// --- test --- | |
private static final MethodHandle TYPE_CHECK; | |
static { | |
try { | |
TYPE_CHECK = lookup().findStatic(FunPIC2.class, "typeCheck", MethodType.methodType(boolean.class, Object.class, Class.class)); | |
} catch (NoSuchMethodException | IllegalAccessException e) { | |
throw new AssertionError(e); | |
} | |
} | |
static final MethodHandle PIC_MH; | |
static { | |
PIC_MH = createPIC(methodType(int.class, Object.class), (control, receiver) -> { | |
System.out.println("deopt !!!"); | |
Class<?> receiverClass = receiver.getClass(); | |
MethodHandle guard = insertArguments(TYPE_CHECK, 1, receiverClass); | |
MethodHandle target; | |
try { | |
target = lookup().findStatic(FunPIC2.class, "impl", MethodType.methodType(int.class, receiverClass)); | |
} catch (NoSuchMethodException | IllegalAccessException e) { | |
throw new AssertionError(e); | |
} | |
target = target.asType(methodType(int.class, Object.class)); | |
control.setTarget(guard, target); | |
return target; | |
}); | |
} | |
private static int m(Object o) throws Throwable { | |
return (int)PIC_MH.invokeExact(o); | |
} | |
public static int test(Object o) { | |
try { | |
return m(o); | |
} catch (Throwable e) { | |
throw new AssertionError(e); | |
} | |
} | |
public static int test2(Object o) { | |
try { | |
return m(o); | |
} catch (Throwable e) { | |
throw new AssertionError(e); | |
} | |
} | |
public static int loop(Object o, Object o2) { | |
int sum = 0; | |
for(int i = 0; i < 100_000; i++) { | |
sum += test(o); | |
sum += test2(o2); | |
} | |
return sum; | |
} | |
public static void main(String[] args) throws URISyntaxException { | |
Object[] array = { "hello", new URI("http://hello/") /*, 4.5*/ }; | |
Object[] array2 = { "hello", "2" /*, 4.5*/ }; | |
int sum = 0; | |
for(int i = 0; i < array.length; i++) { | |
sum += loop(array[i], array2[i]); | |
} | |
System.out.println(sum); | |
} | |
private static boolean typeCheck(Object o, Class<?> type) { | |
return o.getClass() == type; | |
} | |
private static int ONE = 1; | |
private static int TWO = 2; | |
private static int impl(String s) { | |
/*int sum = 0; | |
for(int c: s.toCharArray()) { | |
sum += c; | |
} | |
return sum;*/ | |
return ONE; | |
} | |
private static int impl(URI u) { | |
/* | |
int sum = 0; | |
for(int c: u.toASCIIString().toCharArray()) { | |
sum += c; | |
} | |
return sum; | |
*/ | |
return TWO; | |
} | |
private static int impl(Integer i) { | |
return ((Integer)i.intValue()).intValue(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment