package com.oracle.svm.methodhandles;
import static com.oracle.svm.core.util.VMError.unimplemented;
import static com.oracle.svm.core.util.VMError.unsupportedFeature;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.AnnotateOriginal;
import com.oracle.svm.core.annotate.Delete;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.jdk.JDK11OrLater;
import com.oracle.svm.core.jdk.JDK8OrEarlier;
import com.oracle.svm.reflect.target.Target_java_lang_reflect_Field;
@SuppressWarnings("unused")
@TargetClass(className = "java.lang.invoke.MethodHandleNatives", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_MethodHandleNatives {
@Substitute
private static void init(Target_java_lang_invoke_MemberName self, Object ref) {
Member member = (Member) ref;
Object type;
int flags;
byte refKind;
if (member instanceof Field) {
Field field = (Field) member;
type = field.getType();
flags = Target_java_lang_invoke_MethodHandleNatives_Constants.MN_IS_FIELD | field.getModifiers();
refKind = Modifier.isStatic(field.getModifiers()) ? Target_java_lang_invoke_MethodHandleNatives_Constants.REF_getStatic
: Target_java_lang_invoke_MethodHandleNatives_Constants.REF_getField;
} else if (member instanceof Method) {
Method method = (Method) member;
Object[] typeInfo = new Object[2];
typeInfo[0] = method.getReturnType();
typeInfo[1] = method.getParameterTypes();
type = typeInfo;
int mods = method.getModifiers();
flags = Target_java_lang_invoke_MethodHandleNatives_Constants.MN_IS_METHOD | mods;
if (Modifier.isStatic(mods)) {
refKind = Target_java_lang_invoke_MethodHandleNatives_Constants.REF_invokeStatic;
} else if (Modifier.isInterface(mods)) {
refKind = Target_java_lang_invoke_MethodHandleNatives_Constants.REF_invokeInterface;
} else {
refKind = Target_java_lang_invoke_MethodHandleNatives_Constants.REF_invokeVirtual;
}
} else if (member instanceof Constructor) {
Constructor<?> constructor = (Constructor<?>) member;
Object[] typeInfo = new Object[2];
typeInfo[0] = void.class;
typeInfo[1] = constructor.getParameterTypes();
type = typeInfo;
flags = Target_java_lang_invoke_MethodHandleNatives_Constants.MN_IS_CONSTRUCTOR | constructor.getModifiers();
refKind = Target_java_lang_invoke_MethodHandleNatives_Constants.REF_newInvokeSpecial;
} else {
throw new InternalError("unknown member type: " + member.getClass());
}
flags |= refKind << Target_java_lang_invoke_MethodHandleNatives_Constants.MN_REFERENCE_KIND_SHIFT;
self.init(member.getDeclaringClass(), member.getName(), type, flags);
self.reflectAccess = (Member) ref;
}
@Substitute
private static void expand(Target_java_lang_invoke_MemberName self) {
throw unsupportedFeature("MethodHandleNatives.expand()");
}
@Delete
private static native int getMembers(Class<?> defc, String matchName, String matchSig, int matchFlags, Class<?> caller, int skip, Target_java_lang_invoke_MemberName[] results);
@Substitute
private static long objectFieldOffset(Target_java_lang_invoke_MemberName self) {
if (self.reflectAccess == null && self.intrinsic == null) {
throw new InternalError("unresolved field");
}
if (!self.isField() || self.isStatic()) {
throw new InternalError("non-static field required");
}
if (self.intrinsic != null) {
return -1L;
}
return GraalUnsafeAccess.getUnsafe().objectFieldOffset((Field) self.reflectAccess);
}
@Substitute
private static long staticFieldOffset(Target_java_lang_invoke_MemberName self) {
if (!self.isField() || !self.isStatic()) {
throw new InternalError("static field required");
}
return 0L;
}
@Substitute
private static Object staticFieldBase(Target_java_lang_invoke_MemberName self) {
if (self.reflectAccess == null) {
throw new InternalError("unresolved field");
}
if (!self.isField() || !self.isStatic()) {
throw new InternalError("static field required");
}
return SubstrateUtil.cast(self.reflectAccess, Target_java_lang_reflect_Field.class).acquireFieldAccessor(false);
}
@Substitute
private static Object getMemberVMInfo(Target_java_lang_invoke_MemberName self) {
throw unsupportedFeature("MethodHandleNatives.getMemberVMInfo()");
}
@Delete
private static native void setCallSiteTargetNormal(CallSite site, MethodHandle target);
@Delete
private static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target);
@Delete
private static native void registerNatives();
@Delete
private static native int getNamedCon(int which, Object[] name);
@Delete
@TargetElement(onlyWith = JDK8OrEarlier.class)
private static native Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class<?> caller) throws LinkageError, ClassNotFoundException;
@Delete
@TargetElement(onlyWith = JDK8OrEarlier.class)
private static native int getConstant(int which);
@TargetElement(onlyWith = JDK11OrLater.class)
@Substitute
static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class<?> caller, boolean speculativeResolve) throws LinkageError, ClassNotFoundException {
if (self.reflectAccess != null) {
return self;
}
Class<?> declaringClass = self.getDeclaringClass();
if (declaringClass == null) {
return null;
}
self.intrinsic = MethodHandleIntrinsic.resolve(self);
if (self.intrinsic != null) {
self.flags |= self.intrinsic.variant.flags;
return self;
}
try {
if (self.isMethod()) {
Class<?>[] parameterTypes = self.getMethodType().parameterArray();
Method method = Util_java_lang_invoke_MethodHandleNatives.lookupMethod(declaringClass, self.name, parameterTypes);
if (method.getReturnType() != self.getMethodType().returnType()) {
throw new NoSuchMethodException(SubstrateUtil.cast(declaringClass, DynamicHub.class).methodToString(self.name, parameterTypes));
}
self.reflectAccess = method;
self.flags |= method.getModifiers();
} else if (self.isConstructor()) {
Constructor<?> constructor = declaringClass.getDeclaredConstructor(self.getMethodType().parameterArray());
self.reflectAccess = constructor;
self.flags |= constructor.getModifiers();
} else if (self.isField()) {
Field field = Util_java_lang_invoke_MethodHandleNatives.lookupField(declaringClass, self.name);
if (field.getType() != self.getFieldType()) {
throw new NoSuchFieldException(declaringClass.getName() + "." + self.name);
}
self.reflectAccess = field;
self.flags |= field.getModifiers();
}
return self;
} catch (NoSuchMethodException e) {
if (speculativeResolve) {
return null;
} else {
throw new NoSuchMethodError(e.getMessage());
}
} catch (NoSuchFieldException e) {
if (speculativeResolve) {
return null;
} else {
throw new NoSuchFieldError(e.getMessage());
}
}
}
@Delete
@TargetElement(onlyWith = JDK11OrLater.class)
private static native void copyOutBootstrapArguments(Class<?> caller, int[] indexInfo, int start, int end, Object[] buf, int pos, boolean resolve, Object ifNotAvailable);
@Substitute
@TargetElement(onlyWith = JDK11OrLater.class)
private static void clearCallSiteContext(Target_java_lang_invoke_MethodHandleNatives_CallSiteContext context) {
throw unimplemented("CallSiteContext not supported");
}
@AnnotateOriginal
static native boolean refKindIsMethod(byte refKind);
@AnnotateOriginal
static native String refKindName(byte refKind);
}
final class Util_java_lang_invoke_MethodHandleNatives {
static Method lookupMethod(Class<?> declaringClazz, String name, Class<?>[] parameterTypes) throws NoSuchMethodException {
return lookupMethod(declaringClazz, name, parameterTypes, null);
}
private static Method lookupMethod(Class<?> declaringClazz, String name, Class<?>[] parameterTypes, NoSuchMethodException originalException) throws NoSuchMethodException {
try {
return declaringClazz.getDeclaredMethod(name, parameterTypes);
} catch (NoSuchMethodException e) {
Class<?> superClass = declaringClazz.getSuperclass();
NoSuchMethodException newOriginalException = originalException == null ? e : originalException;
if (superClass == null) {
throw newOriginalException;
} else {
return lookupMethod(superClass, name, parameterTypes, newOriginalException);
}
}
}
static Field lookupField(Class<?> declaringClazz, String name) throws NoSuchFieldException {
return lookupField(declaringClazz, name, null);
}
private static Field lookupField(Class<?> declaringClazz, String name, NoSuchFieldException originalException) throws NoSuchFieldException {
try {
return declaringClazz.getDeclaredField(name);
} catch (NoSuchFieldException e) {
Class<?> superClass = declaringClazz.getSuperclass();
NoSuchFieldException newOriginalException = originalException == null ? e : originalException;
if (superClass == null) {
throw newOriginalException;
} else {
return lookupField(superClass, name, newOriginalException);
}
}
}
}
@TargetClass(className = "java.lang.invoke.MethodHandleNatives", innerClass = "Constants", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_MethodHandleNatives_Constants {
@Alias static int MN_IS_METHOD;
@Alias static int MN_IS_CONSTRUCTOR;
@Alias static int MN_IS_FIELD;
@Alias static int MN_IS_TYPE;
@Alias static int MN_CALLER_SENSITIVE;
@Alias static int MN_REFERENCE_KIND_SHIFT;
@Alias static int MN_REFERENCE_KIND_MASK;
@Alias static int MN_SEARCH_SUPERCLASSES;
@Alias static int MN_SEARCH_INTERFACES;
@Alias static byte REF_NONE;
@Alias static byte REF_getField;
@Alias static byte REF_getStatic;
@Alias static byte REF_putField;
@Alias static byte REF_putStatic;
@Alias static byte REF_invokeVirtual;
@Alias static byte REF_invokeStatic;
@Alias static byte REF_invokeSpecial;
@Alias static byte REF_newInvokeSpecial;
@Alias static byte REF_invokeInterface;
@Alias static byte REF_LIMIT;
}
@TargetClass(className = "java.lang.invoke.MethodHandleNatives", innerClass = "CallSiteContext", onlyWith = JDK11OrLater.class)
final class Target_java_lang_invoke_MethodHandleNatives_CallSiteContext {
}
@TargetClass(className = "java.lang.invoke.MethodHandleNatives", onlyWith = MethodHandlesNotSupported.class)
final class Target_java_lang_invoke_MethodHandleNatives_NotSupported {
@Delete
private static native void init(Target_java_lang_invoke_MemberName_NotSupported self, Object ref);
@Delete
private static native void expand(Target_java_lang_invoke_MemberName_NotSupported self);
@Delete
private static native int getMembers(Class<?> defc, String matchName, String matchSig, int matchFlags, Class<?> caller, int skip, Target_java_lang_invoke_MemberName_NotSupported[] results);
@Delete
private static native long objectFieldOffset(Target_java_lang_invoke_MemberName_NotSupported self);
@Delete
private static native long staticFieldOffset(Target_java_lang_invoke_MemberName_NotSupported self);
@Delete
private static native Object staticFieldBase(Target_java_lang_invoke_MemberName_NotSupported self);
@Delete
private static native Object getMemberVMInfo(Target_java_lang_invoke_MemberName_NotSupported self);
@Delete
private static native void setCallSiteTargetNormal(CallSite site, MethodHandle target);
@Delete
private static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target);
@Delete
private static native void registerNatives();
@Delete
private static native int getNamedCon(int which, Object[] name);
@Delete
@TargetElement(onlyWith = JDK8OrEarlier.class)
private static native Target_java_lang_invoke_MemberName_NotSupported resolve(Target_java_lang_invoke_MemberName_NotSupported self, Class<?> caller) throws LinkageError, ClassNotFoundException;
@Delete
@TargetElement(onlyWith = JDK8OrEarlier.class)
private static native int getConstant(int which);
@Delete
@TargetElement(onlyWith = JDK11OrLater.class)
private static native Target_java_lang_invoke_MemberName_NotSupported resolve(Target_java_lang_invoke_MemberName_NotSupported self, Class<?> caller, boolean speculativeResolve)
throws LinkageError, ClassNotFoundException;
@Delete
@TargetElement(onlyWith = JDK11OrLater.class)
private static native void copyOutBootstrapArguments(Class<?> caller, int[] indexInfo, int start, int end, Object[] buf, int pos, boolean resolve, Object ifNotAvailable);
@Delete
@TargetElement(onlyWith = JDK11OrLater.class)
private static native void clearCallSiteContext(Target_java_lang_invoke_MethodHandleNatives_CallSiteContext context);
}