1 /*
2 * Copyright (c) 2024, 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 hat.backend.ffi;
26
27 import java.lang.foreign.FunctionDescriptor;
28 import java.lang.foreign.Linker;
29 import java.lang.foreign.MemorySegment;
30 import java.lang.foreign.SymbolLookup;
31 import java.lang.invoke.MethodHandle;
32
33 import static java.lang.foreign.ValueLayout.ADDRESS;
34 import static java.lang.foreign.ValueLayout.JAVA_BOOLEAN;
35 import static java.lang.foreign.ValueLayout.JAVA_INT;
36 import static java.lang.foreign.ValueLayout.JAVA_LONG;
37
38 public class FFILib {
39 final public String name;
40 public final boolean available;
41
42 final public Linker nativeLinker;
43
44 final public SymbolLookup loaderLookup;
45
46 public static class MethodPtr{
47 final FFILib ffiLib;
48 final FunctionDescriptor functionDescriptor;
49 final MethodHandle mh;
50 final String name;
51
52 MethodPtr(FFILib ffiLib, FunctionDescriptor descriptor, String name) {
53 this.ffiLib = ffiLib;
54 this.functionDescriptor= descriptor;
55 this.mh = ffiLib.loaderLookup.find(name)
56 .map(symbolSegment -> ffiLib.nativeLinker.downcallHandle(symbolSegment, descriptor))
57 .orElse(null);
58 if (this.mh == null) {
59 System.err.println("Could not find method " + name + " in " + ffiLib.name);
60 }
61 this.name = name;
62 }
63
64 }
65
66 public static class VoidAddressMethodPtr extends MethodPtr{
67 VoidAddressMethodPtr(FFILib ffiLib, String name) {
68 super(ffiLib,FunctionDescriptor.ofVoid(ADDRESS), name);
69 }
70 public void invoke(MemorySegment memorySegment) {
71 if (mh == null){
72 throw new RuntimeException("Null methodhandle "+name);
73 }
74 try {
75 mh.invoke(memorySegment);
76 } catch (Throwable e) {
77 throw new RuntimeException(e);
78 }
79 }
80 }
81
82 public static class VoidHandleMethodPtr extends MethodPtr{
83 VoidHandleMethodPtr(FFILib ffiLib, String name) {
84 super(ffiLib, FunctionDescriptor.ofVoid(JAVA_LONG), name);
85 }
86 public void invoke(long handle) {
87 if (mh == null){
88 throw new RuntimeException("Null methodhandle "+name);
89 }
90 if (handle == 0) {
91 throw new RuntimeException("handle is zero");
92 }
93 try {
94 mh.invoke(handle);
95 } catch (Throwable e) {
96 throw new RuntimeException(e);
97 }
98 }
99 }
100
101 public static class BooleanHandleMethodPtr extends MethodPtr{
102 BooleanHandleMethodPtr(FFILib ffiLib, String name) {
103 super(ffiLib, FunctionDescriptor.of(JAVA_BOOLEAN,JAVA_LONG),name);
104 }
105 public boolean invoke(long handle) {
106 if (mh == null){
107 throw new RuntimeException("Null methodhandle "+name);
108 }
109 if (handle == 0L) {
110 throw new IllegalArgumentException("handle is zero");
111 }
112 try {
113 return (boolean)mh.invoke(handle);
114 } catch (Throwable e) {
115 throw new RuntimeException(e);
116 }
117 }
118 }
119
120 public static class BooleanHandleAddressLongMethodPtr extends MethodPtr{
121 BooleanHandleAddressLongMethodPtr(FFILib ffiLib, String name) {
122 super(ffiLib, FunctionDescriptor.of(JAVA_BOOLEAN,JAVA_LONG,ADDRESS,JAVA_LONG), name);
123 }
124 public boolean invoke(long handle,MemorySegment memorySegment, long len) {
125 if (mh == null){
126 throw new RuntimeException("Null methodhandle "+name);
127 }
128 if (handle == 0L) {
129 throw new IllegalArgumentException("handle is zero");
130 }
131 try {
132 return (boolean)mh.invoke(handle, memorySegment, len);
133 } catch (Throwable e) {
134 throw new RuntimeException(e);
135 }
136 }
137 }
138
139 public static class LongHandleIntAddressMethodPtr extends MethodPtr{
140 LongHandleIntAddressMethodPtr(FFILib ffiLib, String name) {
141 super(ffiLib, FunctionDescriptor.of(JAVA_LONG,JAVA_LONG,JAVA_INT,ADDRESS), name);
142 }
143 public long invoke(long handle, int i, MemorySegment memorySegment) {
144 if (mh == null){
145 throw new RuntimeException("Null methodhandle "+name);
146 }
147 if (handle == 0L) {
148 throw new IllegalArgumentException("handle is zero");
149 }
150 try {
151 return (long)mh.invoke(handle, i, memorySegment);
152 } catch (Throwable e) {
153 throw new RuntimeException(e);
154 }
155 }
156 }
157
158 public static class LongHandleIntMethodPtr extends MethodPtr{
159 LongHandleIntMethodPtr(FFILib ffiLib, String name) {
160 super(ffiLib,FunctionDescriptor.of(JAVA_LONG,JAVA_INT), name);
161 }
162 public long invoke( int i) {
163 if (mh == null){
164 throw new RuntimeException("Null method handle trying to invoke "+ffiLib.name+"::"+name+"()");
165 }
166 try {
167 return (long)mh.invoke(i);
168 } catch (Throwable e) {
169 throw new RuntimeException(e);
170 }
171 }
172 }
173
174 public static class LongHandleLongAddressMethodPtr extends MethodPtr{
175 LongHandleLongAddressMethodPtr(FFILib ffiLib, String name) {
176 super(ffiLib,FunctionDescriptor.of(JAVA_LONG,JAVA_LONG,ADDRESS), name);
177 }
178 public long invoke(long l, MemorySegment memorySegment) {
179 if (mh == null){
180 throw new RuntimeException("Null methodhandle "+name);
181 }
182 try {
183 return (long)mh.invoke(l, memorySegment);
184 } catch (Throwable e) {
185 throw new RuntimeException(e);
186 }
187 }
188 }
189
190 public FFILib(String name) {
191 this.name = name;
192
193 boolean nonFinalAvailable = true;
194 try {
195 Runtime.getRuntime().loadLibrary(name);
196 } catch (UnsatisfiedLinkError e) {
197 nonFinalAvailable = false;
198 }
199 this.available = nonFinalAvailable;
200 this.nativeLinker = Linker.nativeLinker();
201 this.loaderLookup = SymbolLookup.loaderLookup();
202 }
203
204
205 public VoidAddressMethodPtr voidAddressFunc(String name) {
206 return new VoidAddressMethodPtr(this, name);
207 }
208
209 public VoidHandleMethodPtr voidHandleFunc(String name) {
210 return new VoidHandleMethodPtr(this, name);
211 }
212 public BooleanHandleMethodPtr booleanHandleFunc(String name) {
213 return new BooleanHandleMethodPtr(this, name);
214 }
215 public BooleanHandleAddressLongMethodPtr booleanHandleAddressLongFunc(String name) {
216 return new BooleanHandleAddressLongMethodPtr(this, name);
217 }
218 public LongHandleIntAddressMethodPtr longHandleIntAddressFunc(String name) {
219 return new LongHandleIntAddressMethodPtr(this, name);
220 }
221 public LongHandleIntMethodPtr longHandleIntFunc(String name) {
222 return new LongHandleIntMethodPtr(this, name);
223 }
224 public LongHandleLongAddressMethodPtr longHandleLongAddressFunc(String name) {
225 return new LongHandleLongAddressMethodPtr(this, name);
226 }
227
228 }