Skip to content

Commit

Permalink
Don't generate functional types for functions with long signatures (J…
Browse files Browse the repository at this point in the history
…etBrains#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 JetBrains#2334.
  • Loading branch information
ilmat192 authored Nov 21, 2018
1 parent 77897ba commit 1ec506d
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private class ObjCCategoryImpl(
override val properties = mutableListOf<ObjCProperty>()
}

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()
Expand Down Expand Up @@ -154,6 +154,12 @@ internal class NativeIndexImpl(val library: NativeLibrary) : NativeIndex() {

override lateinit var includedHeaders: List<HeaderId>

private fun log(message: String) {
if (verbose) {
println(message)
}
}

private fun getDeclarationId(cursor: CValue<CXCursor>): DeclarationID {
val usr = clang_getCursorUSR(cursor).convertAndDispose()
if (usr == "") {
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ data class NativeLibrary(val includes: List<String>,
/**
* 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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ private fun processCLib(args: Array<String>): Array<String>? {
target = tool.target
)

val nativeIndex = buildNativeIndex(library)
val nativeIndex = buildNativeIndex(library, verbose)

val gen = StubGenerator(nativeIndex, configuration, libName, generateShims, verbose, flavor, imports)

Expand Down
2 changes: 1 addition & 1 deletion backend.native/tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}
Expand Down
32 changes: 32 additions & 0 deletions backend.native/tests/interop/basics/cfunptr.def
Original file line number Diff line number Diff line change
Expand Up @@ -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 &notSoLongSignatureFunction;
}
10 changes: 10 additions & 0 deletions backend.native/tests/interop/basics/funptr.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>) {
val atoiPtr = getAtoiPtr()!!

Expand All @@ -31,6 +36,11 @@ fun main(args: Array<String>) {
printIntPtr(isIntPositivePtr(-42).ifThenOneElseZero())

assertEquals(getMaxUIntGetter()!!(), UInt.MAX_VALUE)

val longSignaturePtr: COpaquePointer? = getLongSignatureFunctionPtr()
val notSoLongSignaturePtr: CPointer<CFunction<NotSoLongSignatureFunction>>? = 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

0 comments on commit 1ec506d

Please sign in to comment.