package st.gravel.support.jvm.runtime;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import st.gravel.core.Symbol;
import st.gravel.support.compiler.ast.AbsoluteReference;
import st.gravel.support.compiler.ast.Reference;
import st.gravel.support.compiler.jvm.BlockSendArgument;
import st.gravel.support.jvm.ArrayExtensions;
import st.gravel.support.jvm.Block1;
import st.gravel.support.jvm.StringExtensions;
public class MethodLinker {
public static CallSite bootstrap(Lookup lookup, String selector,
MethodType type) throws Throwable {
BaseCallSite site = SmalltalkCallSite.newInstance(lookup, type,
selector);
return site;
}
public static CallSite literalBlockSendBootstrap(final Lookup lookup, String selector,
MethodType type, String ownerType, String astConstantString, String copiedArgumentsString) throws Throwable {
final Class<?> ownerClass = ImageBootstrapper.systemMapping.compilerTools().classForName_(ownerType);
BlockSendArgument[] astConstants = ArrayExtensions.collect_(ArrayExtensions.copyWithoutLast(
StringExtensions.tokensBasedOn_(astConstantString, ';')), new Block1<BlockSendArgument, String>() {
@Override
public BlockSendArgument value_(String constantName) {
if (constantName.length()==0) return null;
try {
return (BlockSendArgument) lookup.findStaticGetter(ownerClass, constantName, Object.class).invoke();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
});
String[] copiedArgumentNames = ArrayExtensions.copyWithoutLast(StringExtensions.tokensBasedOn_(copiedArgumentsString, ';'));
BaseCallSite site = LiteralBlockSendCallSite.newInstance(lookup, type, selector, astConstants, copiedArgumentNames);
return site;
}
public static CallSite constructorBootstrap(Lookup lookup, String selector,
MethodType type, String referenceString) throws Throwable {
Reference reference = Reference.factory.value_(referenceString);
Constructor constructor = ImageBootstrapper.systemMapping.classMappingAtReference_(reference).identityClass().getConstructor();
MethodHandle constructorHandle = lookup.unreflectConstructor(constructor);
return new ConstantCallSite(constructorHandle.asType(type));
}
public static CallSite superBootstrap(Lookup lookup, String selector,
MethodType type, String lookupStart) throws Throwable {
SuperCallSite site = SuperCallSite.newInstance(type, lookupStart,
selector, lookup);
return site;
}
public static CallSite fieldReadBootstrap(Lookup lookup, String selector,
MethodType type) throws Throwable {
FieldAccessCallSite site = FieldReadCallSite.newInstance(lookup, type,
selector);
return site;
}
public static CallSite fieldWriteBootstrap(Lookup lookup, String selector,
MethodType type) throws Throwable {
FieldWriteCallSite site = FieldWriteCallSite.newInstance(lookup, type,
selector, null);
return site;
}
public static CallSite globalReadBootstrap(Lookup lookup, String selector,
MethodType type, String namespaceString) throws Throwable {
AbsoluteReference namespace = (AbsoluteReference) Reference.factory
.value_(namespaceString);
AbsoluteReference fullReference = namespace.$slash$(Symbol
.value(selector));
final AlmostFinalValue singletonHolder = ImageBootstrapper.systemMapping
.resolveSingletonHolder_(fullReference);
return new ConstantCallSite(singletonHolder.createGetter());
}
public static CallSite globalWriteBootstrap(Lookup lookup, String selector,
MethodType type, String namespaceString) throws Throwable {
AbsoluteReference namespace = (AbsoluteReference) Reference.factory
.value_(namespaceString);
AbsoluteReference fullReference = namespace.$slash$(Symbol
.value(selector));
final AlmostFinalValue singletonHolder = ImageBootstrapper.systemMapping
.resolveSingletonHolder_(fullReference);
final MethodHandle target = lookup.findVirtual(
AlmostFinalValue.class,
"setValue",
MethodType.methodType(Object.class, Object.class)).bindTo(singletonHolder);
return new ConstantCallSite(target);
}
}