diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/FunctionPointers.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/FunctionPointers.kt index 37eb70f4d76..c30153e7ba6 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/FunctionPointers.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/FunctionPointers.kt @@ -67,7 +67,7 @@ import konan.internal.ExportForCompiler @ExportForCompiler private fun invokeImplUnitRet(ptr: COpaquePointer, vararg args: Any?): Unit = memScoped { - callWithVarargs(ptr.rawValue, nativeNullPtr, FFI_TYPE_KIND_VOID, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, nativeNullPtr, FFI_TYPE_KIND_VOID, args, null, memScope) } @ExportForCompiler @@ -77,48 +77,48 @@ private fun invokeImplBooleanRet(ptr: COpaquePointer, vararg args: Any?): Boolea @ExportForCompiler private fun invokeImplByteRet(ptr: COpaquePointer, vararg args: Any?): Byte = memScoped { val resultBuffer = allocFfiReturnValueBuffer(ByteVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT8, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT8, args, null, memScope) resultBuffer.value } @ExportForCompiler private fun invokeImplShortRet(ptr: COpaquePointer, vararg args: Any?): Short = memScoped { val resultBuffer = allocFfiReturnValueBuffer(ShortVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT16, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT16, args, null, memScope) resultBuffer.value } @ExportForCompiler private fun invokeImplIntRet(ptr: COpaquePointer, vararg args: Any?): Int = memScoped { val resultBuffer = allocFfiReturnValueBuffer(IntVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT32, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT32, args, null, memScope) resultBuffer.value } @ExportForCompiler private fun invokeImplLongRet(ptr: COpaquePointer, vararg args: Any?): Long = memScoped { val resultBuffer = allocFfiReturnValueBuffer(LongVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT64, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT64, args, null, memScope) resultBuffer.value } @ExportForCompiler private fun invokeImplFloatRet(ptr: COpaquePointer, vararg args: Any?): Float = memScoped { val resultBuffer = allocFfiReturnValueBuffer(FloatVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_FLOAT, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_FLOAT, args, null, memScope) resultBuffer.value } @ExportForCompiler private fun invokeImplDoubleRet(ptr: COpaquePointer, vararg args: Any?): Double = memScoped { val resultBuffer = allocFfiReturnValueBuffer(DoubleVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_DOUBLE, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_DOUBLE, args, null, memScope) resultBuffer.value } @ExportForCompiler private fun invokeImplPointerRet(ptr: COpaquePointer, vararg args: Any?): COpaquePointer? = memScoped { val resultBuffer = allocFfiReturnValueBuffer(COpaquePointerVar) - callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_POINTER, args, emptyArray(), memScope) + callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_POINTER, args, null, memScope) resultBuffer.value } diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt index 645de66c00d..2733e9be0d6 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt @@ -95,10 +95,10 @@ inline fun NativePlacement.allocFfiReturnValueBuffer(ty } fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind, - fixedArguments: Array, variadicArguments: Array, + fixedArguments: Array, variadicArguments: Array?, argumentsPlacement: AutofreeScope) { - val totalArgumentsNumber = fixedArguments.size + variadicArguments.size + val totalArgumentsNumber = fixedArguments.size + if (variadicArguments == null) 0 else variadicArguments.size // All supported arguments take at most 8 bytes each: val argumentsStorage = argumentsPlacement.allocArray(totalArgumentsNumber) @@ -122,17 +122,30 @@ fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKin addArgument(argument, isVariadic = false) } - for (argument in variadicArguments) { - addArgument(argument, isVariadic = true) + val variadicArgumentsNumber: Int + + if (variadicArguments != null) { + for (argument in variadicArguments) { + addArgument(argument, isVariadic = true) + } + variadicArgumentsNumber = variadicArguments.size + } else { + variadicArgumentsNumber = -1 } assert (index == totalArgumentsNumber) - callWithVarargs(codePtr, returnValuePtr, returnTypeKind, arguments.rawValue, types.rawValue, - fixedArguments.size, totalArgumentsNumber) + callFunctionPointer(codePtr, returnValuePtr, returnTypeKind, arguments.rawValue, types.rawValue, + totalArgumentsNumber, variadicArgumentsNumber) } -@SymbolName("Kotlin_Interop_callWithVarargs") -private external fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind, - arguments: NativePtr, argumentTypeKinds: NativePtr, - fixedArgumentsNumber: Int, totalArgumentsNumber: Int) \ No newline at end of file +@SymbolName("Kotlin_Interop_callFunctionPointer") +private external fun callFunctionPointer( + codePtr: NativePtr, + returnValuePtr: NativePtr, + returnTypeKind: FfiTypeKind, + arguments: NativePtr, + argumentTypeKinds: NativePtr, + totalArgumentsNumber: Int, + variadicArgumentsNumber: Int +) diff --git a/runtime/src/main/cpp/Interop.cpp b/runtime/src/main/cpp/Interop.cpp index b40f4cbf0dd..aa2f44bf4da 100644 --- a/runtime/src/main/cpp/Interop.cpp +++ b/runtime/src/main/cpp/Interop.cpp @@ -61,9 +61,9 @@ ffi_type* convertFfiTypeKindToType(FfiTypeKind typeKind) { extern "C" { -void Kotlin_Interop_callWithVarargs(void* codePtr, void* returnValuePtr, FfiTypeKind returnTypeKind, +void Kotlin_Interop_callFunctionPointer(void* codePtr, void* returnValuePtr, FfiTypeKind returnTypeKind, void** arguments, intptr_t* argumentTypeKinds, - int fixedArgumentsNumber, int totalArgumentsNumber) { + int totalArgumentsNumber, int variadicArgumentsNumber) { #ifdef KONAN_NO_FFI RuntimeAssert(false, "Vararg calls are not supported on this platform"); #else @@ -72,11 +72,18 @@ void Kotlin_Interop_callWithVarargs(void* codePtr, void* returnValuePtr, FfiType for (int i = 0; i < totalArgumentsNumber; ++i) { argumentTypes[i] = convertFfiTypeKindToType((FfiTypeKind) argumentTypeKinds[i]); } + ffi_type* returnType = convertFfiTypeKindToType(returnTypeKind); ffi_cif cif; - ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, - fixedArgumentsNumber, totalArgumentsNumber, - convertFfiTypeKindToType(returnTypeKind), argumentTypes); + if (variadicArgumentsNumber < 0) { + // Non-variadic. + ffi_prep_cif(&cif, FFI_DEFAULT_ABI, totalArgumentsNumber, returnType, argumentTypes); + } else { + int fixedArgumentsNumber = totalArgumentsNumber - variadicArgumentsNumber; + ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, + fixedArgumentsNumber, totalArgumentsNumber, + returnType, argumentTypes); + } ffi_call(&cif, (void (*)())codePtr, returnValuePtr, arguments); #endif