[C Interop] Use CCall annotation for global getters and setters. (#3420)
This commit is contained in:
@@ -4,7 +4,11 @@ package kotlinx.cinterop.internal
|
|||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class CStruct(val spelling: String)
|
annotation class CStruct(val spelling: String)
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(
|
||||||
|
AnnotationTarget.FUNCTION,
|
||||||
|
AnnotationTarget.PROPERTY_GETTER,
|
||||||
|
AnnotationTarget.PROPERTY_SETTER
|
||||||
|
)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
public annotation class CCall(val id: String) {
|
public annotation class CCall(val id: String) {
|
||||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||||
|
|||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package org.jetbrains.kotlin.native.interop.gen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.native.interop.indexer.FunctionDecl
|
||||||
|
import org.jetbrains.kotlin.native.interop.indexer.GlobalDecl
|
||||||
|
import org.jetbrains.kotlin.native.interop.indexer.VoidType
|
||||||
|
import org.jetbrains.kotlin.native.interop.indexer.unwrapTypedefs
|
||||||
|
|
||||||
|
internal data class CCalleeWrapper(val lines: List<String>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some functions don't have an address (e.g. macros-based or builtins).
|
||||||
|
* To solve this problem we generate a wrapper function.
|
||||||
|
*/
|
||||||
|
internal class CWrappersGenerator(private val context: StubIrContext) {
|
||||||
|
|
||||||
|
private var currentFunctionWrapperId = 0
|
||||||
|
|
||||||
|
private val packageName =
|
||||||
|
context.configuration.pkgName.replace(INVALID_CLANG_IDENTIFIER_REGEX, "_")
|
||||||
|
|
||||||
|
private fun generateFunctionWrapperName(functionName: String): String {
|
||||||
|
return "${packageName}_${functionName}_wrapper${currentFunctionWrapperId++}"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindSymbolToFunction(symbol: String, function: String): List<String> = listOf(
|
||||||
|
"const void* $symbol __asm(${symbol.quoteAsKotlinLiteral()});",
|
||||||
|
"const void* $symbol = &$function;"
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class Parameter(val type: String, val name: String)
|
||||||
|
|
||||||
|
private fun createWrapper(
|
||||||
|
symbolName: String,
|
||||||
|
wrapperName: String,
|
||||||
|
returnType: String,
|
||||||
|
parameters: List<Parameter>,
|
||||||
|
body: String
|
||||||
|
): List<String> = listOf(
|
||||||
|
"__attribute__((always_inline))",
|
||||||
|
"$returnType $wrapperName(${parameters.joinToString { "${it.type} ${it.name}" }}) {",
|
||||||
|
body,
|
||||||
|
"}",
|
||||||
|
*bindSymbolToFunction(symbolName, wrapperName).toTypedArray()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun generateCCalleeWrapper(function: FunctionDecl, symbolName: String): CCalleeWrapper =
|
||||||
|
if (function.isVararg) {
|
||||||
|
CCalleeWrapper(bindSymbolToFunction(symbolName, function.name))
|
||||||
|
} else {
|
||||||
|
val wrapperName = generateFunctionWrapperName(function.name)
|
||||||
|
|
||||||
|
val returnType = function.returnType.getStringRepresentation()
|
||||||
|
val parameters = function.parameters.mapIndexed { index, parameter ->
|
||||||
|
Parameter(parameter.type.getStringRepresentation(), "p$index")
|
||||||
|
}
|
||||||
|
val callExpression = "${function.name}(${parameters.joinToString { it.name }});"
|
||||||
|
val wrapperBody = if (function.returnType.unwrapTypedefs() is VoidType) {
|
||||||
|
callExpression
|
||||||
|
} else {
|
||||||
|
"return $callExpression"
|
||||||
|
}
|
||||||
|
val wrapper = createWrapper(symbolName, wrapperName, returnType, parameters, wrapperBody)
|
||||||
|
CCalleeWrapper(wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateCGlobalGetter(globalDecl: GlobalDecl, symbolName: String): CCalleeWrapper {
|
||||||
|
val wrapperName = generateFunctionWrapperName("${globalDecl.name}_getter")
|
||||||
|
val returnType = globalDecl.type.getStringRepresentation()
|
||||||
|
val wrapperBody = "return ${globalDecl.name};"
|
||||||
|
val wrapper = createWrapper(symbolName, wrapperName, returnType, emptyList(), wrapperBody)
|
||||||
|
return CCalleeWrapper(wrapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun generateCGlobalSetter(globalDecl: GlobalDecl, symbolName: String): CCalleeWrapper {
|
||||||
|
val wrapperName = generateFunctionWrapperName("${globalDecl.name}_setter")
|
||||||
|
val globalType = globalDecl.type.getStringRepresentation()
|
||||||
|
val parameter = Parameter(globalType, "p1")
|
||||||
|
val wrapperBody = "${globalDecl.name} = ${parameter.name};"
|
||||||
|
val wrapper = createWrapper(symbolName, wrapperName, "void", listOf(parameter), wrapperBody)
|
||||||
|
return CCalleeWrapper(wrapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-4
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.native.interop.indexer.CompilationWithPCH
|
|||||||
import org.jetbrains.kotlin.native.interop.indexer.Language
|
import org.jetbrains.kotlin.native.interop.indexer.Language
|
||||||
import org.jetbrains.kotlin.native.interop.indexer.mapFragmentIsCompilable
|
import org.jetbrains.kotlin.native.interop.indexer.mapFragmentIsCompilable
|
||||||
|
|
||||||
|
internal val INVALID_CLANG_IDENTIFIER_REGEX = "[^a-zA-Z1-9_]".toRegex()
|
||||||
|
|
||||||
class SimpleBridgeGeneratorImpl(
|
class SimpleBridgeGeneratorImpl(
|
||||||
private val platform: KotlinPlatform,
|
private val platform: KotlinPlatform,
|
||||||
private val pkgName: String,
|
private val pkgName: String,
|
||||||
@@ -246,8 +248,4 @@ class SimpleBridgeGeneratorImpl(
|
|||||||
nativeBacked !in excludedClients
|
nativeBacked !in excludedClients
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
internal val INVALID_CLANG_IDENTIFIER_REGEX = "[^a-zA-Z1-9_]".toRegex()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-64
@@ -4,11 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.kotlin.native.interop.gen
|
package org.jetbrains.kotlin.native.interop.gen
|
||||||
|
|
||||||
import org.jetbrains.kotlin.native.interop.gen.SimpleBridgeGeneratorImpl.Companion.INVALID_CLANG_IDENTIFIER_REGEX
|
|
||||||
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
|
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
|
||||||
import org.jetbrains.kotlin.native.interop.indexer.ObjCProtocol
|
import org.jetbrains.kotlin.native.interop.indexer.*
|
||||||
import org.jetbrains.kotlin.native.interop.indexer.VoidType
|
|
||||||
import org.jetbrains.kotlin.native.interop.indexer.unwrapTypedefs
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
|
||||||
class BridgeBuilderResult(
|
class BridgeBuilderResult(
|
||||||
@@ -19,8 +16,6 @@ class BridgeBuilderResult(
|
|||||||
val excludedStubs: Set<StubIrElement>
|
val excludedStubs: Set<StubIrElement>
|
||||||
)
|
)
|
||||||
|
|
||||||
private data class CCalleeWrapper(val name: String, val lines: List<String>)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates [NativeBridges] and corresponding function bodies and property accessors.
|
* Generates [NativeBridges] and corresponding function bodies and property accessors.
|
||||||
*/
|
*/
|
||||||
@@ -30,6 +25,8 @@ class StubIrBridgeBuilder(
|
|||||||
|
|
||||||
private val globalAddressExpressions = mutableMapOf<Pair<String, PropertyAccessor>, KotlinExpression>()
|
private val globalAddressExpressions = mutableMapOf<Pair<String, PropertyAccessor>, KotlinExpression>()
|
||||||
|
|
||||||
|
private val wrapperGenerator = CWrappersGenerator(context)
|
||||||
|
|
||||||
private fun getGlobalAddressExpression(cGlobalName: String, accessor: PropertyAccessor) =
|
private fun getGlobalAddressExpression(cGlobalName: String, accessor: PropertyAccessor) =
|
||||||
globalAddressExpressions.getOrPut(Pair(cGlobalName, accessor)) {
|
globalAddressExpressions.getOrPut(Pair(cGlobalName, accessor)) {
|
||||||
simpleBridgeGenerator.kotlinToNative(
|
simpleBridgeGenerator.kotlinToNative(
|
||||||
@@ -74,13 +71,6 @@ class StubIrBridgeBuilder(
|
|||||||
|
|
||||||
private val bridgeGeneratingVisitor = object : StubIrVisitor<StubContainer?, Unit> {
|
private val bridgeGeneratingVisitor = object : StubIrVisitor<StubContainer?, Unit> {
|
||||||
|
|
||||||
private var currentFunctionWrapperId = 0
|
|
||||||
|
|
||||||
private fun generateFunctionWrapperName(packageName: String, functionName: String): String {
|
|
||||||
val validPackageName = packageName.replace(INVALID_CLANG_IDENTIFIER_REGEX, "_")
|
|
||||||
return "${validPackageName}_${functionName}_wrapper${currentFunctionWrapperId++}"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitClass(element: ClassStub, owner: StubContainer?) {
|
override fun visitClass(element: ClassStub, owner: StubContainer?) {
|
||||||
element.annotations.filterIsInstance<AnnotationStub.ObjC.ExternalClass>().firstOrNull()?.let {
|
element.annotations.filterIsInstance<AnnotationStub.ObjC.ExternalClass>().firstOrNull()?.let {
|
||||||
if (it.protocolGetter.isNotEmpty() && element.origin is StubOrigin.ObjCProtocol) {
|
if (it.protocolGetter.isNotEmpty() && element.origin is StubOrigin.ObjCProtocol) {
|
||||||
@@ -116,50 +106,10 @@ class StubIrBridgeBuilder(
|
|||||||
?: return
|
?: return
|
||||||
val cCallAnnotation = function.annotations.firstIsInstanceOrNull<AnnotationStub.CCall.Symbol>()
|
val cCallAnnotation = function.annotations.firstIsInstanceOrNull<AnnotationStub.CCall.Symbol>()
|
||||||
?: return
|
?: return
|
||||||
val cCallSymbolName = cCallAnnotation.symbolName
|
val wrapper = wrapperGenerator.generateCCalleeWrapper(origin.function, cCallAnnotation.symbolName)
|
||||||
val (wrapperName, wrapperLines) = generateCCalleeWrapper(origin)
|
simpleBridgeGenerator.insertNativeBridge(function, emptyList(), wrapper.lines)
|
||||||
simpleBridgeGenerator.insertNativeBridge(
|
|
||||||
function,
|
|
||||||
emptyList(),
|
|
||||||
listOf(
|
|
||||||
*wrapperLines.toTypedArray(),
|
|
||||||
"const void* $cCallSymbolName __asm(${cCallSymbolName.quoteAsKotlinLiteral()});",
|
|
||||||
"const void* $cCallSymbolName = &$wrapperName;"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Some functions don't have an address (e.g. macros-based or builtins).
|
|
||||||
* To solve this problem we generate a wrapper function.
|
|
||||||
*/
|
|
||||||
private fun generateCCalleeWrapper(origin: StubOrigin.Function): CCalleeWrapper =
|
|
||||||
if (origin.function.isVararg) {
|
|
||||||
CCalleeWrapper(origin.function.name, emptyList())
|
|
||||||
} else {
|
|
||||||
val function = origin.function
|
|
||||||
val wrapperName = generateFunctionWrapperName(context.configuration.pkgName, function.name)
|
|
||||||
|
|
||||||
val returnType = function.returnType.getStringRepresentation()
|
|
||||||
val parameters = function.parameters.mapIndexed { index, parameter ->
|
|
||||||
"p$index" to parameter.type.getStringRepresentation()
|
|
||||||
}
|
|
||||||
val callExpression = "${function.name}(${parameters.joinToString { it.first }});"
|
|
||||||
val wrapperBody = if (function.returnType.unwrapTypedefs() is VoidType) {
|
|
||||||
callExpression
|
|
||||||
} else {
|
|
||||||
"return $callExpression"
|
|
||||||
}
|
|
||||||
|
|
||||||
val alwaysInline = "__attribute__((always_inline))"
|
|
||||||
val lines = listOf(
|
|
||||||
"$alwaysInline $returnType $wrapperName(${parameters.joinToString { "${it.second} ${it.first}" }}) {",
|
|
||||||
wrapperBody,
|
|
||||||
"}"
|
|
||||||
)
|
|
||||||
CCalleeWrapper(wrapperName, lines)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitProperty(element: PropertyStub, owner: StubContainer?) {
|
override fun visitProperty(element: PropertyStub, owner: StubContainer?) {
|
||||||
try {
|
try {
|
||||||
when (val kind = element.kind) {
|
when (val kind = element.kind) {
|
||||||
@@ -185,14 +135,11 @@ class StubIrBridgeBuilder(
|
|||||||
override fun visitPropertyAccessor(accessor: PropertyAccessor, owner: StubContainer?) {
|
override fun visitPropertyAccessor(accessor: PropertyAccessor, owner: StubContainer?) {
|
||||||
when (accessor) {
|
when (accessor) {
|
||||||
is PropertyAccessor.Getter.SimpleGetter -> {
|
is PropertyAccessor.Getter.SimpleGetter -> {
|
||||||
if (accessor in builderResult.bridgeGenerationComponents.getterToBridgeInfo) {
|
when (accessor) {
|
||||||
val extra = builderResult.bridgeGenerationComponents.getterToBridgeInfo.getValue(accessor)
|
in builderResult.bridgeGenerationComponents.getterToBridgeInfo -> {
|
||||||
val typeInfo = extra.typeInfo
|
val extra = builderResult.bridgeGenerationComponents.getterToBridgeInfo.getValue(accessor)
|
||||||
val expression = if (extra.isArray) {
|
val typeInfo = extra.typeInfo
|
||||||
val getAddressExpression = getGlobalAddressExpression(extra.cGlobalName, accessor)
|
propertyAccessorBridgeBodies[accessor] = typeInfo.argFromBridged(simpleBridgeGenerator.kotlinToNative(
|
||||||
typeInfo.argFromBridged(getAddressExpression, kotlinFile, nativeBacked = accessor) + "!!"
|
|
||||||
} else {
|
|
||||||
typeInfo.argFromBridged(simpleBridgeGenerator.kotlinToNative(
|
|
||||||
nativeBacked = accessor,
|
nativeBacked = accessor,
|
||||||
returnType = typeInfo.bridgedType,
|
returnType = typeInfo.bridgedType,
|
||||||
kotlinValues = emptyList(),
|
kotlinValues = emptyList(),
|
||||||
@@ -201,7 +148,12 @@ class StubIrBridgeBuilder(
|
|||||||
typeInfo.cToBridged(expr = extra.cGlobalName)
|
typeInfo.cToBridged(expr = extra.cGlobalName)
|
||||||
}, kotlinFile, nativeBacked = accessor)
|
}, kotlinFile, nativeBacked = accessor)
|
||||||
}
|
}
|
||||||
propertyAccessorBridgeBodies[accessor] = expression
|
in builderResult.bridgeGenerationComponents.arrayGetterInfo -> {
|
||||||
|
val extra = builderResult.bridgeGenerationComponents.arrayGetterInfo.getValue(accessor)
|
||||||
|
val typeInfo = extra.typeInfo
|
||||||
|
val getAddressExpression = getGlobalAddressExpression(extra.cGlobalName, accessor)
|
||||||
|
propertyAccessorBridgeBodies[accessor] = typeInfo.argFromBridged(getAddressExpression, kotlinFile, nativeBacked = accessor) + "!!"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +197,26 @@ class StubIrBridgeBuilder(
|
|||||||
val getAddressExpression = getGlobalAddressExpression(accessor.cGlobalName, accessor)
|
val getAddressExpression = getGlobalAddressExpression(accessor.cGlobalName, accessor)
|
||||||
propertyAccessorBridgeBodies[accessor] = getAddressExpression
|
propertyAccessorBridgeBodies[accessor] = getAddressExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is PropertyAccessor.Getter.ExternalGetter -> {
|
||||||
|
if (accessor in builderResult.wrapperGenerationComponents.getterToWrapperInfo) {
|
||||||
|
val extra = builderResult.wrapperGenerationComponents.getterToWrapperInfo.getValue(accessor)
|
||||||
|
val cCallAnnotation = accessor.annotations.firstIsInstanceOrNull<AnnotationStub.CCall.Symbol>()
|
||||||
|
?: error("external getter for ${extra.global.name} wasn't marked with @CCall")
|
||||||
|
val wrapper = wrapperGenerator.generateCGlobalGetter(extra.global, cCallAnnotation.symbolName)
|
||||||
|
simpleBridgeGenerator.insertNativeBridge(accessor, emptyList(), wrapper.lines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is PropertyAccessor.Setter.ExternalSetter -> {
|
||||||
|
if (accessor in builderResult.wrapperGenerationComponents.setterToWrapperInfo) {
|
||||||
|
val extra = builderResult.wrapperGenerationComponents.setterToWrapperInfo.getValue(accessor)
|
||||||
|
val cCallAnnotation = accessor.annotations.firstIsInstanceOrNull<AnnotationStub.CCall.Symbol>()
|
||||||
|
?: error("external setter for ${extra.global.name} wasn't marked with @CCall")
|
||||||
|
val wrapper = wrapperGenerator.generateCGlobalSetter(extra.global, cCallAnnotation.symbolName)
|
||||||
|
simpleBridgeGenerator.insertNativeBridge(accessor, emptyList(), wrapper.lines)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-21
@@ -8,25 +8,22 @@ import org.jetbrains.kotlin.native.interop.gen.jvm.InteropConfiguration
|
|||||||
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
|
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
|
||||||
import org.jetbrains.kotlin.native.interop.indexer.*
|
import org.jetbrains.kotlin.native.interop.indexer.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Components that are not passed via StubIr but required for bridge generation.
|
||||||
|
*/
|
||||||
|
class BridgeGenerationInfo(val cGlobalName: String, val typeInfo: TypeInfo)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional components that are required to generate bridges.
|
* Additional components that are required to generate bridges.
|
||||||
|
* TODO: Metadata-based interop should not depend on these components.
|
||||||
*/
|
*/
|
||||||
interface BridgeGenerationComponents {
|
interface BridgeGenerationComponents {
|
||||||
|
|
||||||
class GlobalSetterBridgeInfo(
|
val setterToBridgeInfo: Map<PropertyAccessor.Setter, BridgeGenerationInfo>
|
||||||
val cGlobalName: String,
|
|
||||||
val typeInfo: TypeInfo
|
|
||||||
)
|
|
||||||
|
|
||||||
class GlobalGetterBridgeInfo(
|
val getterToBridgeInfo: Map<PropertyAccessor.Getter, BridgeGenerationInfo>
|
||||||
val cGlobalName: String,
|
|
||||||
val typeInfo: TypeInfo,
|
|
||||||
val isArray: Boolean
|
|
||||||
)
|
|
||||||
|
|
||||||
val setterToBridgeInfo: Map<PropertyAccessor.Setter, GlobalSetterBridgeInfo>
|
val arrayGetterInfo: Map<PropertyAccessor.Getter, BridgeGenerationInfo>
|
||||||
|
|
||||||
val getterToBridgeInfo: Map<PropertyAccessor.Getter, GlobalGetterBridgeInfo>
|
|
||||||
|
|
||||||
val enumToTypeMirror: Map<ClassStub.Enum, TypeMirror>
|
val enumToTypeMirror: Map<ClassStub.Enum, TypeMirror>
|
||||||
|
|
||||||
@@ -35,13 +32,15 @@ interface BridgeGenerationComponents {
|
|||||||
val cStringParameters: Set<FunctionParameterStub>
|
val cStringParameters: Set<FunctionParameterStub>
|
||||||
}
|
}
|
||||||
|
|
||||||
class BridgeGenerationComponentsBuilder(
|
class BridgeGenerationComponentsBuilder {
|
||||||
val getterToBridgeInfo: MutableMap<PropertyAccessor.Getter, BridgeGenerationComponents.GlobalGetterBridgeInfo> = mutableMapOf(),
|
|
||||||
val setterToBridgeInfo: MutableMap<PropertyAccessor.Setter, BridgeGenerationComponents.GlobalSetterBridgeInfo> = mutableMapOf(),
|
val getterToBridgeInfo = mutableMapOf<PropertyAccessor.Getter, BridgeGenerationInfo>()
|
||||||
val enumToTypeMirror: MutableMap<ClassStub.Enum, TypeMirror> = mutableMapOf(),
|
val setterToBridgeInfo = mutableMapOf<PropertyAccessor.Setter, BridgeGenerationInfo>()
|
||||||
val wCStringParameters: MutableSet<FunctionParameterStub> = mutableSetOf(),
|
val arrayGetterBridgeInfo = mutableMapOf<PropertyAccessor.Getter, BridgeGenerationInfo>()
|
||||||
val cStringParameters: MutableSet<FunctionParameterStub> = mutableSetOf()
|
val enumToTypeMirror = mutableMapOf<ClassStub.Enum, TypeMirror>()
|
||||||
) {
|
val wCStringParameters = mutableSetOf<FunctionParameterStub>()
|
||||||
|
val cStringParameters = mutableSetOf<FunctionParameterStub>()
|
||||||
|
|
||||||
fun build(): BridgeGenerationComponents = object : BridgeGenerationComponents {
|
fun build(): BridgeGenerationComponents = object : BridgeGenerationComponents {
|
||||||
override val getterToBridgeInfo =
|
override val getterToBridgeInfo =
|
||||||
this@BridgeGenerationComponentsBuilder.getterToBridgeInfo.toMap()
|
this@BridgeGenerationComponentsBuilder.getterToBridgeInfo.toMap()
|
||||||
@@ -57,6 +56,31 @@ class BridgeGenerationComponentsBuilder(
|
|||||||
|
|
||||||
override val cStringParameters: Set<FunctionParameterStub> =
|
override val cStringParameters: Set<FunctionParameterStub> =
|
||||||
this@BridgeGenerationComponentsBuilder.cStringParameters.toSet()
|
this@BridgeGenerationComponentsBuilder.cStringParameters.toSet()
|
||||||
|
|
||||||
|
override val arrayGetterInfo: Map<PropertyAccessor.Getter, BridgeGenerationInfo> =
|
||||||
|
this@BridgeGenerationComponentsBuilder.arrayGetterBridgeInfo.toMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Components that are not passed via StubIr but required for generation of wrappers.
|
||||||
|
*/
|
||||||
|
class WrapperGenerationInfo(val global: GlobalDecl)
|
||||||
|
|
||||||
|
interface WrapperGenerationComponents {
|
||||||
|
val getterToWrapperInfo: Map<PropertyAccessor.Getter.ExternalGetter, WrapperGenerationInfo>
|
||||||
|
val setterToWrapperInfo: Map<PropertyAccessor.Setter.ExternalSetter, WrapperGenerationInfo>
|
||||||
|
}
|
||||||
|
|
||||||
|
class WrapperGenerationComponentsBuilder {
|
||||||
|
|
||||||
|
val getterToWrapperInfo = mutableMapOf<PropertyAccessor.Getter.ExternalGetter, WrapperGenerationInfo>()
|
||||||
|
val setterToWrapperInfo = mutableMapOf<PropertyAccessor.Setter.ExternalSetter, WrapperGenerationInfo>()
|
||||||
|
|
||||||
|
fun build(): WrapperGenerationComponents = object : WrapperGenerationComponents {
|
||||||
|
override val getterToWrapperInfo = this@WrapperGenerationComponentsBuilder.getterToWrapperInfo.toMap()
|
||||||
|
|
||||||
|
override val setterToWrapperInfo = this@WrapperGenerationComponentsBuilder.setterToWrapperInfo.toMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +110,8 @@ interface StubsBuildingContext {
|
|||||||
|
|
||||||
val bridgeComponentsBuilder: BridgeGenerationComponentsBuilder
|
val bridgeComponentsBuilder: BridgeGenerationComponentsBuilder
|
||||||
|
|
||||||
|
val wrapperComponentsBuilder: WrapperGenerationComponentsBuilder
|
||||||
|
|
||||||
fun getKotlinClassFor(objCClassOrProtocol: ObjCClassOrProtocol, isMeta: Boolean = false): Classifier
|
fun getKotlinClassFor(objCClassOrProtocol: ObjCClassOrProtocol, isMeta: Boolean = false): Classifier
|
||||||
|
|
||||||
fun getKotlinClassForPointed(structDecl: StructDecl): Classifier
|
fun getKotlinClassForPointed(structDecl: StructDecl): Classifier
|
||||||
@@ -210,6 +236,8 @@ class StubsBuildingContextImpl(
|
|||||||
|
|
||||||
override val bridgeComponentsBuilder = BridgeGenerationComponentsBuilder()
|
override val bridgeComponentsBuilder = BridgeGenerationComponentsBuilder()
|
||||||
|
|
||||||
|
override val wrapperComponentsBuilder = WrapperGenerationComponentsBuilder()
|
||||||
|
|
||||||
override fun getKotlinClassFor(objCClassOrProtocol: ObjCClassOrProtocol, isMeta: Boolean): Classifier {
|
override fun getKotlinClassFor(objCClassOrProtocol: ObjCClassOrProtocol, isMeta: Boolean): Classifier {
|
||||||
return declarationMapper.getKotlinClassFor(objCClassOrProtocol, isMeta)
|
return declarationMapper.getKotlinClassFor(objCClassOrProtocol, isMeta)
|
||||||
}
|
}
|
||||||
@@ -223,7 +251,8 @@ class StubsBuildingContextImpl(
|
|||||||
data class StubIrBuilderResult(
|
data class StubIrBuilderResult(
|
||||||
val stubs: SimpleStubContainer,
|
val stubs: SimpleStubContainer,
|
||||||
val declarationMapper: DeclarationMapper,
|
val declarationMapper: DeclarationMapper,
|
||||||
val bridgeGenerationComponents: BridgeGenerationComponents
|
val bridgeGenerationComponents: BridgeGenerationComponents,
|
||||||
|
val wrapperGenerationComponents: WrapperGenerationComponents
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -285,7 +314,8 @@ class StubIrBuilder(private val context: StubIrContext) {
|
|||||||
return StubIrBuilderResult(
|
return StubIrBuilderResult(
|
||||||
stubs,
|
stubs,
|
||||||
buildingContext.declarationMapper,
|
buildingContext.declarationMapper,
|
||||||
buildingContext.bridgeComponentsBuilder.build()
|
buildingContext.bridgeComponentsBuilder.build(),
|
||||||
|
buildingContext.wrapperComponentsBuilder.build()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-12
@@ -110,9 +110,8 @@ internal class StructStubBuilder(
|
|||||||
val signed = field.type.isIntegerTypeSigned()
|
val signed = field.type.isIntegerTypeSigned()
|
||||||
val readBits = PropertyAccessor.Getter.ReadBits(field.offset, field.size, signed)
|
val readBits = PropertyAccessor.Getter.ReadBits(field.offset, field.size, signed)
|
||||||
val writeBits = PropertyAccessor.Setter.WriteBits(field.offset, field.size)
|
val writeBits = PropertyAccessor.Setter.WriteBits(field.offset, field.size)
|
||||||
// TODO: Use something instead of [GlobalGetterBridgeInfo].
|
context.bridgeComponentsBuilder.getterToBridgeInfo[readBits] = BridgeGenerationInfo("", typeInfo)
|
||||||
context.bridgeComponentsBuilder.getterToBridgeInfo[readBits] = BridgeGenerationComponents.GlobalGetterBridgeInfo("", typeInfo, false)
|
context.bridgeComponentsBuilder.setterToBridgeInfo[writeBits] = BridgeGenerationInfo("", typeInfo)
|
||||||
context.bridgeComponentsBuilder.setterToBridgeInfo[writeBits] = BridgeGenerationComponents.GlobalSetterBridgeInfo("", typeInfo)
|
|
||||||
val kind = PropertyStub.Kind.Var(readBits, writeBits)
|
val kind = PropertyStub.Kind.Var(readBits, writeBits)
|
||||||
PropertyStub(field.name, WrapperStubType(kotlinType), kind)
|
PropertyStub(field.name, WrapperStubType(kotlinType), kind)
|
||||||
}
|
}
|
||||||
@@ -357,7 +356,7 @@ internal class FunctionStubBuilder(
|
|||||||
val type = WrapperStubType(KotlinTypes.any.makeNullable())
|
val type = WrapperStubType(KotlinTypes.any.makeNullable())
|
||||||
parameters += FunctionParameterStub("variadicArguments", type, isVararg = true)
|
parameters += FunctionParameterStub("variadicArguments", type, isVararg = true)
|
||||||
}
|
}
|
||||||
annotations = listOf(AnnotationStub.CCall.Symbol(context.generateNextUniqueId("knifunptr_") + "_${func.name}"))
|
annotations = listOf(AnnotationStub.CCall.Symbol("${context.generateNextUniqueId("knifunptr_")}_${func.name}"))
|
||||||
mustBeExternal = true
|
mustBeExternal = true
|
||||||
}
|
}
|
||||||
val functionStub = FunctionStub(
|
val functionStub = FunctionStub(
|
||||||
@@ -443,22 +442,44 @@ internal class GlobalStubBuilder(
|
|||||||
if (unwrappedType is ArrayType) {
|
if (unwrappedType is ArrayType) {
|
||||||
kotlinType = (mirror as TypeMirror.ByValue).valueType
|
kotlinType = (mirror as TypeMirror.ByValue).valueType
|
||||||
val getter = PropertyAccessor.Getter.SimpleGetter()
|
val getter = PropertyAccessor.Getter.SimpleGetter()
|
||||||
val extra = BridgeGenerationComponents.GlobalGetterBridgeInfo(global.name, mirror.info, isArray = true)
|
val extra = BridgeGenerationInfo(global.name, mirror.info)
|
||||||
context.bridgeComponentsBuilder.getterToBridgeInfo[getter] = extra
|
context.bridgeComponentsBuilder.arrayGetterBridgeInfo[getter] = extra
|
||||||
kind = PropertyStub.Kind.Val(getter)
|
kind = PropertyStub.Kind.Val(getter)
|
||||||
} else {
|
} else {
|
||||||
when (mirror) {
|
when (mirror) {
|
||||||
is TypeMirror.ByValue -> {
|
is TypeMirror.ByValue -> {
|
||||||
kotlinType = mirror.argType
|
kotlinType = mirror.argType
|
||||||
val getter = PropertyAccessor.Getter.SimpleGetter()
|
val getter = when (context.platform) {
|
||||||
val getterExtra = BridgeGenerationComponents.GlobalGetterBridgeInfo(global.name, mirror.info, isArray = false)
|
KotlinPlatform.JVM -> {
|
||||||
context.bridgeComponentsBuilder.getterToBridgeInfo[getter] = getterExtra
|
PropertyAccessor.Getter.SimpleGetter().also {
|
||||||
|
val getterExtra = BridgeGenerationInfo(global.name, mirror.info)
|
||||||
|
context.bridgeComponentsBuilder.getterToBridgeInfo[it] = getterExtra
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KotlinPlatform.NATIVE -> {
|
||||||
|
val cCallAnnotation = AnnotationStub.CCall.Symbol("${context.generateNextUniqueId("knifunptr_")}_${global.name}_getter")
|
||||||
|
PropertyAccessor.Getter.ExternalGetter(listOf(cCallAnnotation)).also {
|
||||||
|
context.wrapperComponentsBuilder.getterToWrapperInfo[it] = WrapperGenerationInfo(global)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
kind = if (global.isConst) {
|
kind = if (global.isConst) {
|
||||||
PropertyStub.Kind.Val(getter)
|
PropertyStub.Kind.Val(getter)
|
||||||
} else {
|
} else {
|
||||||
val setter = PropertyAccessor.Setter.SimpleSetter()
|
val setter = when (context.platform) {
|
||||||
val setterExtra = BridgeGenerationComponents.GlobalSetterBridgeInfo(global.name, mirror.info)
|
KotlinPlatform.JVM -> {
|
||||||
context.bridgeComponentsBuilder.setterToBridgeInfo[setter] = setterExtra
|
PropertyAccessor.Setter.SimpleSetter().also {
|
||||||
|
val setterExtra = BridgeGenerationInfo(global.name, mirror.info)
|
||||||
|
context.bridgeComponentsBuilder.setterToBridgeInfo[it] = setterExtra
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KotlinPlatform.NATIVE -> {
|
||||||
|
val cCallAnnotation = AnnotationStub.CCall.Symbol("${context.generateNextUniqueId("knifunptr_")}_${global.name}_setter")
|
||||||
|
PropertyAccessor.Setter.ExternalSetter(listOf(cCallAnnotation)).also {
|
||||||
|
context.wrapperComponentsBuilder.setterToWrapperInfo[it] = WrapperGenerationInfo(global)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
PropertyStub.Kind.Var(getter, setter)
|
PropertyStub.Kind.Var(getter, setter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user