1 /*
  2  * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.incubator.code.dialect.java.impl;
 26 
 27 import jdk.incubator.code.CodeType;
 28 import jdk.incubator.code.dialect.core.FunctionType;
 29 import jdk.incubator.code.dialect.java.FieldRef;
 30 import jdk.incubator.code.dialect.java.JavaOp.InvokeOp.InvokeKind;
 31 import jdk.incubator.code.dialect.java.JavaType;
 32 import jdk.incubator.code.dialect.java.MethodRef;
 33 
 34 import java.lang.constant.Constable;
 35 import java.lang.invoke.MethodHandle;
 36 import java.lang.invoke.MethodHandles;
 37 import java.lang.invoke.MethodHandles.Lookup;
 38 import java.lang.invoke.MethodType;
 39 import java.lang.invoke.TypeDescriptor;
 40 import java.lang.invoke.VarHandle;
 41 import java.util.function.Supplier;
 42 
 43 public class ResolutionHelper {
 44     interface HandleResolver<X extends Constable, T extends TypeDescriptor> {
 45         X resolve(Lookup lookup, Class<?> refc, String name, T type) throws ReflectiveOperationException;
 46 
 47         HandleResolver<MethodHandle, MethodType> FIND_STATIC = MethodHandles.Lookup::findStatic;
 48         HandleResolver<MethodHandle, MethodType> FIND_VIRTUAL = MethodHandles.Lookup::findVirtual;
 49         HandleResolver<MethodHandle, MethodType> FIND_SPECIAL = (l, refc, name, type) -> l.findSpecial(refc, name, type, l.lookupClass());
 50         HandleResolver<MethodHandle, MethodType> FIND_CONSTRUCTOR = (l, refc, name, type) -> l.findConstructor(refc, type);
 51         HandleResolver<MethodHandle, Class<?>> FIND_STATIC_GETTER = MethodHandles.Lookup::findStaticGetter;
 52         HandleResolver<MethodHandle, Class<?>> FIND_GETTER = MethodHandles.Lookup::findGetter;
 53         HandleResolver<VarHandle, Class<?>> FIND_STATIC_VARHANDLE = MethodHandles.Lookup::findStaticVarHandle;
 54         HandleResolver<VarHandle, Class<?>> FIND_VARHANDLE = MethodHandles.Lookup::findVarHandle;
 55     }
 56 
 57     sealed interface Result<H extends Constable> {
 58         H handle() throws ReflectiveOperationException;
 59 
 60         default Result<H> orElse(Supplier<Result<H>> resultSupplier) {
 61             if (this instanceof Success<?>) return this;
 62             else return resultSupplier.get();
 63         }
 64     }
 65     record Success<H extends Constable>(H handle) implements Result<H> { }
 66     record Failure<H extends Constable>(ReflectiveOperationException error) implements Result<H> {
 67         @Override
 68         public H handle() throws ReflectiveOperationException {
 69             throw error;
 70         }
 71     }
 72 
 73     static <Z extends Constable, T extends TypeDescriptor> Result<Z> resolveHandle(HandleResolver<Z, T> resolver, MethodHandles.Lookup l, Class<?> refc, String name, T type) {
 74         try {
 75             Z res = resolver.resolve(l, refc, name, type);
 76             return new Success<>(res);
 77         } catch (ReflectiveOperationException ex) {
 78             return new Failure<>(ex);
 79         }
 80     }
 81 
 82     // public API
 83 
 84     public static Class<?> resolveClass(MethodHandles.Lookup l, CodeType t) throws ReflectiveOperationException {
 85         if (t instanceof JavaType jt) {
 86             return (Class<?>)jt.erasure().resolve(l);
 87         } else {
 88             throw new UnsupportedOperationException();
 89         }
 90     }
 91 
 92     public static MethodType resolveMethodType(MethodHandles.Lookup l, FunctionType ft) throws ReflectiveOperationException {
 93         return MethodRef.toNominalDescriptor(ft)
 94                 .resolveConstantDesc(l);
 95     }
 96 
 97     public static MethodHandle resolveMethod(MethodHandles.Lookup l, MethodRef methodRef, InvokeKind kind) throws ReflectiveOperationException {
 98         Class<?> refC = resolveClass(l, methodRef.refType());
 99         MethodType mt = resolveMethodType(l, methodRef.signature());
100         HandleResolver<MethodHandle, MethodType> resolver = switch (kind) {
101             case INSTANCE -> HandleResolver.FIND_VIRTUAL;
102             case STATIC -> HandleResolver.FIND_STATIC;
103             case SUPER -> HandleResolver.FIND_SPECIAL;
104         };
105         return resolveHandle(resolver, l, refC, methodRef.name(), mt).handle();
106     }
107 
108     public static MethodHandle resolveMethod(MethodHandles.Lookup l, MethodRef methodRef) throws ReflectiveOperationException {
109         Class<?> refC = resolveClass(l, methodRef.refType());
110         MethodType mt = resolveMethodType(l, methodRef.signature());
111         return resolveHandle(HandleResolver.FIND_STATIC, l, refC, methodRef.name(), mt)
112                 .orElse(() -> resolveHandle(HandleResolver.FIND_VIRTUAL, l, refC, methodRef.name(), mt))
113                 .handle();
114     }
115 
116     public static MethodHandle resolveFieldGetter(MethodHandles.Lookup l, FieldRef fieldRef) throws ReflectiveOperationException {
117         Class<?> refC = resolveClass(l, fieldRef.refType());
118         Class<?> ft = resolveClass(l, fieldRef.type());
119         return resolveHandle(HandleResolver.FIND_STATIC_GETTER, l, refC, fieldRef.name(), ft)
120                 .orElse(() -> resolveHandle(HandleResolver.FIND_GETTER, l, refC, fieldRef.name(), ft))
121                 .handle();
122     }
123 
124     public static VarHandle resolveFieldHandle(MethodHandles.Lookup l, FieldRef fieldRef) throws ReflectiveOperationException {
125         Class<?> refC = resolveClass(l, fieldRef.refType());
126         Class<?> ft = resolveClass(l, fieldRef.type());
127         return resolveHandle(HandleResolver.FIND_STATIC_VARHANDLE, l, refC, fieldRef.name(), ft)
128                 .orElse(() -> resolveHandle(HandleResolver.FIND_VARHANDLE, l, refC, fieldRef.name(), ft))
129                 .handle();
130     }
131 
132     public static MethodHandle resolveConstructor(MethodHandles.Lookup l, Class<?> refc, MethodType type) throws ReflectiveOperationException {
133         return resolveHandle(HandleResolver.FIND_CONSTRUCTOR, l, refc, null, type).handle();
134     }
135 }