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