Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Commit

Permalink
Proper fix for interop enum and struct generation
Browse files Browse the repository at this point in the history
Current approach to generate interop enum and structs during linkage stage turned out to be fragile. We might get unbound wrapper descriptors which are useless for function body generation.
The solution is to postpone body generation until linkage step is complete.
  • Loading branch information
sbogolepov committed Dec 3, 2020
1 parent cb76660 commit a012e23
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ internal fun Context.psiToIr(
modulesWithoutDCE
.filter(ModuleDescriptor::isFromInteropLibrary)
.forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom)


translator.addPostprocessingStep {
irProviderForCEnumsAndCStructs.generateBodies()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ internal interface DescriptorToIrTranslationMixin {

val typeTranslator: TypeTranslator

val postLinkageSteps: MutableList<() -> Unit>

fun invokePostLinkageSteps() {
postLinkageSteps.forEach { it() }
}

fun KotlinType.toIrType() = typeTranslator.translateType(this)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ 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.backend.konan.ir.interop.cstruct.CStructVarCompanionGenerator
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.*
Expand Down Expand Up @@ -50,8 +51,10 @@ internal class IrProviderForCEnumAndCStructStubs(
CEnumVarClassGenerator(context, interopBuiltIns)
private val cEnumClassGenerator =
CEnumClassGenerator(context, cEnumCompanionGenerator, cEnumVarClassGenerator)
private val cStructCompanionGenerator =
CStructVarCompanionGenerator(context, interopBuiltIns)
private val cStructClassGenerator =
CStructVarClassGenerator(context, interopBuiltIns)
CStructVarClassGenerator(context, interopBuiltIns, cStructCompanionGenerator)

fun isCEnumOrCStruct(declarationDescriptor: DeclarationDescriptor): Boolean =
declarationDescriptor.run { findCEnumDescriptor(interopBuiltIns) ?: findCStructDescriptor(interopBuiltIns) } != null
Expand All @@ -73,6 +76,19 @@ internal class IrProviderForCEnumAndCStructStubs(
}
}

/**
* We postpone generation of bodies until IR linkage is complete.
* This way we ensure that all used symbols are resolved.
*/
fun generateBodies() {
cEnumCompanionGenerator.invokePostLinkageSteps()
cEnumByValueFunctionGenerator.invokePostLinkageSteps()
cEnumClassGenerator.invokePostLinkageSteps()
cEnumVarClassGenerator.invokePostLinkageSteps()
cStructClassGenerator.invokePostLinkageSteps()
cStructCompanionGenerator.invokePostLinkageSteps()
}

fun getDeclaration(descriptor: DeclarationDescriptor, idSignature: IdSignature, file: IrFile, symbolKind: BinarySymbolData.SymbolKind): IrSymbolOwner {
return symbolTable.run {
when (symbolKind) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal class CEnumByValueFunctionGenerator(
override val irBuiltIns: IrBuiltIns = context.irBuiltIns
override val symbolTable: SymbolTable = context.symbolTable
override val typeTranslator: TypeTranslator = context.typeTranslator
override val postLinkageSteps: MutableList<() -> Unit> = mutableListOf()

fun generateByValueFunction(
companionIrClass: IrClass,
Expand All @@ -51,46 +52,48 @@ internal class CEnumByValueFunctionGenerator(
// i++
// }
// throw NPE
byValueIrFunction.body = irBuilder(irBuiltIns, byValueIrFunction.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+irReturn(irBlock {
val values = irTemporary(irCall(valuesIrFunctionSymbol), isMutable = true)
val inductionVariable = irTemporary(irInt(0), isMutable = true)
val arrayClass = values.type.classOrNull!!
val valuesSize = irCall(symbols.arraySize.getValue(arrayClass), irBuiltIns.intType).also { irCall ->
irCall.dispatchReceiver = irGet(values)
}
val getElementFn = symbols.arrayGet.getValue(arrayClass)
val plusFun = symbols.getBinaryOperator(OperatorNameConventions.PLUS, irBuiltIns.intType, irBuiltIns.intType)
val lessFunctionSymbol = irBuiltIns.lessFunByOperandType.getValue(irBuiltIns.intClass)
+irWhile().also { loop ->
loop.condition = irCall(lessFunctionSymbol, irBuiltIns.booleanType).also { irCall ->
irCall.putValueArgument(0, irGet(inductionVariable))
irCall.putValueArgument(1, valuesSize)
postLinkageSteps.add {
byValueIrFunction.body = irBuilder(irBuiltIns, byValueIrFunction.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+irReturn(irBlock {
val values = irTemporary(irCall(valuesIrFunctionSymbol), isMutable = true)
val inductionVariable = irTemporary(irInt(0), isMutable = true)
val arrayClass = values.type.classOrNull!!
val valuesSize = irCall(symbols.arraySize.getValue(arrayClass), irBuiltIns.intType).also { irCall ->
irCall.dispatchReceiver = irGet(values)
}
loop.body = irBlock {
val entry = irTemporary(irCall(getElementFn, byValueIrFunction.returnType).also { irCall ->
irCall.dispatchReceiver = irGet(values)
val getElementFn = symbols.arrayGet.getValue(arrayClass)
val plusFun = symbols.getBinaryOperator(OperatorNameConventions.PLUS, irBuiltIns.intType, irBuiltIns.intType)
val lessFunctionSymbol = irBuiltIns.lessFunByOperandType.getValue(irBuiltIns.intClass)
+irWhile().also { loop ->
loop.condition = irCall(lessFunctionSymbol, irBuiltIns.booleanType).also { irCall ->
irCall.putValueArgument(0, irGet(inductionVariable))
}, isMutable = true)
val valueGetter = entry.type.getClass()!!.getPropertyGetter("value")!!
val entryValue = irGet(irValueParameter.type, irGet(entry), valueGetter)
+irIfThenElse(
type = irBuiltIns.unitType,
condition = irEquals(entryValue, irGet(irValueParameter)),
thenPart = irReturn(irGet(entry)),
elsePart = irSetVar(
inductionVariable,
irCallOp(plusFun, irBuiltIns.intType,
irGet(inductionVariable),
irInt(1)
)
)
)
irCall.putValueArgument(1, valuesSize)
}
loop.body = irBlock {
val entry = irTemporary(irCall(getElementFn, byValueIrFunction.returnType).also { irCall ->
irCall.dispatchReceiver = irGet(values)
irCall.putValueArgument(0, irGet(inductionVariable))
}, isMutable = true)
val valueGetter = entry.type.getClass()!!.getPropertyGetter("value")!!
val entryValue = irGet(irValueParameter.type, irGet(entry), valueGetter)
+irIfThenElse(
type = irBuiltIns.unitType,
condition = irEquals(entryValue, irGet(irValueParameter)),
thenPart = irReturn(irGet(entry)),
elsePart = irSetVar(
inductionVariable,
irCallOp(plusFun, irBuiltIns.intType,
irGet(inductionVariable),
irInt(1)
)
)
)
}
}
}
+IrCallImpl.fromSymbolDescriptor(startOffset, endOffset, irBuiltIns.nothingType,
symbols.throwNullPointerException)
})
+IrCallImpl.fromSymbolOwner(startOffset, endOffset, irBuiltIns.nothingType,
symbols.throwNullPointerException)
})
}
}
return byValueIrFunction
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ internal class CEnumClassGenerator(
override val irBuiltIns: IrBuiltIns = context.irBuiltIns
override val symbolTable: SymbolTable = context.symbolTable
override val typeTranslator: TypeTranslator = context.typeTranslator
override val postLinkageSteps: MutableList<() -> Unit> = mutableListOf()

private val enumClassMembersGenerator = EnumClassMembersGenerator(DeclarationGenerator(context))

Expand Down Expand Up @@ -97,38 +98,46 @@ internal class CEnumClassGenerator(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
propertyDescriptor, propertyDescriptor.type.toIrType(), DescriptorVisibilities.PRIVATE
).also {
it.initializer = irBuilder(irBuiltIns, it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).run {
irExprBody(irGet(irClass.primaryConstructor!!.valueParameters[0]))
postLinkageSteps.add {
it.initializer = irBuilder(irBuiltIns, it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).run {
irExprBody(irGet(irClass.primaryConstructor!!.valueParameters[0]))
}
}
}
}
val getter = irProperty.getter!!
getter.correspondingPropertySymbol = irProperty.symbol
getter.body = irBuilder(irBuiltIns, getter.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+irReturn(
irGetField(
irGet(getter.dispatchReceiverParameter!!),
irProperty.backingField!!
)
)
postLinkageSteps.add {
getter.body = irBuilder(irBuiltIns, getter.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+irReturn(
irGetField(
irGet(getter.dispatchReceiverParameter!!),
irProperty.backingField!!
)
)
}
}
return irProperty
}

private fun createEnumEntry(enumDescriptor: ClassDescriptor, entryDescriptor: ClassDescriptor): IrEnumEntry {
return symbolTable.declareEnumEntry(
val enumEntry = symbolTable.declareEnumEntry(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB, entryDescriptor
).also { enumEntry ->
enumEntry.initializerExpression = IrExpressionBodyImpl(IrEnumConstructorCallImpl.fromSymbolDescriptor(
)
val constructorSymbol = symbolTable.referenceConstructor(enumDescriptor.unsubstitutedPrimaryConstructor!!)
postLinkageSteps.add {
enumEntry.initializerExpression = IrExpressionBodyImpl(IrEnumConstructorCallImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
type = irBuiltIns.unitType,
symbol = symbolTable.referenceConstructor(enumDescriptor.unsubstitutedPrimaryConstructor!!),
typeArgumentsCount = 0 // enums can't be generic
symbol = constructorSymbol,
typeArgumentsCount = 0,
valueArgumentsCount = constructorSymbol.owner.valueParameters.size
).also {
it.putValueArgument(0, extractEnumEntryValue(entryDescriptor))
})
}
return enumEntry
}

/**
Expand All @@ -146,16 +155,23 @@ internal class CEnumClassGenerator(
private fun createEnumPrimaryConstructor(descriptor: ClassDescriptor): IrConstructor {
val irConstructor = createConstructor(descriptor.unsubstitutedPrimaryConstructor!!)
val enumConstructor = context.builtIns.enum.constructors.single()
irConstructor.body = irBuilder(irBuiltIns, irConstructor.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrEnumConstructorCallImpl.fromSymbolDescriptor(
startOffset, endOffset,
context.irBuiltIns.unitType,
symbolTable.referenceConstructor(enumConstructor),
typeArgumentsCount = 1 // kotlin.Enum<T> has a single type parameter.
).apply {
putTypeArgument(0, descriptor.defaultType.toIrType())
}
+irInstanceInitializer(symbolTable.referenceClass(descriptor))
val constructorSymbol = symbolTable.referenceConstructor(enumConstructor)
val classSymbol = symbolTable.referenceClass(descriptor)
val type = descriptor.defaultType.toIrType()
postLinkageSteps.add {
irConstructor.body = irBuilder(irBuiltIns, irConstructor.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET)
.irBlockBody {
+IrEnumConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
constructorSymbol,
typeArgumentsCount = 1, // kotlin.Enum<T> has a single type parameter.
valueArgumentsCount = constructorSymbol.owner.valueParameters.size
).apply {
putTypeArgument(0, type)
}
+irInstanceInitializer(classSymbol)
}
}
return irConstructor
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ internal class CEnumCompanionGenerator(
override val irBuiltIns: IrBuiltIns = context.irBuiltIns
override val symbolTable: SymbolTable = context.symbolTable
override val typeTranslator: TypeTranslator = context.typeTranslator
override val postLinkageSteps: MutableList<() -> Unit> = mutableListOf()

// Depends on already generated `.values()` irFunction.
fun generate(enumClass: IrClass): IrClass =
Expand All @@ -50,13 +51,16 @@ internal class CEnumCompanionGenerator(
private fun createCompanionConstructor(companionObjectDescriptor: ClassDescriptor): IrConstructor {
val anyPrimaryConstructor = companionObjectDescriptor.builtIns.any.unsubstitutedPrimaryConstructor!!
val superConstructorSymbol = symbolTable.referenceConstructor(anyPrimaryConstructor)
val classSymbol = symbolTable.referenceClass(companionObjectDescriptor)
return createConstructor(companionObjectDescriptor.unsubstitutedPrimaryConstructor!!).also {
it.body = irBuilder(irBuiltIns, it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrDelegatingConstructorCallImpl.fromSymbolDescriptor(
startOffset, endOffset, context.irBuiltIns.unitType,
superConstructorSymbol
)
+irInstanceInitializer(symbolTable.referenceClass(companionObjectDescriptor))
postLinkageSteps.add {
it.body = irBuilder(irBuiltIns, it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrDelegatingConstructorCallImpl.fromSymbolOwner(
startOffset, endOffset, context.irBuiltIns.unitType,
superConstructorSymbol
)
+irInstanceInitializer(classSymbol)
}
}
}
}
Expand Down Expand Up @@ -88,7 +92,9 @@ internal class CEnumCompanionGenerator(
private fun declareEntryAliasProperty(propertyDescriptor: PropertyDescriptor, enumClass: IrClass): IrProperty {
val entrySymbol = fundCorrespondingEnumEntrySymbol(propertyDescriptor, enumClass)
return createProperty(propertyDescriptor).also {
it.getter!!.body = generateAliasGetterBody(it.getter!!, entrySymbol, enumClass)
postLinkageSteps.add {
it.getter!!.body = generateAliasGetterBody(it.getter!!, entrySymbol, enumClass)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ internal class CEnumVarClassGenerator(
override val irBuiltIns: IrBuiltIns = context.irBuiltIns
override val symbolTable: SymbolTable = context.symbolTable
override val typeTranslator: TypeTranslator = context.typeTranslator
override val postLinkageSteps: MutableList<() -> Unit> = mutableListOf()

fun generate(enumIrClass: IrClass): IrClass {
val enumVarClassDescriptor = enumIrClass.descriptor.unsubstitutedMemberScope
Expand All @@ -56,13 +57,16 @@ internal class CEnumVarClassGenerator(
val enumVarConstructorSymbol = symbolTable.referenceConstructor(
interopBuiltIns.cEnumVar.unsubstitutedPrimaryConstructor!!
)
irConstructor.body = irBuilder(irBuiltIns, irConstructor.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrDelegatingConstructorCallImpl.fromSymbolDescriptor(
startOffset, endOffset, context.irBuiltIns.unitType, enumVarConstructorSymbol
).also {
it.putValueArgument(0, irGet(irConstructor.valueParameters[0]))
val classSymbol = symbolTable.referenceClass(enumVarClass.descriptor)
postLinkageSteps.add {
irConstructor.body = irBuilder(irBuiltIns, irConstructor.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrDelegatingConstructorCallImpl.fromSymbolOwner(
startOffset, endOffset, context.irBuiltIns.unitType, enumVarConstructorSymbol
).also {
it.putValueArgument(0, irGet(irConstructor.valueParameters[0]))
}
+irInstanceInitializer(classSymbol)
}
+irInstanceInitializer(symbolTable.referenceClass(enumVarClass.descriptor))
}
return irConstructor
}
Expand All @@ -77,15 +81,18 @@ internal class CEnumVarClassGenerator(

private fun createCompanionConstructor(companionObjectDescriptor: ClassDescriptor, typeSize: Int): IrConstructor {
val superConstructorSymbol = symbolTable.referenceConstructor(interopBuiltIns.cPrimitiveVarType.unsubstitutedPrimaryConstructor!!)
val classSymbol = symbolTable.referenceClass(companionObjectDescriptor)
return createConstructor(companionObjectDescriptor.unsubstitutedPrimaryConstructor!!).also {
it.body = irBuilder(irBuiltIns, it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrDelegatingConstructorCallImpl.fromSymbolDescriptor(
startOffset, endOffset, context.irBuiltIns.unitType,
superConstructorSymbol
).also {
it.putValueArgument(0, irInt(typeSize))
postLinkageSteps.add {
it.body = irBuilder(irBuiltIns, it.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody {
+IrDelegatingConstructorCallImpl.fromSymbolOwner(
startOffset, endOffset, context.irBuiltIns.unitType,
superConstructorSymbol
).also {
it.putValueArgument(0, irInt(typeSize))
}
+irInstanceInitializer(classSymbol)
}
+irInstanceInitializer(symbolTable.referenceClass(companionObjectDescriptor))
}
}
}
Expand Down
Loading

0 comments on commit a012e23

Please sign in to comment.