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 }