package com.oracle.svm.hosted.meta;
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
import static com.oracle.svm.core.util.VMError.unimplemented;
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.lang.reflect.Type;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.JavaMethodContext;
import org.graalvm.compiler.nodes.StructuredGraph;
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
import com.oracle.graal.pointsto.infrastructure.GraphProvider;
import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod;
import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.graal.pointsto.meta.HostedProviders;
import com.oracle.graal.pointsto.results.StaticAnalysisResults;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.annotate.AlwaysInline;
import com.oracle.svm.core.annotate.StubCallingConvention;
import com.oracle.svm.core.deopt.Deoptimizer;
import com.oracle.svm.core.meta.SharedMethod;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.code.CompilationInfo;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ExceptionHandler;
import jdk.vm.ci.meta.JavaMethod;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.LineNumberTable;
import jdk.vm.ci.meta.Local;
import jdk.vm.ci.meta.LocalVariableTable;
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 HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, Comparable<HostedMethod>, OriginalMethodProvider {
public static final String METHOD_NAME_DEOPT_SUFFIX = "**";
public final AnalysisMethod wrapped;
private final HostedType holder;
private final Signature signature;
private final ConstantPool constantPool;
private final ExceptionHandler[] handlers;
protected StaticAnalysisResults staticAnalysisResults;
private final boolean hasNeverInlineDirective;
protected int vtableIndex = -1;
private int codeAddressOffset;
private boolean codeAddressOffsetValid;
private boolean compiled;
protected HostedMethod[] implementations;
public final CompilationInfo compilationInfo;
private final LocalVariableTable localVariableTable;
public HostedMethod(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, ExceptionHandler[] handlers) {
this.wrapped = wrapped;
this.holder = holder;
this.signature = signature;
this.constantPool = constantPool;
this.handlers = handlers;
this.compilationInfo = new CompilationInfo(this);
LocalVariableTable newLocalVariableTable = null;
if (wrapped.getLocalVariableTable() != null) {
try {
Local[] origLocals = wrapped.getLocalVariableTable().getLocals();
Local[] newLocals = new Local[origLocals.length];
for (int i = 0; i < newLocals.length; ++i) {
Local origLocal = origLocals[i];
JavaType origType = origLocal.getType();
if (!universe.contains(origType)) {
throw new UnsupportedFeatureException("No HostedType for given AnalysisType");
}
HostedType newType = universe.lookup(origType);
newLocals[i] = new Local(origLocal.getName(), newType, origLocal.getStartBCI(), origLocal.getEndBCI(), origLocal.getSlot());
}
newLocalVariableTable = new LocalVariableTable(newLocals);
} catch (UnsupportedFeatureException e) {
newLocalVariableTable = null;
}
}
localVariableTable = newLocalVariableTable;
hasNeverInlineDirective = SubstrateUtil.NativeImageLoadingShield.isNeverInline(wrapped);
}
@Override
public HostedMethod[] getImplementations() {
return implementations;
}
public String getQualifiedName() {
return wrapped.getQualifiedName();
}
public void setCodeAddressOffset(int address) {
assert isCompiled();
codeAddressOffset = address;
codeAddressOffsetValid = true;
}
public int getCodeAddressOffset() {
if (!codeAddressOffsetValid) {
throw VMError.shouldNotReachHere(format("%H.%n(%p)") + ": has no code address offset set.");
}
return codeAddressOffset;
}
public boolean isCodeAddressOffsetValid() {
return codeAddressOffsetValid;
}
public void setCompiled() {
this.compiled = true;
}
public boolean isCompiled() {
return compiled;
}
public void clear() {
compilationInfo.clear();
staticAnalysisResults = null;
}
@Override
public int getCodeOffsetInImage() {
throw unimplemented();
}
@Override
public int getDeoptOffsetInImage() {
HostedMethod deoptTarget = compilationInfo.getDeoptTargetMethod();
int result = 0;
if (deoptTarget != null && deoptTarget.isCodeAddressOffsetValid()) {
result = deoptTarget.getCodeAddressOffset();
assert result != 0;
} else if (compilationInfo.isDeoptTarget()) {
result = getCodeAddressOffset();
assert result != 0;
}
return result;
}
@Override
public AnalysisMethod getWrapped() {
return wrapped;
}
@Override
public Parameter[] getParameters() {
return wrapped.getParameters();
}
@Override
public boolean isDeoptTarget() {
return compilationInfo.isDeoptTarget();
}
@Override
public boolean canDeoptimize() {
return compilationInfo.canDeoptForTesting();
}
public boolean hasVTableIndex() {
return vtableIndex != -1;
}
@Override
public int getVTableIndex() {
assert vtableIndex != -1;
return vtableIndex;
}
@Override
public Deoptimizer.StubType getDeoptStubType() {
Deoptimizer.DeoptStub stubAnnotation = getAnnotation(Deoptimizer.DeoptStub.class);
if (stubAnnotation != null) {
return stubAnnotation.stubType();
}
return Deoptimizer.StubType.NoDeoptStub;
}
@Override
public boolean isEntryPoint() {
return wrapped.isEntryPoint();
}
@Override
public boolean hasCalleeSavedRegisters() {
return StubCallingConvention.Utils.hasStubCallingConvention(this);
}
@Override
public String getName() {
if (compilationInfo.isDeoptTarget()) {
return wrapped.getName() + METHOD_NAME_DEOPT_SUFFIX;
}
return wrapped.getName();
}
@Override
public Signature getSignature() {
return signature;
}
@Override
public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) {
return wrapped.buildGraph(debug, method, providers, purpose);
}
@Override
public boolean allowRuntimeCompilation() {
return wrapped.allowRuntimeCompilation();
}
@Override
public byte[] getCode() {
return wrapped.getCode();
}
@Override
public int getCodeSize() {
return wrapped.getCodeSize();
}
@Override
public HostedType getDeclaringClass() {
return holder;
}
@Override
public int getMaxLocals() {
return wrapped.getMaxLocals();
}
@Override
public int getMaxStackSize() {
return wrapped.getMaxStackSize();
}
@Override
public int getModifiers() {
return wrapped.getModifiers();
}
@Override
public boolean isSynthetic() {
return wrapped.isSynthetic();
}
@Override
public boolean isVarArgs() {
return wrapped.isVarArgs();
}
@Override
public boolean isBridge() {
return wrapped.isBridge();
}
@Override
public boolean isClassInitializer() {
return wrapped.isClassInitializer();
}
@Override
public boolean isConstructor() {
return wrapped.isConstructor();
}
@Override
public boolean canBeStaticallyBound() {
return implementations.length == 1 && implementations[0].equals(this);
}
@Override
public ExceptionHandler[] getExceptionHandlers() {
return handlers;
}
@Override
public StackTraceElement asStackTraceElement(int bci) {
return wrapped.asStackTraceElement(bci);
}
@Override
public StaticAnalysisResults getProfilingInfo() {
return staticAnalysisResults;
}
@Override
public StaticAnalysisResults getProfilingInfo(boolean includeNormal, boolean includeOSR) {
return staticAnalysisResults;
}
@Override
public ConstantPool getConstantPool() {
return constantPool;
}
@Override
public Annotation[] getAnnotations() {
return wrapped.getAnnotations();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return wrapped.getDeclaredAnnotations();
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
return wrapped.getAnnotation(annotationClass);
}
@Override
public Annotation[][] getParameterAnnotations() {
return wrapped.getParameterAnnotations();
}
@Override
public Type[] getGenericParameterTypes() {
return wrapped.getGenericParameterTypes();
}
@Override
public boolean canBeInlined() {
return !hasNeverInlineDirective();
}
@Override
public boolean hasNeverInlineDirective() {
return hasNeverInlineDirective;
}
@Override
public boolean shouldBeInlined() {
return getAnnotation(AlwaysInline.class) != null;
}
@Override
public LineNumberTable getLineNumberTable() {
return wrapped.getLineNumberTable();
}
@Override
public String toString() {
return "HostedMethod<" + format("%h.%n") + " -> " + wrapped.toString() + ">";
}
@Override
public LocalVariableTable getLocalVariableTable() {
return localVariableTable;
}
@Override
public void reprofile() {
throw unimplemented();
}
@Override
public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
return false;
}
@Override
public Constant getEncoding() {
throw unimplemented();
}
@Override
public boolean isDefault() {
throw unimplemented();
}
@Override
public SpeculationLog getSpeculationLog() {
throw shouldNotReachHere();
}
@Override
public JavaMethod asJavaMethod() {
return this;
}
@Override
public int hashCode() {
return wrapped.hashCode();
}
@Override
public int compareTo(HostedMethod other) {
if (this.equals(other)) {
return 0;
}
int result = Boolean.compare(this.compilationInfo.isDeoptTarget(), other.compilationInfo.isDeoptTarget());
if (result == 0) {
result = this.getDeclaringClass().compareTo(other.getDeclaringClass());
}
if (result == 0) {
result = this.getName().compareTo(other.getName());
}
if (result == 0) {
result = this.getSignature().getParameterCount(false) - other.getSignature().getParameterCount(false);
}
if (result == 0) {
for (int i = 0; i < this.getSignature().getParameterCount(false); i++) {
result = ((HostedType) this.getSignature().getParameterType(i, null)).compareTo((HostedType) other.getSignature().getParameterType(i, null));
if (result != 0) {
break;
}
}
}
if (result == 0) {
result = ((HostedType) this.getSignature().getReturnType(null)).compareTo((HostedType) other.getSignature().getReturnType(null));
}
assert result != 0;
return result;
}
@Override
public Executable getJavaMethod() {
return OriginalMethodProvider.getJavaMethod(getDeclaringClass().universe.getSnippetReflection(), wrapped);
}
}