Add megamorphic cache
This commit is contained in:
parent
b71f42a627
commit
a473298f44
|
@ -122,41 +122,62 @@ public final class DefBootstrap {
|
||||||
/**
|
/**
|
||||||
* Does a slow lookup against the whitelist.
|
* Does a slow lookup against the whitelist.
|
||||||
*/
|
*/
|
||||||
private MethodHandle lookup(int flavor, String name, Object[] args) throws Throwable {
|
private MethodHandle lookup(int flavor, String name, Class<?> receiver, Object[] callArgs) throws Throwable {
|
||||||
switch(flavor) {
|
switch(flavor) {
|
||||||
case METHOD_CALL:
|
case METHOD_CALL:
|
||||||
return Def.lookupMethod(lookup, type(), args[0].getClass(), name, args, (Long) this.args[0]);
|
return Def.lookupMethod(lookup, type(), receiver, name, callArgs, (Long) this.args[0]);
|
||||||
case LOAD:
|
case LOAD:
|
||||||
return Def.lookupGetter(args[0].getClass(), name);
|
return Def.lookupGetter(receiver, name);
|
||||||
case STORE:
|
case STORE:
|
||||||
return Def.lookupSetter(args[0].getClass(), name);
|
return Def.lookupSetter(receiver, name);
|
||||||
case ARRAY_LOAD:
|
case ARRAY_LOAD:
|
||||||
return Def.lookupArrayLoad(args[0].getClass());
|
return Def.lookupArrayLoad(receiver);
|
||||||
case ARRAY_STORE:
|
case ARRAY_STORE:
|
||||||
return Def.lookupArrayStore(args[0].getClass());
|
return Def.lookupArrayStore(receiver);
|
||||||
case ITERATOR:
|
case ITERATOR:
|
||||||
return Def.lookupIterator(args[0].getClass());
|
return Def.lookupIterator(receiver);
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
return Def.lookupReference(lookup, (String) this.args[0], args[0].getClass(), name);
|
return Def.lookupReference(lookup, (String) this.args[0], receiver, name);
|
||||||
default: throw new AssertionError();
|
default: throw new AssertionError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a new type is encountered (or, when we have encountered more than {@code MAX_DEPTH}
|
* Called when a new type is encountered (or, when we have encountered more than {@code MAX_DEPTH}
|
||||||
* types at this call site and given up on caching).
|
* types at this call site and given up on caching using this fallback wand we switch to a
|
||||||
|
* megamorphic cache using {@link ClassValue}).
|
||||||
*/
|
*/
|
||||||
@SuppressForbidden(reason = "slow path")
|
@SuppressForbidden(reason = "slow path")
|
||||||
Object fallback(Object[] args) throws Throwable {
|
Object fallback(final Object[] callArgs) throws Throwable {
|
||||||
|
final Class<?> receiver = callArgs[0].getClass();
|
||||||
|
final MethodType type = type();
|
||||||
|
|
||||||
if (depth >= MAX_DEPTH) {
|
if (depth >= MAX_DEPTH) {
|
||||||
// XXX: caching defeated: lookups up every time(!)
|
// we revert the whole cache and build a new megamorphic one
|
||||||
return lookup(flavor, name, args).invokeWithArguments(args);
|
// using ClassValue and MethodHandles.exactInvoker():
|
||||||
|
final ClassValue<MethodHandle> megamorphicCache = new ClassValue<MethodHandle>() {
|
||||||
|
@Override
|
||||||
|
protected MethodHandle computeValue(Class<?> receiverType) {
|
||||||
|
try {
|
||||||
|
return lookup(flavor, name, receiverType, callArgs).asType(type);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// XXX: fix that
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MethodHandle cacheLookup = MEGAMORPHIC_LOOKUP.bindTo(megamorphicCache);
|
||||||
|
cacheLookup = MethodHandles.dropArguments(cacheLookup,
|
||||||
|
0, type.parameterList().subList(1, type.parameterCount()));
|
||||||
|
cacheLookup = cacheLookup.asType(type.changeReturnType(MethodHandle.class));
|
||||||
|
MethodHandle target = MethodHandles.foldArguments(MethodHandles.exactInvoker(type), cacheLookup);
|
||||||
|
setTarget(target);
|
||||||
|
return target.invokeWithArguments(callArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
final MethodType type = type();
|
final MethodHandle target = lookup(flavor, name, receiver, callArgs).asType(type);
|
||||||
final MethodHandle target = lookup(flavor, name, args).asType(type);
|
|
||||||
|
|
||||||
MethodHandle test = CHECK_CLASS.bindTo(args[0].getClass());
|
MethodHandle test = CHECK_CLASS.bindTo(receiver);
|
||||||
test = test.asType(test.type().changeParameterType(0, type.parameterType(0)));
|
test = test.asType(test.type().changeParameterType(0, type.parameterType(0)));
|
||||||
|
|
||||||
MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget());
|
MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget());
|
||||||
|
@ -164,18 +185,24 @@ public final class DefBootstrap {
|
||||||
depth++;
|
depth++;
|
||||||
|
|
||||||
setTarget(guard);
|
setTarget(guard);
|
||||||
return target.invokeWithArguments(args);
|
return target.invokeWithArguments(callArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final MethodHandle CHECK_CLASS;
|
private static final MethodHandle CHECK_CLASS;
|
||||||
private static final MethodHandle FALLBACK;
|
private static final MethodHandle FALLBACK;
|
||||||
|
private static final MethodHandle MEGAMORPHIC_LOOKUP;
|
||||||
static {
|
static {
|
||||||
final Lookup lookup = MethodHandles.lookup();
|
final Lookup lookup = MethodHandles.lookup();
|
||||||
try {
|
try {
|
||||||
CHECK_CLASS = lookup.findStatic(lookup.lookupClass(), "checkClass",
|
CHECK_CLASS = lookup.findStatic(lookup.lookupClass(), "checkClass",
|
||||||
MethodType.methodType(boolean.class, Class.class, Object.class));
|
MethodType.methodType(boolean.class, Class.class, Object.class));
|
||||||
FALLBACK = lookup.findVirtual(lookup.lookupClass(), "fallback",
|
FALLBACK = lookup.findVirtual(lookup.lookupClass(), "fallback",
|
||||||
MethodType.methodType(Object.class, Object[].class));
|
MethodType.methodType(Object.class, Object[].class));
|
||||||
|
MethodHandle mh = MethodHandles.publicLookup().findVirtual(ClassValue.class, "get",
|
||||||
|
MethodType.methodType(Object.class, Class.class));
|
||||||
|
mh = MethodHandles.filterArguments(mh, 1,
|
||||||
|
MethodHandles.publicLookup().findVirtual(Object.class, "getClass", MethodType.methodType(Class.class)));
|
||||||
|
MEGAMORPHIC_LOOKUP = mh;
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue