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