package st.gravel.support.jvm.runtime;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import st.gravel.support.compiler.ast.AbstractMethodMapping;
import st.gravel.support.compiler.ast.Reference;
public class SuperCallSite extends BaseCallSite {
public static SuperCallSite newInstance(MethodType type,
String lookupStart, String selector, Lookup lookup) {
SuperCallSite callsite = new SuperCallSite(type, lookupStart, selector,
lookup);
BaseCallSite.register(callsite);
return callsite;
}
private SuperCallSite(MethodType type, String lookupStart, String selector,
Lookup lookup) {
super(lookup, type, selector);
this.lookupStart = lookupStart;
}
private final String lookupStart;
public MethodHandle lookupMethod(Class receiverClass) {
return lookupMethod(receiverClass, selector);
}
public MethodHandle lookupMethod(Class receiverClass, String selector) {
Reference reference = Reference.factory.value_(lookupStart);
AbstractMethodMapping mapping = ImageBootstrapper.systemMapping
.superMethodMappingFor_methodName_(reference, selector);
if (mapping == null) {
if (selector.equals("doesNotUnderstand_"))
throw new RuntimeException("Can't find DNU method");
return wrapDNUHandle(lookupMethod(receiverClass,
"doesNotUnderstand_"));
}
MethodHandle methodHandle;
try {
Method method = MethodTools.searchForMethod(
mapping.definingClass(), selector, type.parameterArray(),
true);
if (method != null) {
return mapping.methodHandle().asType(type);
}
methodHandle = lookup.findSpecial(mapping.definingClass(),
selector, type.dropParameterTypes(0, 1), lookup.lookupClass());
} catch (NoSuchMethodException | IllegalAccessException r) {
try {
methodHandle = lookup.findStatic(mapping.definingClass(),
selector, type);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return methodHandle.asType(type);
}
@Override
protected void addTargetToCache(Object receiver) {
Class receiverClass = receiver.getClass();
MethodHandle target = lookupMethod(receiverClass);
setTarget(target);
}
@Override
protected void resetCache() {
}
}