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 
 26 #include "jdk_internal_foreign_abi_fallback_LibFallback.h"
 27 
 28 #include <ffi.h>
 29 
 30 #include <errno.h>
 31 #include <stdint.h>
 32 #ifdef _WIN64
 33 #include <Windows.h>
 34 #include <Winsock2.h>
 35 #endif
 36 
 37 #include "jlong.h"
 38 
 39 static JavaVM* VM;
 40 static jclass LibFallback_class;
 41 static jmethodID LibFallback_doUpcall_ID;
 42 static const char* LibFallback_doUpcall_sig = "(JJLjava/lang/invoke/MethodHandle;)V";
 43 
 44 JNIEXPORT void JNICALL
 45 Java_jdk_internal_foreign_abi_fallback_LibFallback_init(JNIEnv* env, jclass cls) {
 46   (*env)->GetJavaVM(env, &VM);
 47   LibFallback_class = (*env)->FindClass(env, "jdk/internal/foreign/abi/fallback/LibFallback");
 48   LibFallback_doUpcall_ID = (*env)->GetStaticMethodID(env,
 49     LibFallback_class, "doUpcall", LibFallback_doUpcall_sig);
 50 }
 51 
 52 JNIEXPORT jlong JNICALL
 53 Java_jdk_internal_foreign_abi_fallback_LibFallback_sizeofCif(JNIEnv* env, jclass cls) {
 54   return sizeof(ffi_cif);
 55 }
 56 
 57 JNIEXPORT jint JNICALL
 58 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1prep_1cif(JNIEnv* env, jclass cls, jlong cif, jint abi, jint nargs, jlong rtype, jlong atypes) {
 59   return ffi_prep_cif(jlong_to_ptr(cif), (ffi_abi) abi, (unsigned int) nargs, jlong_to_ptr(rtype), jlong_to_ptr(atypes));
 60 }
 61 JNIEXPORT jint JNICALL
 62 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1prep_1cif_1var(JNIEnv* env, jclass cls, jlong cif, jint abi, jint nfixedargs, jint ntotalargs, jlong rtype, jlong atypes) {
 63   return ffi_prep_cif_var(jlong_to_ptr(cif), (ffi_abi) abi, (unsigned int) nfixedargs, (unsigned int) ntotalargs, jlong_to_ptr(rtype), jlong_to_ptr(atypes));
 64 }
 65 JNIEXPORT jint JNICALL
 66 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1get_1struct_1offsets(JNIEnv* env, jclass cls, jint abi, jlong type, jlong offsets) {
 67   return ffi_get_struct_offsets((ffi_abi) abi, jlong_to_ptr(type), jlong_to_ptr(offsets));
 68 }
 69 
 70 static void do_capture_state(int32_t* value_ptr, int captured_state_mask) {
 71     // keep in synch with jdk.internal.foreign.abi.CapturableState
 72   enum PreservableValues {
 73     NONE = 0,
 74     GET_LAST_ERROR = 1,
 75     WSA_GET_LAST_ERROR = 1 << 1,
 76     ERRNO = 1 << 2
 77   };
 78 #ifdef _WIN64
 79   if (captured_state_mask & GET_LAST_ERROR) {
 80     *value_ptr = GetLastError();
 81   }
 82   value_ptr++;
 83   if (captured_state_mask & WSA_GET_LAST_ERROR) {
 84     *value_ptr = WSAGetLastError();
 85   }
 86   value_ptr++;
 87 #endif
 88   if (captured_state_mask & ERRNO) {
 89     *value_ptr = errno;
 90   }
 91 }
 92 
 93 JNIEXPORT void JNICALL
 94 Java_jdk_internal_foreign_abi_fallback_LibFallback_doDowncall(JNIEnv* env, jclass cls, jlong cif, jlong fn, jlong rvalue, jlong avalues, jlong jcaptured_state, jint captured_state_mask) {
 95   ffi_call(jlong_to_ptr(cif), jlong_to_ptr(fn), jlong_to_ptr(rvalue), jlong_to_ptr(avalues));
 96 
 97   if (captured_state_mask != 0) {
 98     int32_t* captured_state = jlong_to_ptr(jcaptured_state);
 99     do_capture_state(captured_state, captured_state_mask);
100   }
101 }
102 
103 static void do_upcall(ffi_cif* cif, void* ret, void** args, void* user_data) {
104   // attach thread
105   JNIEnv* env;
106   jint result = (*VM)->AttachCurrentThreadAsDaemon(VM, (void**) &env, NULL);
107 
108   // call into doUpcall in LibFallback
109   jobject upcall_data = (jobject) user_data;
110   (*env)->CallStaticVoidMethod(env, LibFallback_class, LibFallback_doUpcall_ID,
111     ptr_to_jlong(ret), ptr_to_jlong(args), upcall_data);
112 
113   // always detach for now
114   (*VM)->DetachCurrentThread(VM);
115 }
116 
117 static void free_closure(JNIEnv* env, void* closure, jobject upcall_data) {
118   ffi_closure_free(closure);
119   (*env)->DeleteGlobalRef(env, upcall_data);
120 }
121 
122 JNIEXPORT jint JNICALL
123 Java_jdk_internal_foreign_abi_fallback_LibFallback_createClosure(JNIEnv* env, jclass cls, jlong cif, jobject upcall_data, jlongArray jptrs) {
124   void* code;
125   void* closure = ffi_closure_alloc(sizeof(ffi_closure), &code);
126 
127   jobject global_upcall_data = (*env)->NewGlobalRef(env, upcall_data);
128 
129   ffi_status status = ffi_prep_closure_loc(closure, jlong_to_ptr(cif), &do_upcall, (void*) global_upcall_data, code);
130 
131   if (status != FFI_OK) {
132     free_closure(env,closure, global_upcall_data);
133     return status;
134   }
135 
136   jlong* ptrs = (*env)->GetLongArrayElements(env, jptrs, NULL);
137   ptrs[0] = ptr_to_jlong(closure);
138   ptrs[1] = ptr_to_jlong(code);
139   ptrs[2] = ptr_to_jlong(global_upcall_data);
140   (*env)->ReleaseLongArrayElements(env, jptrs, ptrs, JNI_COMMIT);
141 
142   return status;
143 }
144 
145 JNIEXPORT void JNICALL
146 Java_jdk_internal_foreign_abi_fallback_LibFallback_freeClosure(JNIEnv* env, jclass cls, jlong closure, jlong upcall_data) {
147   free_closure(env, jlong_to_ptr(closure), jlong_to_ptr(upcall_data));
148 }
149 
150 JNIEXPORT jint JNICALL
151 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1default_1abi(JNIEnv* env, jclass cls) {
152   return (jint) FFI_DEFAULT_ABI;
153 }
154 
155 JNIEXPORT jshort JNICALL
156 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1struct(JNIEnv* env, jclass cls) {
157   return (jshort) FFI_TYPE_STRUCT;
158 }
159 
160 JNIEXPORT jlong JNICALL
161 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1void(JNIEnv* env, jclass cls) {
162   return ptr_to_jlong(&ffi_type_void);
163 }
164 
165 JNIEXPORT jlong JNICALL
166 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1uint8(JNIEnv* env, jclass cls) {
167   return ptr_to_jlong(&ffi_type_uint8);
168 }
169 JNIEXPORT jlong JNICALL
170 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1sint8(JNIEnv* env, jclass cls) {
171   return ptr_to_jlong(&ffi_type_sint8);
172 }
173 JNIEXPORT jlong JNICALL
174 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1uint16(JNIEnv* env, jclass cls) {
175   return ptr_to_jlong(&ffi_type_uint16);
176 }
177 JNIEXPORT jlong JNICALL
178 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1sint16(JNIEnv* env, jclass cls) {
179   return ptr_to_jlong(&ffi_type_sint16);
180 }
181 JNIEXPORT jlong JNICALL
182 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1uint32(JNIEnv* env, jclass cls) {
183   return ptr_to_jlong(&ffi_type_uint32);
184 }
185 JNIEXPORT jlong JNICALL
186 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1sint32(JNIEnv* env, jclass cls) {
187   return ptr_to_jlong(&ffi_type_sint32);
188 }
189 JNIEXPORT jlong JNICALL
190 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1uint64(JNIEnv* env, jclass cls) {
191   return ptr_to_jlong(&ffi_type_uint64);
192 }
193 JNIEXPORT jlong JNICALL
194 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1sint64(JNIEnv* env, jclass cls) {
195   return ptr_to_jlong(&ffi_type_sint64);
196 }
197 JNIEXPORT jlong JNICALL
198 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1float(JNIEnv* env, jclass cls) {
199   return ptr_to_jlong(&ffi_type_float);
200 }
201 JNIEXPORT jlong JNICALL
202 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1double(JNIEnv* env, jclass cls) {
203   return ptr_to_jlong(&ffi_type_double);
204 }
205 JNIEXPORT jlong JNICALL
206 Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1pointer(JNIEnv* env, jclass cls) {
207   return ptr_to_jlong(&ffi_type_pointer);
208 }