From 1ec506d0b1961abd02e6d89bce8d7b68141f6756 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Wed, 21 Nov 2018 11:21:37 +0700 Subject: [PATCH] Don't generate functional types for functions with long signatures (#2349) The K/N stdlib doesn't contain basic classes (e.g. Functon0, Function1 etc) for functional types with >22 parameters. So we cannot convert functional pointers with such signatures into Kotlin functional types and have to replace them with opaque pointers. Fix for GitHub issue #2334. --- .../kotlin/native/interop/indexer/Indexer.kt | 21 ++++++++++-- .../native/interop/indexer/NativeIndex.kt | 2 +- .../kotlin/native/interop/gen/jvm/main.kt | 2 +- backend.native/tests/build.gradle | 2 +- .../tests/interop/basics/cfunptr.def | 32 +++++++++++++++++++ backend.native/tests/interop/basics/funptr.kt | 10 ++++++ 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt index 12a68d02c7a..f38f95be9a9 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt @@ -77,7 +77,7 @@ private class ObjCCategoryImpl( override val properties = mutableListOf() } -internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() { +internal class NativeIndexImpl(val library: NativeLibrary, val verbose: Boolean = false) : NativeIndex() { private sealed class DeclarationID { data class USR(val usr: String) : DeclarationID() @@ -154,6 +154,12 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() { override lateinit var includedHeaders: List + private fun log(message: String) { + if (verbose) { + println(message) + } + } + private fun getDeclarationId(cursor: CValue): DeclarationID { val usr = clang_getCursorUSR(cursor).convertAndDispose() if (usr == "") { @@ -618,6 +624,15 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() { } else { val returnType = convertType(clang_getResultType(type)) val numArgs = clang_getNumArgTypes(type) + + // Ignore functions with long signatures since we have no basic class for such functional types in the stdlib. + // TODO: Remove this limitation when functional types with long signatures are supported. + if (numArgs > 22) { + log("Warning: cannot generate a Kotlin functional type for a pointer to a function with more than 22 parameters. " + + "An opaque pointer will be used instead.") + return VoidType + } + val paramTypes = (0..numArgs - 1).map { convertType(clang_getArgType(type, it)) } @@ -902,8 +917,8 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() { } -fun buildNativeIndexImpl(library: NativeLibrary): NativeIndex { - val result = NativeIndexImpl(library) +fun buildNativeIndexImpl(library: NativeLibrary, verbose: Boolean): NativeIndex { + val result = NativeIndexImpl(library, verbose) indexDeclarations(result) findMacros(result) return result diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt index 762849974c1..3d942d86196 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt @@ -53,7 +53,7 @@ data class NativeLibrary(val includes: List, /** * Retrieves the definitions from given C header file using given compiler arguments (e.g. defines). */ -fun buildNativeIndex(library: NativeLibrary): NativeIndex = buildNativeIndexImpl(library) +fun buildNativeIndex(library: NativeLibrary, verbose: Boolean): NativeIndex = buildNativeIndexImpl(library, verbose) /** * This class describes the IR of definitions from C header file(s). diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index 84d643c1535..185398d6252 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -241,7 +241,7 @@ private fun processCLib(args: Array): Array? { target = tool.target ) - val nativeIndex = buildNativeIndex(library) + val nativeIndex = buildNativeIndex(library, verbose) val gen = StubGenerator(nativeIndex, configuration, libName, generateShims, verbose, flavor, imports) diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 66adcff6ac7..844f22a67e2 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -2850,7 +2850,7 @@ task interop_bitfields(type: RunInteropKonanTest) { task interop_funptr(type: RunInteropKonanTest) { disabled = (project.testTarget == 'wasm32') // No interop for wasm yet. expectedFail = (project.testTarget == 'linux_mips32') // fails because of big-endiannes - goldValue = "42\n17\n1\n0\n" + goldValue = "42\n17\n1\n0\n42\n42\n" source = "interop/basics/funptr.kt" interop = 'cfunptr' } diff --git a/backend.native/tests/interop/basics/cfunptr.def b/backend.native/tests/interop/basics/cfunptr.def index d9538950da1..7506e77b623 100644 --- a/backend.native/tests/interop/basics/cfunptr.def +++ b/backend.native/tests/interop/basics/cfunptr.def @@ -59,4 +59,36 @@ static unsigned int getMaxUInt(void) { static typeof(&getMaxUInt) getMaxUIntGetter() { return &getMaxUInt; +} + +typedef int (*longSignatureFunctionPtrType)( + int, int, int, int, int, int, int, int, int, int, int, int, + int, int, int, int, int, int, int, int, int, int, int +); + +typedef int (*notSoLongSignatureFunctionPtrType)( + int, int, int, int, int, int, int, int, int, int, int, + int, int, int, int, int, int, int, int, int, int, int +); + +static int longSignatureFunction( + int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12, + int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22, int p23 +) { + return 42; +} + +static int notSoLongSignatureFunction( + int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8, int p9, int p10, int p11, int p12, + int p13, int p14, int p15, int p16, int p17, int p18, int p19, int p20, int p21, int p22 +) { + return 42; +} + +static longSignatureFunctionPtrType getLongSignatureFunctionPtr() { + return &longSignatureFunction; +} + +static notSoLongSignatureFunctionPtrType getNotSoLongSignatureFunctionPtr() { + return ¬SoLongSignatureFunction; } \ No newline at end of file diff --git a/backend.native/tests/interop/basics/funptr.kt b/backend.native/tests/interop/basics/funptr.kt index 1045675563d..6e1e677ba1c 100644 --- a/backend.native/tests/interop/basics/funptr.kt +++ b/backend.native/tests/interop/basics/funptr.kt @@ -7,6 +7,11 @@ import kotlinx.cinterop.* import cfunptr.* import kotlin.test.* +typealias NotSoLongSignatureFunction = ( + Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, + Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int +) -> Int + fun main(args: Array) { val atoiPtr = getAtoiPtr()!! @@ -31,6 +36,11 @@ fun main(args: Array) { printIntPtr(isIntPositivePtr(-42).ifThenOneElseZero()) assertEquals(getMaxUIntGetter()!!(), UInt.MAX_VALUE) + + val longSignaturePtr: COpaquePointer? = getLongSignatureFunctionPtr() + val notSoLongSignaturePtr: CPointer>? = getNotSoLongSignatureFunctionPtr() + printIntPtr(notSoLongSignaturePtr!!.invoke(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) + printIntPtr(notSoLongSignatureFunction(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) } fun Boolean.ifThenOneElseZero() = if (this) 1 else 0 \ No newline at end of file