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     static MethodType toMethodType(MethodHandles.Lookup l, FunctionType ft) throws ReflectiveOperationException {
 83         try {
 84             return MethodType.fromMethodDescriptorString(MethodRef.toNominalDescriptor(ft).descriptorString(),
 85                     l.lookupClass().getClassLoader());
 86         } catch (TypeNotPresentException ex) {
 87             throw (ClassNotFoundException) ex.getCause();
 88         }
 89     }
 90 
 91     // public API
 92 
 93     public static Class<?> resolveClass(MethodHandles.Lookup l, CodeType t) throws ReflectiveOperationException {
 94         if (t instanceof JavaType jt) {
 95             return (Class<?>)jt.erasure().resolve(l);
 96         } else {
 97             throw new UnsupportedOperationException();
 98         }
 99     }
100 
101     public static MethodType resolveMethodType(MethodHandles.Lookup l, FunctionType ft) throws ReflectiveOperationException {
102         return MethodRef.toNominalDescriptor(ft)
103                 .resolveConstantDesc(l);
104     }
105 
106     public static MethodHandle resolveMethod(MethodHandles.Lookup l, MethodRef methodRef, InvokeKind kind) throws ReflectiveOperationException {
107         Class<?> refC = resolveClass(l, methodRef.refType());
108         MethodType mt = toMethodType(l, methodRef.signature());
109         HandleResolver<MethodHandle, MethodType> resolver = switch (kind) {
110             case INSTANCE -> HandleResolver.FIND_VIRTUAL;
111             case STATIC -> HandleResolver.FIND_STATIC;
112             case SUPER -> HandleResolver.FIND_SPECIAL;
113         };
114         return resolveHandle(resolver, l, refC, methodRef.name(), mt).handle();
115     }
116 
117     public static MethodHandle resolveMethod(MethodHandles.Lookup l, MethodRef methodRef) throws ReflectiveOperationException {
118         Class<?> refC = resolveClass(l, methodRef.refType());
119         MethodType mt = toMethodType(l, methodRef.signature());
120         return resolveHandle(HandleResolver.FIND_STATIC, l, refC, methodRef.name(), mt)
121                 .orElse(() -> resolveHandle(HandleResolver.FIND_VIRTUAL, l, refC, methodRef.name(), mt))
122                 .handle();
123     }
124 
125     public static MethodHandle resolveFieldGetter(MethodHandles.Lookup l, FieldRef fieldRef) throws ReflectiveOperationException {
126         Class<?> refC = resolveClass(l, fieldRef.refType());
127         Class<?> ft = resolveClass(l, fieldRef.type());
128         return resolveHandle(HandleResolver.FIND_STATIC_GETTER, l, refC, fieldRef.name(), ft)
129                 .orElse(() -> resolveHandle(HandleResolver.FIND_GETTER, l, refC, fieldRef.name(), ft))
130                 .handle();
131     }
132 
133     public static VarHandle resolveFieldHandle(MethodHandles.Lookup l, FieldRef fieldRef) throws ReflectiveOperationException {
134         Class<?> refC = resolveClass(l, fieldRef.refType());
135         Class<?> ft = resolveClass(l, fieldRef.type());
136         return resolveHandle(HandleResolver.FIND_STATIC_VARHANDLE, l, refC, fieldRef.name(), ft)
137                 .orElse(() -> resolveHandle(HandleResolver.FIND_VARHANDLE, l, refC, fieldRef.name(), ft))
138                 .handle();
139     }
140 
141     public static MethodHandle resolveConstructor(MethodHandles.Lookup l, Class<?> refc, MethodType type) throws ReflectiveOperationException {
142         return resolveHandle(HandleResolver.FIND_CONSTRUCTOR, l, refc, null, type).handle();
143     }
144 }