From 4e1482750b6bb80dfa6b6e2acdd51bf21d1a1973 Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Thu, 6 Feb 2020 16:44:04 +0700 Subject: [PATCH] [StubIr][Metadata] Add support for array members of structs --- .../kotlinx/cinterop/internal/Annotations.kt | 4 ++++ .../jetbrains/kotlin/native/interop/gen/StubIr.kt | 2 ++ .../native/interop/gen/StubIrElementBuilders.kt | 2 +- .../native/interop/gen/StubIrMetadataEmitter.kt | 3 +++ .../native/interop/gen/StubIrTextEmitter.kt | 1 + .../kotlin/native/interop/gen/StubIrType.kt | 6 ++++++ .../kotlin/backend/konan/RuntimeNames.kt | 1 + .../backend/konan/lower/InteropCallConvertors.kt | 15 +++++++++++++++ 8 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/internal/Annotations.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/internal/Annotations.kt index 8a9ecf9a58b..29e47e06afc 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/internal/Annotations.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/internal/Annotations.kt @@ -10,6 +10,10 @@ annotation class CStruct(val spelling: String) { ) annotation class MemberAt(val offset: Long) + @Retention(AnnotationRetention.BINARY) + @Target(AnnotationTarget.PROPERTY_GETTER) + annotation class ArrayMemberAt(val offset: Long) + @Retention(AnnotationRetention.BINARY) @Target( AnnotationTarget.PROPERTY_GETTER, diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt index 0fe2b915250..e97bc87b0e4 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIr.kt @@ -202,6 +202,8 @@ sealed class AnnotationStub(val classifier: Classifier) { class CStruct(val struct: String) : AnnotationStub(cStructClassifier) { class MemberAt(val offset: Long) : AnnotationStub(cStructClassifier.nested("MemberAt")) + class ArrayMemberAt(val offset: Long) : AnnotationStub(cStructClassifier.nested("ArrayMemberAt")) + class BitField(val offset: Long, val size: Int) : AnnotationStub(cStructClassifier.nested("BitField")) class VarType(val size: Long, val align: Int) : AnnotationStub(cStructClassifier.nested("VarType")) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt index a45fddfcba3..2757afe9dd6 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrElementBuilders.kt @@ -86,7 +86,7 @@ internal class StructStubBuilder( } val getter = when (context.generationMode) { GenerationMode.SOURCE_CODE -> PropertyAccessor.Getter.ArrayMemberAt(offset) - GenerationMode.METADATA -> PropertyAccessor.Getter.ExternalGetter(listOf(AnnotationStub.CStruct.MemberAt(offset))) + GenerationMode.METADATA -> PropertyAccessor.Getter.ExternalGetter(listOf(AnnotationStub.CStruct.ArrayMemberAt(offset))) } val kind = PropertyStub.Kind.Val(getter) // TODO: Should receiver be added? diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt index 2316ebf6fcc..54ceb804388 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrMetadataEmitter.kt @@ -393,6 +393,9 @@ private class MappingExtensions( is AnnotationStub.CStruct.MemberAt -> mapOfNotNull( ("offset" to KmAnnotationArgument.LongValue(offset)) ) + is AnnotationStub.CStruct.ArrayMemberAt -> mapOfNotNull( + ("offset" to KmAnnotationArgument.LongValue(offset)) + ) is AnnotationStub.CStruct.BitField -> mapOfNotNull( ("offset" to KmAnnotationArgument.LongValue(offset)), ("size" to KmAnnotationArgument.IntValue(size)) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt index 88ee2bea9d2..32b7d058b54 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrTextEmitter.kt @@ -499,6 +499,7 @@ class StubIrTextEmitter( is AnnotationStub.CEnumEntryAlias, is AnnotationStub.CEnumVarTypeSize, is AnnotationStub.CStruct.MemberAt, + is AnnotationStub.CStruct.ArrayMemberAt, is AnnotationStub.CStruct.BitField, is AnnotationStub.CStruct.VarType -> error("${annotationStub.classifier.fqName} annotation is unsupported in textual mode") diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt index 4d4af7a66f3..6992f8da2fb 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/StubIrType.kt @@ -185,6 +185,11 @@ private object PredefinedTypesHandler { return AbbreviatedType(objCClass, KotlinTypes.objCObjectMeta, emptyList(), nullable) } + private fun expandCArrayPointer(typeArguments: List, nullable: Boolean): AbbreviatedType { + val cPointer = ClassifierStubType(KotlinTypes.cPointer, typeArguments) + return AbbreviatedType(cPointer, KotlinTypes.cArrayPointer, typeArguments, nullable) + } + /** * @return [ClassifierStubType] if [classifier] is a typealias from [kotlinx.cinterop] package. */ @@ -195,6 +200,7 @@ private object PredefinedTypesHandler { KotlinTypes.cOpaquePointerVar.classifier -> expandCOpaquePointerVar(nullable) KotlinTypes.cPointerVar -> expandCPointerVar(typeArguments, nullable) KotlinTypes.objCObjectMeta -> expandObjCObjectMeta(typeArguments, nullable) + KotlinTypes.cArrayPointer -> expandCArrayPointer(typeArguments, nullable) else -> null } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt index 41b97946cfe..c4f3f7caf33 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt @@ -11,6 +11,7 @@ object RuntimeNames { val exportTypeInfoAnnotation = FqName("kotlin.native.internal.ExportTypeInfo") val cCall = FqName("kotlinx.cinterop.internal.CCall") val cStructMemberAt = FqName("kotlinx.cinterop.internal.CStruct.MemberAt") + val cStructArrayMemberAt = FqName("kotlinx.cinterop.internal.CStruct.ArrayMemberAt") val cStructBitField = FqName("kotlinx.cinterop.internal.CStruct.BitField") val objCMethodAnnotation = FqName("kotlinx.cinterop.ObjCMethod") val objCMethodImp = FqName("kotlinx.cinterop.ObjCMethodImp") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt index 05973df75ca..c4ee3593c33 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropCallConvertors.kt @@ -39,6 +39,9 @@ private fun isEnumVarValueAccessor(function: IrFunction, symbols: KonanSymbols): private fun isMemberAtAccessor(function: IrFunction): Boolean = function.hasAnnotation(RuntimeNames.cStructMemberAt) +private fun isArrayMemberAtAccessor(function: IrFunction): Boolean = + function.hasAnnotation(RuntimeNames.cStructArrayMemberAt) + private fun isBitFieldAccessor(function: IrFunction): Boolean = function.hasAnnotation(RuntimeNames.cStructBitField) @@ -238,6 +241,8 @@ internal fun tryGenerateInteropMemberAccess( generateInteropCall(symbols, builder) { generateMemberAtAccess(callSite) } isBitFieldAccessor(callSite.symbol.owner) -> generateInteropCall(symbols, builder) { generateBitFieldAccess(callSite) } + isArrayMemberAtAccessor(callSite.symbol.owner) -> + generateInteropCall(symbols, builder) { generateArrayMemberAtAccess(callSite) } else -> null } @@ -283,6 +288,16 @@ private fun InteropCallContext.generateMemberAtAccess(callSite: IrCall): IrExpre } } +private fun InteropCallContext.generateArrayMemberAtAccess(callSite: IrCall): IrExpression { + val accessor = callSite.symbol.owner + val memberAt = accessor.getAnnotation(RuntimeNames.cStructArrayMemberAt)!! + val offset = (memberAt.getValueArgument(0) as IrConst).value + val fieldPointer = calculateFieldPointer(callSite.dispatchReceiver!!, offset) + return builder.irCall(symbols.interopInterpretCPointer).also { + it.putValueArgument(0, fieldPointer) + } +} + private fun InteropCallContext.writeBits( base: IrExpression, offset: Long,