From a9d0409f2e1f3eba6c2fc8661229ce9f52ec910f Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 19 Mar 2021 06:53:09 +0000 Subject: [PATCH] Don't use Function.reflect() in kotlin-native/Interop on JVM Use inline functions and typeOf() instead --- .../kotlin/kotlinx/cinterop/JvmCallbacks.kt | 28 ++- .../kotlinx/cinterop/JvmStaticCFuntion.kt | 183 ++++++++++++++++++ .../jvm/kotlin/kotlinx/cinterop/JvmTypes.kt | 69 ------- 3 files changed, 196 insertions(+), 84 deletions(-) create mode 100644 kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmStaticCFuntion.kt diff --git a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt index ca6345b690e..edbf5a39f3c 100644 --- a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt +++ b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt @@ -19,13 +19,10 @@ 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 import kotlin.reflect.full.companionObjectInstance import kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.full.isSubclassOf -import kotlin.reflect.jvm.reflect -import kotlin.reflect.jvm.ExperimentalReflectionOnLambdas internal fun createStablePointer(any: Any): COpaquePointer = newGlobalRef(any).toCPointer()!! @@ -158,19 +155,15 @@ private fun getArgOrRetValCType(type: KType): CType<*> { return result } -private fun createStaticCFunction(function: Function<*>): CPointer> { +private fun createStaticCFunction(function: Function<*>, spec: FunctionSpec): CPointer> { val errorMessage = "staticCFunction must take an unbound, non-capturing function" if (!isStatic(function)) { throw IllegalArgumentException(errorMessage) } - @OptIn(ExperimentalReflectionOnLambdas::class) - val kFunction = function as? KFunction<*> ?: function.reflect() ?: - throw IllegalArgumentException(errorMessage) - - val returnType = getArgOrRetValCType(kFunction.returnType) - val paramTypes = kFunction.parameters.map { getArgOrRetValCType(it.type) } + val returnType = getArgOrRetValCType(spec.returnType) + val paramTypes = spec.parameterTypes.map { getArgOrRetValCType(it) } @Suppress("UNCHECKED_CAST") return interpretCPointer(createStaticCFunctionImpl(returnType as CType, paramTypes, function))!! @@ -199,13 +192,18 @@ private fun isStatic(function: Function<*>): Boolean { } } -private val createdStaticFunctions = ConcurrentHashMap, CPointer>>() +private data class FunctionSpec(val functionClass: Class<*>, val returnType: KType, val parameterTypes: List) + +private val createdStaticFunctions = ConcurrentHashMap>>() @Suppress("UNCHECKED_CAST") -internal fun > staticCFunctionImpl(function: F) = - createdStaticFunctions.computeIfAbsent(function.javaClass) { - createStaticCFunction(function) - } as CPointer> +@PublishedApi +internal fun > staticCFunctionImpl(function: F, returnType: KType, vararg parameterTypes: KType): CPointer> { + val spec = FunctionSpec(function.javaClass, returnType, parameterTypes.asList()) + return createdStaticFunctions.computeIfAbsent(spec) { + createStaticCFunction(function, spec) + } as CPointer> +} private val invokeMethods = (0 .. 22).map { arity -> Class.forName("kotlin.jvm.functions.Function$arity").getMethod("invoke", diff --git a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmStaticCFuntion.kt b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmStaticCFuntion.kt new file mode 100644 index 00000000000..917f27681ae --- /dev/null +++ b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmStaticCFuntion.kt @@ -0,0 +1,183 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +/* +// TODO: generate automatically during build. +// The code below is generated with + +fun main() { + println(""" + package kotlinx.cinterop + + @OptIn(ExperimentalStdlibApi::class) + @PublishedApi + internal inline fun t() = kotlin.reflect.typeOf() + + """.trimIndent()) + + repeat(23) { count -> + val typeParameterNames = (1 .. count).map { "P$it" } + val typeParameters = (typeParameterNames + "R").joinToString { "reified $it" } + + val functionType = buildString { + append('(') + typeParameterNames.joinTo(this) + append(") -> R") + } + + println(""" + inline fun <$typeParameters> staticCFunction(noinline function: $functionType): CPointer> = + staticCFunctionImpl( + function, + ${(listOf("R") + typeParameterNames).joinToString { "t<$it>()" }} + ) + + """.trimIndent()) + } +} +*/ +package kotlinx.cinterop + +@OptIn(ExperimentalStdlibApi::class) +@PublishedApi +internal inline fun t() = kotlin.reflect.typeOf() + +inline fun staticCFunction(noinline function: () -> R): CPointer R>> = + staticCFunctionImpl( + function, + t() + ) + +inline fun staticCFunction(noinline function: (P1) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) + +inline fun staticCFunction(noinline function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R): CPointer R>> = + staticCFunctionImpl( + function, + t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t(), t() + ) diff --git a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt index 49b16c4231e..b9d1f03c710 100644 --- a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt +++ b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt @@ -74,72 +74,3 @@ annotation class CLength(val value: Int) @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class CNaturalStruct(vararg val fieldNames: String) - -fun staticCFunction(function: () -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R): CPointer R>> = - staticCFunctionImpl(function) - -fun staticCFunction(function: (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R): CPointer R>> = - staticCFunctionImpl(function)