[Interop] Extend IrProviderForCEnumStubs to support structs.
Since current approach to generate IR for structs is the same as for enums it makes sense to just plug in CStructVarClassGenerator into current provider.
This commit is contained in:
committed by
Sergey Bogolepov
parent
e0117fd297
commit
c1d20ae511
@@ -2,7 +2,24 @@ package kotlinx.cinterop.internal
|
||||
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class CStruct(val spelling: String)
|
||||
annotation class CStruct(val spelling: String) {
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER
|
||||
)
|
||||
annotation class MemberAt(val offset: Long)
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(
|
||||
AnnotationTarget.PROPERTY_GETTER,
|
||||
AnnotationTarget.PROPERTY_SETTER
|
||||
)
|
||||
annotation class BitField(val offset: Long, val size: Int)
|
||||
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class VarType(val size: Long, val align: Int)
|
||||
}
|
||||
|
||||
@Target(
|
||||
AnnotationTarget.FUNCTION,
|
||||
|
||||
+2
@@ -43,6 +43,8 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
||||
|
||||
val cEnum = this.packageScope.getContributedClass("CEnum")
|
||||
val cEnumVar = this.packageScope.getContributedClass("CEnumVar")
|
||||
val cStructVar = this.packageScope.getContributedClass("CStructVar")
|
||||
val cStructVarType = cStructVar.defaultType.memberScope.getContributedClass("Type")
|
||||
val cPrimitiveVar = this.packageScope.getContributedClass("CPrimitiveVar")
|
||||
val cPrimitiveVarType = cPrimitiveVar.defaultType.memberScope.getContributedClass("Type")
|
||||
|
||||
|
||||
+12
-8
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForInteropStubs
|
||||
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumStubs
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
@@ -207,11 +207,15 @@ internal val psiToIrPhase = konanUnitPhase(
|
||||
moduleDescriptor, symbolTable,
|
||||
config.configuration.languageVersionSettings
|
||||
)
|
||||
val irProviderForCEnums = IrProviderForCEnumStubs(generatorContext, interopBuiltIns, stubGenerator, symbols)
|
||||
val irProviderForInteropStubs = IrProviderForInteropStubs { symbol ->
|
||||
irProviderForCEnums.canHandleSymbol(symbol)
|
||||
}
|
||||
val irProviders = listOf(irProviderForCEnums, irProviderForInteropStubs, functionIrClassFactory, deserializer, stubGenerator)
|
||||
val irProviderForCEnumsAndCStructs = IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, stubGenerator, symbols)
|
||||
val irProviderForInteropStubs = IrProviderForInteropStubs(irProviderForCEnumsAndCStructs::canHandleSymbol)
|
||||
val irProviders = listOf(
|
||||
irProviderForCEnumsAndCStructs,
|
||||
irProviderForInteropStubs,
|
||||
functionIrClassFactory,
|
||||
deserializer,
|
||||
stubGenerator
|
||||
)
|
||||
stubGenerator.setIrProviders(irProviders)
|
||||
|
||||
expectDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
|
||||
@@ -233,7 +237,7 @@ internal val psiToIrPhase = konanUnitPhase(
|
||||
}
|
||||
modulesWithoutDCE
|
||||
.filter(ModuleDescriptor::isFromInteropLibrary)
|
||||
.forEach(irProviderForCEnums::buildAllEnumsFrom)
|
||||
.forEach(irProviderForCEnumsAndCStructs::buildAllEnumsAndStructsFrom)
|
||||
|
||||
irModule = module
|
||||
irModules = deserializer.modules.filterValues { llvmModuleSpecification.containsModule(it) }
|
||||
@@ -243,7 +247,7 @@ internal val psiToIrPhase = konanUnitPhase(
|
||||
(listOf(irModule!!) + deserializer.modules.values)
|
||||
.single { it.descriptor.isKonanStdlib() }
|
||||
|
||||
irProviderForCEnums.module = module
|
||||
irProviderForCEnumsAndCStructs.module = module
|
||||
},
|
||||
name = "Psi2Ir",
|
||||
description = "Psi to IR conversion",
|
||||
|
||||
+18
-1
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -57,6 +58,9 @@ internal interface DescriptorToIrTranslationMixin {
|
||||
descriptor.typeConstructor.supertypes.mapTo(irClass.superTypes) {
|
||||
it.toIrType()
|
||||
}
|
||||
descriptor.annotations.mapTo(irClass.annotations) {
|
||||
typeTranslator.constantValueGenerator.generateAnnotationConstructorCall(it)!!
|
||||
}
|
||||
irClass.createParameterDeclarations()
|
||||
builder(irClass)
|
||||
createFakeOverrides(descriptor).forEach(irClass::addMember)
|
||||
@@ -102,6 +106,9 @@ internal fun IrBuilder.irInstanceInitializer(classSymbol: IrClassSymbol): IrExpr
|
||||
internal fun ClassDescriptor.implementsCEnum(interopBuiltIns: InteropBuiltIns): Boolean =
|
||||
interopBuiltIns.cEnum in this.getSuperInterfaces()
|
||||
|
||||
internal fun ClassDescriptor.inheritsFromCStructVar(interopBuiltIns: InteropBuiltIns): Boolean =
|
||||
interopBuiltIns.cStructVar == this.getSuperClassNotAny()
|
||||
|
||||
/**
|
||||
* All enums that come from interop library implement CEnum interface.
|
||||
* This function checks that given symbol located in subtree of
|
||||
@@ -110,4 +117,14 @@ internal fun ClassDescriptor.implementsCEnum(interopBuiltIns: InteropBuiltIns):
|
||||
internal fun IrSymbol.findCEnumDescriptor(interopBuiltIns: InteropBuiltIns): ClassDescriptor? =
|
||||
descriptor.parentsWithSelf
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.firstOrNull { it.implementsCEnum(interopBuiltIns) }
|
||||
.firstOrNull { it.implementsCEnum(interopBuiltIns) }
|
||||
|
||||
/**
|
||||
* All structs that come from interop library inherit from CStructVar class.
|
||||
* This function checks that given symbol located in subtree of
|
||||
* CStructVar inheritor.
|
||||
*/
|
||||
internal fun IrSymbol.findCStructDescriptor(interopBuiltIns: InteropBuiltIns): ClassDescriptor? =
|
||||
descriptor.parentsWithSelf
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.firstOrNull { it.inheritsFromCStructVar(interopBuiltIns) }
|
||||
+30
-14
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumByValueFunctionG
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumClassGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumCompanionGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumVarClassGenerator
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.cstruct.CStructVarClassGenerator
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
@@ -30,7 +31,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
/**
|
||||
* For the most of descriptors that come from metadata-based interop libraries
|
||||
* we generate a lazy IR.
|
||||
* We use a different approach for CEnums and generate IR eagerly. Motivation:
|
||||
* We use a different approach for CEnums and CStructVars and generate IR eagerly. Motivation:
|
||||
* 1. CEnums are "real" Kotlin enums. Thus, we need apply the same compilation approach
|
||||
* as we use for usual Kotlin enums.
|
||||
* Eager generation allows to reuse [EnumClassLowering], [EnumConstructorsLowering] and other
|
||||
@@ -38,7 +39,7 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
* 2. It is an easier and more obvious approach. Since implementation of metadata-based
|
||||
* libraries generation already took too much time we take an easier approach here.
|
||||
*/
|
||||
internal class IrProviderForCEnumStubs(
|
||||
internal class IrProviderForCEnumAndCStructStubs(
|
||||
context: GeneratorContext,
|
||||
private val interopBuiltIns: InteropBuiltIns,
|
||||
stubGenerator: DeclarationStubGenerator,
|
||||
@@ -57,6 +58,8 @@ internal class IrProviderForCEnumStubs(
|
||||
CEnumVarClassGenerator(context, stubGenerator, interopBuiltIns)
|
||||
private val cEnumClassGenerator =
|
||||
CEnumClassGenerator(context, stubGenerator, cEnumCompanionGenerator, cEnumVarClassGenerator)
|
||||
private val cStructClassGenerator =
|
||||
CStructVarClassGenerator(context, stubGenerator, interopBuiltIns)
|
||||
|
||||
var module: IrModuleFragment? = null
|
||||
set(value) {
|
||||
@@ -71,23 +74,36 @@ internal class IrProviderForCEnumStubs(
|
||||
fun canHandleSymbol(symbol: IrSymbol): Boolean {
|
||||
if (!symbol.descriptor.module.isFromInteropLibrary()) return false
|
||||
return symbol.findCEnumDescriptor(interopBuiltIns) != null
|
||||
|| symbol.findCStructDescriptor(interopBuiltIns) != null
|
||||
}
|
||||
|
||||
fun buildAllEnumsFrom(interopModule: ModuleDescriptor) {
|
||||
interopModule.getPackageFragments()
|
||||
.flatMap { it.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) }
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.filter { it.implementsCEnum(interopBuiltIns) }
|
||||
.forEach { cEnumClassGenerator.findOrGenerateCEnum(it, irParentFor(it)) }
|
||||
fun buildAllEnumsAndStructsFrom(interopModule: ModuleDescriptor) = interopModule.getPackageFragments()
|
||||
.flatMap { it.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) }
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.forEach {
|
||||
when {
|
||||
it.implementsCEnum(interopBuiltIns) ->
|
||||
cEnumClassGenerator.findOrGenerateCEnum(it, irParentFor(it))
|
||||
it.inheritsFromCStructVar(interopBuiltIns) ->
|
||||
cStructClassGenerator.findOrGenerateCStruct(it, irParentFor(it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateIrIfNeeded(symbol: IrSymbol) {
|
||||
// TODO: These `findOrGenerate` calls generate a whole subtree.
|
||||
// This a simple but clearly suboptimal solution.
|
||||
symbol.findCEnumDescriptor(interopBuiltIns)?.let { enumDescriptor ->
|
||||
cEnumClassGenerator.findOrGenerateCEnum(enumDescriptor, irParentFor(enumDescriptor))
|
||||
}
|
||||
symbol.findCStructDescriptor(interopBuiltIns)?.let { structDescriptor ->
|
||||
cStructClassGenerator.findOrGenerateCStruct(structDescriptor, irParentFor(structDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? {
|
||||
if (symbol.isBound) return symbol.owner as IrDeclaration
|
||||
if (!canHandleSymbol(symbol)) return null
|
||||
|
||||
val enumClassDescriptor = symbol.findCEnumDescriptor(interopBuiltIns)!!
|
||||
// TODO: This call generates a whole subtree. This a simple but clearly suboptimal solution.
|
||||
cEnumClassGenerator.findOrGenerateCEnum(enumClassDescriptor, irParentFor(enumClassDescriptor))
|
||||
generateIrIfNeeded(symbol)
|
||||
return when (symbol) {
|
||||
is IrClassSymbol -> symbolTable.referenceClass(symbol.descriptor).owner
|
||||
is IrEnumEntrySymbol -> symbolTable.referenceEnumEntry(symbol.descriptor).owner
|
||||
@@ -100,8 +116,8 @@ internal class IrProviderForCEnumStubs(
|
||||
private fun irParentFor(descriptor: ClassDescriptor): IrDeclarationContainer {
|
||||
val packageFragmentDescriptor = descriptor.findPackage()
|
||||
return filesMap.getOrPut(packageFragmentDescriptor) {
|
||||
IrFileImpl(NaiveSourceBasedFileEntryImpl("CEnums"), packageFragmentDescriptor).also {
|
||||
this@IrProviderForCEnumStubs.module?.files?.add(it)
|
||||
IrFileImpl(NaiveSourceBasedFileEntryImpl("CTypeDefinitions"), packageFragmentDescriptor).also {
|
||||
this@IrProviderForCEnumAndCStructStubs.module?.files?.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.backend.konan.ir.interop.cstruct
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InteropBuiltIns
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.DescriptorToIrTranslationMixin
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.irInstanceInitializer
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.addMember
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
|
||||
internal class CStructVarClassGenerator(
|
||||
context: GeneratorContext,
|
||||
override val stubGenerator: DeclarationStubGenerator,
|
||||
private val interopBuiltIns: InteropBuiltIns
|
||||
) : DescriptorToIrTranslationMixin {
|
||||
|
||||
override val irBuiltIns: IrBuiltIns = context.irBuiltIns
|
||||
override val symbolTable: SymbolTable = context.symbolTable
|
||||
override val typeTranslator: TypeTranslator = context.typeTranslator
|
||||
|
||||
private val companionGenerator = CStructVarCompanionGenerator(context, stubGenerator, interopBuiltIns)
|
||||
|
||||
fun findOrGenerateCStruct(classDescriptor: ClassDescriptor, parent: IrDeclarationContainer): IrClass {
|
||||
val irClassSymbol = symbolTable.referenceClass(classDescriptor)
|
||||
return if (!irClassSymbol.isBound) {
|
||||
provideIrClassForCStruct(classDescriptor).also {
|
||||
it.patchDeclarationParents(parent)
|
||||
parent.declarations += it
|
||||
}
|
||||
} else {
|
||||
irClassSymbol.owner
|
||||
}
|
||||
}
|
||||
|
||||
private fun provideIrClassForCStruct(descriptor: ClassDescriptor): IrClass =
|
||||
createClass(descriptor) { irClass ->
|
||||
irClass.addMember(createPrimaryConstructor(irClass))
|
||||
irClass.addMember(companionGenerator.generate(descriptor))
|
||||
descriptor.unsubstitutedMemberScope
|
||||
.getContributedDescriptors()
|
||||
.filterIsInstance<PropertyDescriptor>()
|
||||
.filter { it.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
|
||||
.map(this::createProperty)
|
||||
.forEach(irClass::addMember)
|
||||
}
|
||||
|
||||
private fun createPrimaryConstructor(irClass: IrClass): IrConstructor {
|
||||
val enumVarConstructorSymbol = symbolTable.referenceConstructor(
|
||||
interopBuiltIns.cStructVar.unsubstitutedPrimaryConstructor!!
|
||||
)
|
||||
return createConstructor(irClass.descriptor.unsubstitutedPrimaryConstructor!!).also { irConstructor ->
|
||||
irConstructor.body = irBuilder(irBuiltIns, irConstructor.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
|
||||
+IrDelegatingConstructorCallImpl(
|
||||
startOffset, endOffset,
|
||||
context.irBuiltIns.unitType, enumVarConstructorSymbol
|
||||
).also {
|
||||
it.putValueArgument(0, irGet(irConstructor.valueParameters[0]))
|
||||
}
|
||||
+irInstanceInitializer(symbolTable.referenceClass(irClass.descriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.backend.konan.ir.interop.cstruct
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.InteropBuiltIns
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.getArgumentValueOrNull
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.DescriptorToIrTranslationMixin
|
||||
import org.jetbrains.kotlin.backend.konan.ir.interop.irInstanceInitializer
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.builders.irInt
|
||||
import org.jetbrains.kotlin.ir.builders.irLong
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.addMember
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.irBuilder
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
|
||||
private val varTypeAnnotationFqName = FqName("kotlinx.cinterop.internal.CStruct.VarType")
|
||||
|
||||
internal class CStructVarCompanionGenerator(
|
||||
context: GeneratorContext,
|
||||
override val stubGenerator: DeclarationStubGenerator,
|
||||
private val interopBuiltIns: InteropBuiltIns
|
||||
) : DescriptorToIrTranslationMixin {
|
||||
|
||||
override val irBuiltIns: IrBuiltIns = context.irBuiltIns
|
||||
override val symbolTable: SymbolTable = context.symbolTable
|
||||
override val typeTranslator: TypeTranslator = context.typeTranslator
|
||||
|
||||
fun generate(structDescriptor: ClassDescriptor): IrClass =
|
||||
createClass(structDescriptor.companionObjectDescriptor!!) { companionIrClass ->
|
||||
val annotation = companionIrClass.descriptor.annotations
|
||||
.findAnnotation(varTypeAnnotationFqName)!!
|
||||
val size = annotation.getArgumentValueOrNull<Long>("size")!!
|
||||
val align = annotation.getArgumentValueOrNull<Int>("align")!!
|
||||
companionIrClass.addMember(createCompanionConstructor(companionIrClass.descriptor, size, align))
|
||||
}
|
||||
|
||||
private fun createCompanionConstructor(companionObjectDescriptor: ClassDescriptor, size: Long, align: Int): IrConstructor {
|
||||
val superConstructorSymbol = symbolTable.referenceConstructor(interopBuiltIns.cStructVarType.unsubstitutedPrimaryConstructor!!)
|
||||
return createConstructor(companionObjectDescriptor.unsubstitutedPrimaryConstructor!!).also { irConstructor ->
|
||||
irConstructor.body = irBuilder(irBuiltIns, irConstructor.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
|
||||
+IrDelegatingConstructorCallImpl(
|
||||
startOffset, endOffset, context.irBuiltIns.unitType,
|
||||
superConstructorSymbol
|
||||
).also {
|
||||
it.putValueArgument(0, irLong(size))
|
||||
it.putValueArgument(1, irInt(align))
|
||||
}
|
||||
+irInstanceInitializer(symbolTable.referenceClass(companionObjectDescriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user