[StubIr][Metadata] Add support for array members of structs

This commit is contained in:
Sergey Bogolepov
2020-02-06 16:44:04 +07:00
committed by Sergey Bogolepov
parent 91fb5eca76
commit 4e1482750b
8 changed files with 33 additions and 1 deletions
@@ -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,
@@ -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"))
@@ -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?
@@ -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))
@@ -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")
@@ -185,6 +185,11 @@ private object PredefinedTypesHandler {
return AbbreviatedType(objCClass, KotlinTypes.objCObjectMeta, emptyList(), nullable)
}
private fun expandCArrayPointer(typeArguments: List<TypeArgument>, 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
}
@@ -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")
@@ -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<Long>).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,