diff --git a/Interop/Runtime/src/callbacks/c/callbacks.c b/Interop/Runtime/src/callbacks/c/callbacks.c index 71e546ab411..d187d71a426 100644 --- a/Interop/Runtime/src/callbacks/c/callbacks.c +++ b/Interop/Runtime/src/callbacks/c/callbacks.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -163,10 +164,12 @@ static void checkException(JNIEnv *env) { static void ffi_fun(ffi_cif *cif, void *ret, void **args, void *user_data) { JNIEnv* env = getCurrentEnv(); - static jmethodID ffiFunImpl0 = NULL; + static jmethodID acceptFun = NULL; static jclass cls = NULL; - if (ffiFunImpl0 == NULL) { - jclass clsLocal = (*env)->FindClass(env, "kotlinx/cinterop/JvmCallbacksKt"); + if (acceptFun == NULL) { + // Note: in some cases [FindClass] below may use a classloader different from the one loaded interop classes, + // so stick to JVM-provided class: + jclass clsLocal = (*env)->FindClass(env, "java/util/function/LongConsumer"); checkException(env); assert(clsLocal != NULL); @@ -174,12 +177,13 @@ static void ffi_fun(ffi_cif *cif, void *ret, void **args, void *user_data) { checkException(env); assert(cls != NULL); - ffiFunImpl0 = (*env)->GetStaticMethodID(env, cls, "ffiFunImpl0", "(JJJLjava/lang/Object;)V"); + acceptFun = (*env)->GetMethodID(env, cls, "accept", "(J)V"); checkException(env); - assert(ffiFunImpl0 != NULL); + assert(acceptFun != NULL); } - (*env)->CallStaticVoidMethod(env, cls, ffiFunImpl0, (jlong) cif, (jlong) ret, (jlong) args, (jobject) user_data); + jlong retAndArgs[2] = { (jlong)ret, (jlong)args }; // Unpacked in [ffiClosureImpl]. + (*env)->CallVoidMethod(env, (jobject) user_data, acceptFun, (jlong)(intptr_t)&retAndArgs[0]); checkException(env); } diff --git a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt index b322ce9d4d4..58b84fd0c48 100644 --- a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt +++ b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt @@ -17,6 +17,7 @@ package kotlinx.cinterop import java.util.concurrent.ConcurrentHashMap +import java.util.function.LongConsumer import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KType @@ -275,8 +276,18 @@ private inline fun ffiClosureImpl( returnType: CType, crossinline invoke: (args: CArrayPointer) -> Any? ): FfiClosureImpl { - return { ret, args -> + // Called through [ffi_fun] when a native function created with [ffiCreateClosure] is invoked. + return LongConsumer { retAndArgsRaw -> + val retAndArgs = retAndArgsRaw.toCPointer>()!! + + // Pointer to memory to be filled with return value of the invoked native function: + val ret = retAndArgs[0]!! + + // Pointer to array of pointers to arguments passed to the invoked native function: + val args = retAndArgs[1]!!.reinterpret() + val result = invoke(args) + returnType.write(ret.rawValue, result) } } @@ -357,7 +368,7 @@ private class CEnumType(private val rawValueCType: CType) : CType(ra } } -private typealias FfiClosureImpl = (ret: COpaquePointer, args: CArrayPointer)->Unit +private typealias FfiClosureImpl = LongConsumer private typealias UserData = FfiClosureImpl private fun loadCallbacksLibrary() { @@ -429,29 +440,10 @@ private fun ffiCreateCif(returnType: ffi_type, paramTypes: List): ffi_ return interpretPointed(res) } -@Suppress("UNUSED_PARAMETER", "UNUSED") -private fun ffiFunImpl0(ffiCif: Long, ret: Long, args: Long, userData: Any) { - @Suppress("UNCHECKED_CAST") - ffiFunImpl(interpretCPointer(ret)!!, - interpretCPointer(args)!!, - userData as UserData) -} - -/** - * This function is called from native code when a native function created with [ffiCreateClosure] is invoked. - * - * @param ret pointer to memory to be filled with return value of the invoked native function - * @param args pointer to array of pointers to arguments passed to the invoked native function - */ -private fun ffiFunImpl(ret: COpaquePointer, args: CArrayPointer, userData: UserData) { - - userData.invoke(ret, args) -} - private external fun ffiCreateClosure0(ffiCif: Long, userData: Any): Long /** - * Uses libffi to allocate a native function which will call [ffiFunImpl] when invoked. + * Uses libffi to allocate a native function which will call [impl] when invoked. * * @param ffiCif describes the type of the function to create */