package com.oracle.svm.hosted.substitute;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.List;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.nodes.CallTargetNode;
import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import com.oracle.graal.pointsto.infrastructure.GraphProvider;
import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess;
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
import com.oracle.graal.pointsto.meta.HostedProviders;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.phases.HostedGraphKit;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ExceptionHandler;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.LineNumberTable;
import jdk.vm.ci.meta.LocalVariableTable;
import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
import jdk.vm.ci.meta.SpeculationLog;
public class PolymorphicSignatureWrapperMethod implements ResolvedJavaMethod, GraphProvider {
private final SubstitutionMethod substitutionBaseMethod;
private final ResolvedJavaMethod originalMethod;
private final ConstantPool constantPool;
private StackTraceElement stackTraceElement;
private static final LineNumberTable lineNumberTable = new LineNumberTable(new int[]{1}, new int[]{0});
PolymorphicSignatureWrapperMethod(SubstitutionMethod substitutionBaseMethod, ResolvedJavaMethod originalMethod) {
this.substitutionBaseMethod = substitutionBaseMethod;
this.originalMethod = originalMethod;
this.constantPool = substitutionBaseMethod.getDeclaringClass().getDeclaredConstructors()[0].getConstantPool();
}
@Override
public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) {
UniverseMetaAccess metaAccess = (UniverseMetaAccess) providers.getMetaAccess();
HostedGraphKit kit = new HostedGraphKit(debug, providers, method);
List<ValueNode> args = kit.loadArguments(method.toParameterTypes());
ValueNode receiver = null;
if (!substitutionBaseMethod.isStatic()) {
receiver = args.remove(0);
}
ValueNode parameterArray = kit.createObject(new Object[args.size()]);
for (int i = 0; i < args.size(); ++i) {
ValueNode arg = args.get(i);
if (arg.getStackKind().isPrimitive()) {
arg = kit.createBoxing(arg, arg.getStackKind(), metaAccess.lookupJavaType(arg.getStackKind().toBoxedJavaClass()));
}
StateSplit storeIndexedNode = (StateSplit) kit.createStoreIndexed(parameterArray, i, JavaKind.Object, arg);
storeIndexedNode.setStateAfter(kit.getFrameState().create(kit.bci(), storeIndexedNode));
}
ResolvedJavaMethod invokeTarget;
if (metaAccess instanceof AnalysisMetaAccess) {
invokeTarget = metaAccess.getUniverse().lookup(substitutionBaseMethod.getOriginal());
} else {
invokeTarget = metaAccess.getUniverse().lookup(((AnalysisMetaAccess) metaAccess.getWrapped()).getUniverse().lookup(substitutionBaseMethod.getOriginal()));
}
InvokeWithExceptionNode invoke;
if (substitutionBaseMethod.isStatic()) {
invoke = kit.createInvokeWithExceptionAndUnwind(invokeTarget, CallTargetNode.InvokeKind.Static, kit.getFrameState(), kit.bci(), parameterArray);
} else {
invoke = kit.createInvokeWithExceptionAndUnwind(invokeTarget, CallTargetNode.InvokeKind.Virtual, kit.getFrameState(), kit.bci(), receiver, parameterArray);
}
JavaKind returnKind = getSignature().getReturnKind();
ValueNode retVal = invoke;
if (returnKind.isPrimitive() && returnKind != JavaKind.Void) {
retVal = kit.createUnboxing(invoke, returnKind, metaAccess);
}
kit.createReturn(retVal, returnKind);
return kit.finalizeGraph();
}
@Override
public String getName() {
return substitutionBaseMethod.getName();
}
@Override
public ResolvedJavaType getDeclaringClass() {
return substitutionBaseMethod.getDeclaringClass();
}
@Override
public Signature getSignature() {
return originalMethod.getSignature();
}
@Override
public boolean allowRuntimeCompilation() {
return false;
}
@Override
public byte[] getCode() {
return null;
}
@Override
public int getCodeSize() {
return 0;
}
@Override
public int getMaxLocals() {
return 2 * getSignature().getParameterCount(true);
}
@Override
public int getMaxStackSize() {
return 0;
}
@Override
public boolean isSynthetic() {
return true;
}
@Override
public boolean isVarArgs() {
return false;
}
@Override
public boolean isBridge() {
return false;
}
@Override
public boolean isDefault() {
return false;
}
@Override
public boolean isClassInitializer() {
return false;
}
@Override
public boolean isConstructor() {
return false;
}
@Override
public boolean canBeStaticallyBound() {
return true;
}
@Override
public ExceptionHandler[] getExceptionHandlers() {
return new ExceptionHandler[0];
}
@Override
public StackTraceElement asStackTraceElement(int bci) {
if (stackTraceElement == null) {
stackTraceElement = new StackTraceElement(getDeclaringClass().toJavaName(true), getName(), "generated", 0);
}
return stackTraceElement;
}
@Override
public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
throw VMError.unimplemented();
}
@Override
public void reprofile() {
throw VMError.unimplemented();
}
@Override
public ConstantPool getConstantPool() {
return constantPool;
}
@Override
public Annotation[][] getParameterAnnotations() {
throw VMError.unimplemented();
}
@Override
public Type[] getGenericParameterTypes() {
throw VMError.unimplemented();
}
@Override
public boolean canBeInlined() {
return true;
}
@Override
public boolean hasNeverInlineDirective() {
return false;
}
@Override
public boolean shouldBeInlined() {
return true;
}
@Override
public LineNumberTable getLineNumberTable() {
return lineNumberTable;
}
@Override
public LocalVariableTable getLocalVariableTable() {
return null;
}
@Override
public Constant getEncoding() {
throw VMError.unimplemented();
}
@Override
public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
throw VMError.unimplemented();
}
@Override
public SpeculationLog getSpeculationLog() {
throw VMError.unimplemented();
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return substitutionBaseMethod.getAnnotation(annotationClass);
}
@Override
public Annotation[] getAnnotations() {
return substitutionBaseMethod.getAnnotations();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return substitutionBaseMethod.getDeclaredAnnotations();
}
@Override
public int getModifiers() {
return substitutionBaseMethod.getModifiers();
}
}