1 package jdk.incubator.code.dialect.java.impl;
  2 
  3 import jdk.incubator.code.TypeElement;
  4 import jdk.incubator.code.dialect.core.FunctionType;
  5 import jdk.incubator.code.dialect.java.FieldRef;
  6 import jdk.incubator.code.dialect.java.JavaOp.InvokeOp.InvokeKind;
  7 import jdk.incubator.code.dialect.java.JavaType;
  8 import jdk.incubator.code.dialect.java.MethodRef;
  9 
 10 import java.lang.constant.Constable;
 11 import java.lang.invoke.MethodHandle;
 12 import java.lang.invoke.MethodHandles;
 13 import java.lang.invoke.MethodHandles.Lookup;
 14 import java.lang.invoke.MethodType;
 15 import java.lang.invoke.TypeDescriptor;
 16 import java.lang.invoke.VarHandle;
 17 import java.util.NoSuchElementException;
 18 import java.util.function.Supplier;
 19 
 20 public class ResolutionHelper {
 21     interface HandleResolver<X extends Constable, T extends TypeDescriptor> {
 22         X resolve(Lookup lookup, Class<?> refc, String name, T type) throws ReflectiveOperationException;
 23 
 24         HandleResolver<MethodHandle, MethodType> FIND_STATIC = MethodHandles.Lookup::findStatic;
 25         HandleResolver<MethodHandle, MethodType> FIND_VIRTUAL = MethodHandles.Lookup::findVirtual;
 26         HandleResolver<MethodHandle, MethodType> FIND_SPECIAL = (l, refc, name, type) -> l.findSpecial(refc, name, type, l.lookupClass());
 27         HandleResolver<MethodHandle, MethodType> FIND_CONSTRUCTOR = (l, refc, name, type) -> l.findConstructor(refc, type);
 28         HandleResolver<MethodHandle, Class<?>> FIND_STATIC_GETTER = MethodHandles.Lookup::findStaticGetter;
 29         HandleResolver<MethodHandle, Class<?>> FIND_GETTER = MethodHandles.Lookup::findGetter;
 30         HandleResolver<VarHandle, Class<?>> FIND_STATIC_VARHANDLE = MethodHandles.Lookup::findStaticVarHandle;
 31         HandleResolver<VarHandle, Class<?>> FIND_VARHANDLE = MethodHandles.Lookup::findVarHandle;
 32     }
 33 
 34     sealed interface Result<H extends Constable> {
 35         H handle() throws ReflectiveOperationException;
 36 
 37         default Result<H> orElse(Supplier<Result<H>> resultSupplier) {
 38             if (this instanceof Success<?>) return this;
 39             else return resultSupplier.get();
 40         }
 41     }
 42     record Success<H extends Constable>(H handle) implements Result<H> { }
 43     record Failure<H extends Constable>(ReflectiveOperationException error) implements Result<H> {
 44         @Override
 45         public H handle() throws ReflectiveOperationException {
 46             throw error;
 47         }
 48     }
 49 
 50     static <Z extends Constable, T extends TypeDescriptor> Result<Z> resolveHandle(HandleResolver<Z, T> resolver, MethodHandles.Lookup l, Class<?> refc, String name, T type) {
 51         try {
 52             Z res = resolver.resolve(l, refc, name, type);
 53             return new Success<>(res);
 54         } catch (ReflectiveOperationException ex) {
 55             return new Failure<>(ex);
 56         }
 57     }
 58 
 59     // public API
 60 
 61     public static Class<?> resolveClass(MethodHandles.Lookup l, TypeElement t) throws ReflectiveOperationException {
 62         if (t instanceof JavaType jt) {
 63             return (Class<?>)jt.erasure().resolve(l);
 64         } else {
 65             throw new UnsupportedOperationException();
 66         }
 67     }
 68 
 69     public static MethodType resolveMethodType(MethodHandles.Lookup l, FunctionType ft) throws ReflectiveOperationException {
 70         return MethodRef.toNominalDescriptor(ft)
 71                 .resolveConstantDesc(l);
 72     }
 73 
 74     public static MethodHandle resolveMethod(MethodHandles.Lookup l, MethodRef methodRef, InvokeKind kind) throws ReflectiveOperationException {
 75         Class<?> refC = resolveClass(l, methodRef.refType());
 76         MethodType mt = resolveMethodType(l, methodRef.type());
 77         HandleResolver<MethodHandle, MethodType> resolver = switch (kind) {
 78             case INSTANCE -> HandleResolver.FIND_VIRTUAL;
 79             case STATIC -> HandleResolver.FIND_STATIC;
 80             case SUPER -> HandleResolver.FIND_SPECIAL;
 81         };
 82         return resolveHandle(resolver, l, refC, methodRef.name(), mt).handle();
 83     }
 84 
 85     public static MethodHandle resolveMethod(MethodHandles.Lookup l, MethodRef methodRef) throws ReflectiveOperationException {
 86         Class<?> refC = resolveClass(l, methodRef.refType());
 87         MethodType mt = resolveMethodType(l, methodRef.type());
 88         return resolveHandle(HandleResolver.FIND_STATIC, l, refC, methodRef.name(), mt)
 89                 .orElse(() -> resolveHandle(HandleResolver.FIND_VIRTUAL, l, refC, methodRef.name(), mt))
 90                 .handle();
 91     }
 92 
 93     public static MethodHandle resolveFieldGetter(MethodHandles.Lookup l, FieldRef fieldRef) throws ReflectiveOperationException {
 94         Class<?> refC = resolveClass(l, fieldRef.refType());
 95         Class<?> ft = resolveClass(l, fieldRef.type());
 96         return resolveHandle(HandleResolver.FIND_STATIC_GETTER, l, refC, fieldRef.name(), ft)
 97                 .orElse(() -> resolveHandle(HandleResolver.FIND_GETTER, l, refC, fieldRef.name(), ft))
 98                 .handle();
 99     }
100 
101     public static VarHandle resolveFieldHandle(MethodHandles.Lookup l, FieldRef fieldRef) throws ReflectiveOperationException {
102         Class<?> refC = resolveClass(l, fieldRef.refType());
103         Class<?> ft = resolveClass(l, fieldRef.type());
104         return resolveHandle(HandleResolver.FIND_STATIC_VARHANDLE, l, refC, fieldRef.name(), ft)
105                 .orElse(() -> resolveHandle(HandleResolver.FIND_VARHANDLE, l, refC, fieldRef.name(), ft))
106                 .handle();
107     }
108 
109     public static MethodHandle resolveConstructor(MethodHandles.Lookup l, Class<?> refc, MethodType type) throws ReflectiveOperationException {
110         return resolveHandle(HandleResolver.FIND_CONSTRUCTOR, l, refc, null, type).handle();
111     }
112 }