package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import java.lang.invoke.MethodHandle;
import java.util.Objects;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.MethodHandleAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider {
private final ConstantReflectionProvider constantReflection;
public HotSpotMethodHandleAccessProvider(ConstantReflectionProvider constantReflection) {
this.constantReflection = constantReflection;
}
static class LazyInitialization {
static final ResolvedJavaType lambdaFormType;
static final ResolvedJavaField methodHandleFormField;
static final ResolvedJavaField lambdaFormVmentryField;
static final ResolvedJavaField methodField;
static final HotSpotResolvedJavaField vmtargetField;
private static ResolvedJavaField findFieldInClass(ResolvedJavaType declaringType, String fieldName, ResolvedJavaType fieldType) {
ResolvedJavaField[] fields = declaringType.getInstanceFields(false);
for (ResolvedJavaField field : fields) {
if (field.getName().equals(fieldName) && field.getType().equals(fieldType)) {
return field;
}
}
throw new NoSuchFieldError(fieldType.getName() + " " + declaringType + "." + fieldName);
}
private static ResolvedJavaType resolveType(Class<?> c) {
return runtime().fromClass(c);
}
private static ResolvedJavaType resolveType(String className) throws ClassNotFoundException {
return resolveType(Class.forName(className));
}
static {
try {
ResolvedJavaType methodHandleType = resolveType(MethodHandle.class);
ResolvedJavaType memberNameType = resolveType("java.lang.invoke.MemberName");
lambdaFormType = resolveType("java.lang.invoke.LambdaForm");
methodHandleFormField = findFieldInClass(methodHandleType, "form", lambdaFormType);
lambdaFormVmentryField = findFieldInClass(lambdaFormType, "vmentry", memberNameType);
ResolvedJavaType methodType = resolveType("java.lang.invoke.ResolvedMethodName");
methodField = findFieldInClass(memberNameType, "method", methodType);
vmtargetField = (HotSpotResolvedJavaField) findFieldInClass(methodType, "vmtarget", resolveType(HotSpotJVMCIRuntime.getHostWordKind().toJavaClass()));
} catch (Throwable ex) {
throw new JVMCIError(ex);
}
}
}
@Override
public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId();
if (intrinsicId != 0) {
return getMethodHandleIntrinsic(intrinsicId);
}
return null;
}
public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) {
HotSpotVMConfig config = runtime().getConfig();
if (intrinsicId == config.vmIntrinsicInvokeBasic) {
return IntrinsicMethod.INVOKE_BASIC;
} else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
return IntrinsicMethod.LINK_TO_INTERFACE;
} else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
return IntrinsicMethod.LINK_TO_SPECIAL;
} else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
return IntrinsicMethod.LINK_TO_STATIC;
} else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
return IntrinsicMethod.LINK_TO_VIRTUAL;
}
return null;
}
@Override
public ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration) {
if (methodHandle.isNull()) {
return null;
}
JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle);
if (lambdaForm == null || lambdaForm.isNull()) {
return null;
}
JavaConstant memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm);
if (memberName.isNull() && forceBytecodeGeneration) {
Object lf = ((HotSpotObjectConstant) lambdaForm).asObject(LazyInitialization.lambdaFormType);
compilerToVM().compileToBytecode(Objects.requireNonNull(lf));
memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm);
assert memberName.isNonNull();
}
JavaConstant method = constantReflection.readFieldValue(LazyInitialization.methodField, memberName);
return getTargetMethod(method);
}
@Override
public ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName) {
if (memberName.isNull()) {
return null;
}
JavaConstant method = constantReflection.readFieldValue(LazyInitialization.methodField, memberName);
return getTargetMethod(method);
}
private static ResolvedJavaMethod getTargetMethod(JavaConstant method) {
if (method == null) {
throw new IllegalArgumentException("unexpected type for memberName");
}
Object object = ((HotSpotObjectConstantImpl) method).object();
return compilerToVM().getResolvedJavaMethod(object, LazyInitialization.vmtargetField.getOffset());
}
}