1 /*
  2  * Copyright (c) 2023, 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.internal.foreign.abi.fallback;
 26 
 27 import jdk.internal.foreign.abi.SharedUtils;
 28 
 29 import java.lang.foreign.Arena;
 30 import java.lang.foreign.MemorySegment;
 31 import java.lang.invoke.MethodHandle;
 32 import java.lang.invoke.MethodType;
 33 
 34 final class LibFallback {
 35     private LibFallback() {}
 36 
 37     static final boolean SUPPORTED = tryLoadLibrary();
 38 
 39     @SuppressWarnings("removal")
 40     private static boolean tryLoadLibrary() {
 41         return java.security.AccessController.doPrivileged(
 42                 new java.security.PrivilegedAction<>() {
 43                     public Boolean run() {
 44                         try {
 45                             System.loadLibrary("fallbackLinker");
 46                             init();
 47                             return true;
 48                         } catch (UnsatisfiedLinkError ule) {
 49                             return false;
 50                         }
 51                     }
 52                 });
 53     }
 54 
 55     static int defaultABI() { return NativeConstants.DEFAULT_ABI; }
 56 
 57     static MemorySegment uint8Type() { return NativeConstants.UINT8_TYPE; }
 58     static MemorySegment sint8Type() { return NativeConstants.SINT8_TYPE; }
 59     static MemorySegment uint16Type() { return NativeConstants.UINT16_TYPE; }
 60     static MemorySegment sint16Type() { return NativeConstants.SINT16_TYPE; }
 61     static MemorySegment sint32Type() { return NativeConstants.SINT32_TYPE; }
 62     static MemorySegment sint64Type() { return NativeConstants.SINT64_TYPE; }
 63     static MemorySegment floatType() { return NativeConstants.FLOAT_TYPE; }
 64     static MemorySegment doubleType() { return NativeConstants.DOUBLE_TYPE; }
 65     static MemorySegment pointerType() { return NativeConstants.POINTER_TYPE; }
 66     static MemorySegment voidType() { return NativeConstants.VOID_TYPE; }
 67 
 68     // platform-dependent types
 69     static int shortSize() { return NativeConstants.SIZEOF_SHORT; }
 70     static int intSize() { return NativeConstants.SIZEOF_INT; }
 71     static int longSize() {return NativeConstants.SIZEOF_LONG; }
 72     static int wcharSize() {return NativeConstants.SIZEOF_WCHAR; }
 73 
 74     static short structTag() { return NativeConstants.STRUCT_TAG; }
 75 
 76     private static final MethodType UPCALL_TARGET_TYPE = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class);
 77 
 78     /**
 79      * Do a libffi based downcall. This method wraps the {@code ffi_call} function
 80      *
 81      * @param cif a pointer to a {@code ffi_cif} struct
 82      * @param target the address of the target function
 83      * @param retPtr a pointer to a buffer into which the return value shall be written, or {@code null} if the target
 84      *               function does not return a value
 85      * @param argPtrs a pointer to an array of pointers, which each point to an argument value
 86      * @param capturedState a pointer to a buffer into which captured state is written, or {@code null} if no state is
 87      *                      to be captured
 88      * @param capturedStateMask the bit mask indicating which state to capture
 89      *
 90      * @see jdk.internal.foreign.abi.CapturableState
 91      */
 92     static void doDowncall(MemorySegment cif, MemorySegment target, MemorySegment retPtr, MemorySegment argPtrs,
 93                                   MemorySegment capturedState, int capturedStateMask) {
 94             doDowncall(cif.address(), target.address(),
 95                     retPtr == null ? 0 : retPtr.address(), argPtrs.address(),
 96                     capturedState == null ? 0 : capturedState.address(), capturedStateMask);
 97     }
 98 
 99     /**
100      * Wrapper for {@code ffi_prep_cif}
101      *
102      * @param returnType a pointer to an @{code ffi_type} describing the return type
103      * @param numArgs the number of arguments
104      * @param paramTypes a pointer to an array of pointers, which each point to an {@code ffi_type} describing a
105      *                parameter type
106      * @param abi the abi to be used
107      * @param scope the scope into which to allocate the returned {@code ffi_cif} struct
108      * @return a pointer to a prepared {@code ffi_cif} struct
109      *
110      * @throws IllegalStateException if the call to {@code ffi_prep_cif} returns a non-zero status code
111      */
112     static MemorySegment prepCif(MemorySegment returnType, int numArgs, MemorySegment paramTypes, FFIABI abi,
113                                          Arena scope) throws IllegalStateException {
114         MemorySegment cif = scope.allocate(NativeConstants.SIZEOF_CIF);
115         checkStatus(ffi_prep_cif(cif.address(), abi.value(), numArgs, returnType.address(), paramTypes.address()));
116         return cif;
117     }
118 
119     /**
120      * Wrapper for {@code ffi_prep_cif_var}. The variadic version of prep_cif
121      *
122      * @param returnType a pointer to an @{code ffi_type} describing the return type
123      * @param numFixedArgs the number of fixed arguments
124      * @param numTotalArgs the number of total arguments
125      * @param paramTypes a pointer to an array of pointers, which each point to an {@code ffi_type} describing a
126      *                parameter type
127      * @param abi the abi to be used
128      * @param scope the scope into which to allocate the returned {@code ffi_cif} struct
129      * @return a pointer to a prepared {@code ffi_cif} struct
130      *
131      * @throws IllegalStateException if the call to {@code ffi_prep_cif} returns a non-zero status code
132      */
133     static MemorySegment prepCifVar(MemorySegment returnType, int numFixedArgs, int numTotalArgs, MemorySegment paramTypes, FFIABI abi,
134                                     Arena scope) throws IllegalStateException {
135         MemorySegment cif = scope.allocate(NativeConstants.SIZEOF_CIF);
136         checkStatus(ffi_prep_cif_var(cif.address(), abi.value(), numFixedArgs, numTotalArgs, returnType.address(), paramTypes.address()));
137         return cif;
138     }
139 
140     /**
141      * Create an upcallStub-style closure. This method wraps the {@code ffi_closure_alloc}
142      * and {@code ffi_prep_closure_loc} functions.
143      * <p>
144      * The closure will end up calling into {@link #doUpcall(long, long, MethodHandle)}
145      * <p>
146      * The target method handle should have the type {@code (MemorySegment, MemorySegment) -> void}. The first
147      * argument is a pointer to the buffer into which the native return value should be written. The second argument
148      * is a pointer to an array of pointers, which each point to a native argument value.
149      *
150      * @param cif a pointer to a {@code ffi_cif} struct
151      * @param target a method handle that points to the target function
152      * @param arena the scope to which to attach the created upcall stub
153      * @return the created upcall stub
154      *
155      * @throws IllegalStateException if the call to {@code ffi_prep_closure_loc} returns a non-zero status code
156      * @throws IllegalArgumentException if {@code target} does not have the right type
157      */
158     static MemorySegment createClosure(MemorySegment cif, MethodHandle target, Arena arena)
159             throws IllegalStateException, IllegalArgumentException {
160         if (target.type() != UPCALL_TARGET_TYPE) {
161             throw new IllegalArgumentException("Target handle has wrong type: " + target.type() + " != " + UPCALL_TARGET_TYPE);
162         }
163 
164         long[] ptrs = new long[3];
165         checkStatus(createClosure(cif.address(), target, ptrs));
166         long closurePtr = ptrs[0];
167         long execPtr = ptrs[1];
168         long globalTarget = ptrs[2];
169 
170         return MemorySegment.ofAddress(execPtr).reinterpret(arena, unused -> freeClosure(closurePtr, globalTarget));
171     }
172 
173     // the target function for a closure call
174     private static void doUpcall(long retPtr, long argPtrs, MethodHandle target) {
175         try {
176             target.invokeExact(MemorySegment.ofAddress(retPtr), MemorySegment.ofAddress(argPtrs));
177         } catch (Throwable t) {
178             SharedUtils.handleUncaughtException(t);
179         }
180     }
181 
182     /**
183      * Wrapper for {@code ffi_get_struct_offsets}
184      *
185      * @param structType a pointer to an {@code ffi_type} representing a struct
186      * @param offsetsOut a pointer to an array of {@code size_t}, with one element for each element of the struct.
187      *                   This is an 'out' parameter that will be filled in by this call
188      * @param abi the abi to be used
189      *
190      * @throws IllegalStateException if the call to {@code ffi_get_struct_offsets} returns a non-zero status code
191      */
192     static void getStructOffsets(MemorySegment structType, MemorySegment offsetsOut, FFIABI abi)
193             throws IllegalStateException {
194         checkStatus(ffi_get_struct_offsets(abi.value(), structType.address(), offsetsOut.address()));
195     }
196 
197     private static void checkStatus(int code) {
198         FFIStatus status = FFIStatus.of(code);
199         if (status != FFIStatus.FFI_OK) {
200             throw new IllegalStateException("libffi call failed with status: " + status);
201         }
202     }
203 
204     private static native void init();
205 
206     private static native long sizeofCif();
207 
208     private static native int createClosure(long cif, Object userData, long[] ptrs);
209     private static native void freeClosure(long closureAddress, long globalTarget);
210     private static native void doDowncall(long cif, long fn, long rvalue, long avalues, long capturedState, int capturedStateMask);
211 
212     private static native int ffi_prep_cif(long cif, int abi, int nargs, long rtype, long atypes);
213     private static native int ffi_prep_cif_var(long cif, int abi, int nfixedargs, int ntotalargs, long rtype, long atypes);
214     private static native int ffi_get_struct_offsets(int abi, long type, long offsets);
215 
216     private static native int ffi_default_abi();
217     private static native short ffi_type_struct();
218 
219     private static native long ffi_type_void();
220     private static native long ffi_type_uint8();
221     private static native long ffi_type_sint8();
222     private static native long ffi_type_uint16();
223     private static native long ffi_type_sint16();
224     private static native long ffi_type_uint32();
225     private static native long ffi_type_sint32();
226     private static native long ffi_type_uint64();
227     private static native long ffi_type_sint64();
228     private static native long ffi_type_float();
229     private static native long ffi_type_double();
230     private static native long ffi_type_pointer();
231     private static native int ffi_sizeof_short();
232     private static native int ffi_sizeof_int();
233     private static native int ffi_sizeof_long();
234     private static native int ffi_sizeof_wchar();
235 
236     // put these in a separate class to avoid an UnsatisfiedLinkError
237     // when LibFallback is initialized but the library is not present
238     private static final class NativeConstants {
239         private NativeConstants() {}
240 
241         static final int DEFAULT_ABI = ffi_default_abi();
242 
243         static final MemorySegment UINT8_TYPE = MemorySegment.ofAddress(ffi_type_uint8());
244         static final MemorySegment SINT8_TYPE = MemorySegment.ofAddress(ffi_type_sint8());
245         static final MemorySegment UINT16_TYPE = MemorySegment.ofAddress(ffi_type_uint16());
246         static final MemorySegment SINT16_TYPE = MemorySegment.ofAddress(ffi_type_sint16());
247         static final MemorySegment SINT32_TYPE = MemorySegment.ofAddress(ffi_type_sint32());
248         static final MemorySegment SINT64_TYPE = MemorySegment.ofAddress(ffi_type_sint64());
249         static final MemorySegment FLOAT_TYPE = MemorySegment.ofAddress(ffi_type_float());
250         static final MemorySegment DOUBLE_TYPE = MemorySegment.ofAddress(ffi_type_double());
251         static final MemorySegment POINTER_TYPE = MemorySegment.ofAddress(ffi_type_pointer());
252         static final int SIZEOF_SHORT = ffi_sizeof_short();
253         static final int SIZEOF_INT = ffi_sizeof_int();
254         static final int SIZEOF_LONG = ffi_sizeof_long();
255         static final int SIZEOF_WCHAR = ffi_sizeof_wchar();
256 
257 
258         static final MemorySegment VOID_TYPE = MemorySegment.ofAddress(ffi_type_void());
259         static final short STRUCT_TAG = ffi_type_struct();
260         static final long SIZEOF_CIF = sizeofCif();
261     }
262 }