Skip to content

Instantly share code, notes, and snippets.

@forax
Created July 29, 2016 14:57
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/5876d900cad800d3445f7a07d2daef52 to your computer and use it in GitHub Desktop.
Save forax/5876d900cad800d3445f7a07d2daef52 to your computer and use it in GitHub Desktop.
Create a polymorphic inline cache that doesn't deoptimize a lot
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