[K/N][IR] Refactored enums lowering
This commit is contained in:
+4
-4
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.backend.konan.lower.BridgesSupport
|
||||
import org.jetbrains.kotlin.backend.konan.lower.EnumsSupport
|
||||
import org.jetbrains.kotlin.backend.konan.lower.InlineFunctionsSupport
|
||||
import org.jetbrains.kotlin.backend.konan.lower.InnerClassesSupport
|
||||
import org.jetbrains.kotlin.backend.konan.lower.InternalLoweredEnum
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis
|
||||
import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG
|
||||
@@ -60,11 +59,12 @@ internal class NativeMapping : DefaultMapping() {
|
||||
data class BridgeKey(val target: IrSimpleFunction, val bridgeDirections: BridgeDirections)
|
||||
|
||||
val outerThisFields = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
||||
val enumImplObjects = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrClass>()
|
||||
val enumValueGetters = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrFunction>()
|
||||
val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>()
|
||||
val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
|
||||
val notLoweredInlineFunctions = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
||||
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||
val internalLoweredEnums = mutableMapOf<IrClass, InternalLoweredEnum>()
|
||||
val externalLoweredEnums = mutableMapOf<IrClass, ExternalLoweredEnum>()
|
||||
}
|
||||
|
||||
internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
@@ -104,7 +104,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
val innerClassesSupport by lazy { InnerClassesSupport(mapping, irFactory) }
|
||||
val bridgesSupport by lazy { BridgesSupport(mapping, irBuiltIns, irFactory) }
|
||||
val inlineFunctionsSupport by lazy { InlineFunctionsSupport(mapping) }
|
||||
val enumsSupport by lazy { EnumsSupport(this) }
|
||||
val enumsSupport by lazy { EnumsSupport(mapping, ir.symbols, irBuiltIns, irFactory) }
|
||||
|
||||
open class LazyMember<T>(val initializer: Context.() -> T) {
|
||||
operator fun getValue(thisRef: Context, property: KProperty<*>): T = thisRef.getValue(this)
|
||||
|
||||
+35
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMo
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.lower.CacheInfoBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_ENUM
|
||||
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
||||
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
@@ -427,6 +429,21 @@ internal val exportInternalAbiPhase = makeKonanModuleOpPhase(
|
||||
}
|
||||
context.internalAbi.declare(function, declaration.module)
|
||||
}
|
||||
|
||||
if (declaration.isEnumClass) {
|
||||
val function = context.irFactory.buildFun {
|
||||
name = InternalAbi.getEnumValuesAccessorName(declaration)
|
||||
returnType = context.ir.symbols.array.typeWith(declaration.defaultType)
|
||||
origin = InternalAbi.INTERNAL_ABI_ORIGIN
|
||||
}
|
||||
|
||||
context.createIrBuilder(function.symbol).run {
|
||||
function.body = irBlockBody {
|
||||
+irReturn(with(context.enumsSupport) { irGetValuesField(declaration) })
|
||||
}
|
||||
}
|
||||
context.internalAbi.declare(function, declaration.module)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitProperty(declaration: IrProperty) {
|
||||
@@ -470,6 +487,7 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
|
||||
val companionObjectAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
||||
val outerThisAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
||||
val lateinitPropertyAccessors = mutableMapOf<IrProperty, IrSimpleFunction>()
|
||||
val enumValuesAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
|
||||
|
||||
val transformer = object : IrElementTransformerVoid() {
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||
@@ -561,6 +579,23 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
|
||||
}
|
||||
}
|
||||
|
||||
field.origin == DECLARATION_ORIGIN_ENUM -> {
|
||||
val enumClass = irClass?.parentClassOrNull
|
||||
require(enumClass != null) { "Unexpected usage of enum VALUES field" }
|
||||
require(enumClass.isEnumClass) { "Expected a enum class: ${enumClass.render()}" }
|
||||
val accessor = enumValuesAccessors.getOrPut(enumClass) {
|
||||
context.irFactory.buildFun {
|
||||
name = InternalAbi.getEnumValuesAccessorName(enumClass)
|
||||
returnType = context.ir.symbols.array.typeWith(enumClass.defaultType)
|
||||
origin = InternalAbi.INTERNAL_ABI_ORIGIN
|
||||
isExternal = true
|
||||
}.also {
|
||||
context.internalAbi.reference(it, enumClass.module)
|
||||
}
|
||||
}
|
||||
return IrCallImpl(expression.startOffset, expression.endOffset, expression.type, accessor.symbol, accessor.typeParameters.size, accessor.valueParameters.size)
|
||||
}
|
||||
|
||||
else -> expression
|
||||
}
|
||||
}
|
||||
|
||||
+3
-12
@@ -1366,19 +1366,10 @@ internal abstract class FunctionGenerationContext(
|
||||
*/
|
||||
fun getEnumEntry(enumEntry: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
|
||||
val enumClass = enumEntry.parentAsClass
|
||||
val loweredEnum = context.enumsSupport.getLoweredEnum(enumClass)
|
||||
|
||||
val getterId = loweredEnum.entriesMap[enumEntry.name]!!.getterId
|
||||
val values = call(
|
||||
loweredEnum.valuesGetter.llvmFunction.llvmValue,
|
||||
emptyList(),
|
||||
Lifetime.ARGUMENT,
|
||||
exceptionHandler
|
||||
)
|
||||
|
||||
val getterId = context.enumsSupport.enumEntriesMap(enumClass)[enumEntry.name]!!.getterId
|
||||
return call(
|
||||
loweredEnum.itemGetterSymbol.owner.llvmFunction.llvmValue,
|
||||
listOf(values, Int32(getterId).llvm),
|
||||
context.enumsSupport.getValueGetter(enumClass).llvmFunction.llvmValue,
|
||||
listOf(Int32(getterId).llvm),
|
||||
Lifetime.GLOBAL,
|
||||
exceptionHandler
|
||||
)
|
||||
|
||||
+112
-176
@@ -18,53 +18,27 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERING_FOR_CALL
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrPropertySymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private class EnumSyntheticFunctionsBuilder(val context: Context) {
|
||||
fun IrBuilderWithScope.enumValues(enumClass: IrClass): IrExpression {
|
||||
val loweredEnum = this@EnumSyntheticFunctionsBuilder.context.enumsSupport.getLoweredEnum(enumClass)
|
||||
return irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply {
|
||||
putValueArgument(0, loweredEnum.getValuesField(startOffset, endOffset))
|
||||
}
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.enumValueOf(enumClass: IrClass, value: IrExpression): IrExpression {
|
||||
val loweredEnum = this@EnumSyntheticFunctionsBuilder.context.enumsSupport.getLoweredEnum(enumClass)
|
||||
return irCall(genericValueOfSymbol, listOf(enumClass.defaultType)).apply {
|
||||
putValueArgument(0, value)
|
||||
putValueArgument(1, loweredEnum.getValuesField(startOffset, endOffset))
|
||||
}
|
||||
}
|
||||
|
||||
private val genericValueOfSymbol = context.ir.symbols.valueOfForEnum
|
||||
|
||||
private val genericValuesSymbol = context.ir.symbols.valuesForEnum
|
||||
}
|
||||
|
||||
internal class NativeEnumWhenLowering constructor(context: Context) : EnumWhenLowering(context) {
|
||||
override fun mapConstEnumEntry(entry: IrEnumEntry): Int {
|
||||
val parent = entry.parentAsClass
|
||||
val loweredEnum = (context as Context).enumsSupport.getLoweredEnumOrNull(parent)
|
||||
?: return super.mapConstEnumEntry(entry)
|
||||
return loweredEnum.entriesMap[entry.name]!!.ordinal
|
||||
val enumEntriesMap = (context as Context).enumsSupport.enumEntriesMap(entry.parentAsClass)
|
||||
return enumEntriesMap[entry.name]!!.ordinal
|
||||
}
|
||||
}
|
||||
|
||||
internal class EnumUsageLowering(val context: Context)
|
||||
: IrElementTransformer<IrBuilderWithScope?>, FileLoweringPass {
|
||||
|
||||
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
|
||||
internal class EnumUsageLowering(val context: Context) : IrElementTransformer<IrBuilderWithScope?>, FileLoweringPass {
|
||||
private val enumsSupport = context.enumsSupport
|
||||
private val symbols = context.ir.symbols
|
||||
private val arrayGet = symbols.arrayGet[symbols.array]!!
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
visitFile(irFile, data = null)
|
||||
@@ -99,25 +73,28 @@ internal class EnumUsageLowering(val context: Context)
|
||||
|
||||
require(irClass.kind == ClassKind.ENUM_CLASS)
|
||||
|
||||
return with(enumSyntheticFunctionsBuilder) {
|
||||
return with(enumsSupport) {
|
||||
if (intrinsicType == IntrinsicType.ENUM_VALUES)
|
||||
data.enumValues(irClass)
|
||||
data.irEnumValues(irClass)
|
||||
else
|
||||
data.enumValueOf(irClass, expression.getValueArgument(0)!!)
|
||||
data.irEnumValueOf(irClass, expression.getValueArgument(0)!!)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.loadEnumEntry(enumClass: IrClass, name: Name): IrExpression {
|
||||
val loweredEnum = this@EnumUsageLowering.context.enumsSupport.getLoweredEnum(enumClass)
|
||||
val getterId = loweredEnum.entriesMap.getValue(name).getterId
|
||||
return irCall(loweredEnum.itemGetterSymbol, enumClass.defaultType).apply {
|
||||
dispatchReceiver = irCall(loweredEnum.valuesGetter)
|
||||
putValueArgument(0, irInt(getterId))
|
||||
}
|
||||
}
|
||||
private fun IrBuilderWithScope.loadEnumEntry(enumClass: IrClass, name: Name) =
|
||||
irCall(arrayGet, enumClass.defaultType).apply {
|
||||
dispatchReceiver = with(enumsSupport) { irGetValuesField(enumClass) }
|
||||
putValueArgument(0, irInt(enumsSupport.enumEntriesMap(enumClass).getValue(name).getterId))
|
||||
}
|
||||
}
|
||||
|
||||
internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
||||
private val enumsSupport = context.enumsSupport
|
||||
private val symbols = context.ir.symbols
|
||||
private val createUninitializedInstance = symbols.createUninitializedInstance
|
||||
private val initInstance = symbols.initInstance
|
||||
private val arrayGet = symbols.arrayGet[symbols.array]!!
|
||||
private val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
@@ -131,167 +108,137 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
||||
}
|
||||
|
||||
private inner class EnumClassTransformer(val irClass: IrClass) {
|
||||
private val loweredEnum = context.enumsSupport.getInternalLoweredEnum(irClass)
|
||||
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
|
||||
private val implObject = enumsSupport.getImplObject(irClass)
|
||||
private val valuesField = enumsSupport.getValuesField(implObject)
|
||||
private val enumEntriesMap = enumsSupport.enumEntriesMap(irClass)
|
||||
|
||||
fun run() {
|
||||
pullUpEnumEntriesClasses()
|
||||
createImplObject()
|
||||
val enumEntries = transformEnumBody()
|
||||
defineImplObject(enumEntries)
|
||||
defineValueGetter()
|
||||
}
|
||||
|
||||
private fun pullUpEnumEntriesClasses() {
|
||||
irClass.declarations.transformFlat { declaration ->
|
||||
if (declaration is IrEnumEntry) {
|
||||
val correspondingClass = declaration.correspondingClass
|
||||
declaration.correspondingClass = null
|
||||
listOfNotNull(declaration, correspondingClass)
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun createImplObject() {
|
||||
val implObject = loweredEnum.implObject
|
||||
|
||||
private fun transformEnumBody(): List<IrEnumEntry> {
|
||||
val enumEntries = mutableListOf<IrEnumEntry>()
|
||||
var i = 0
|
||||
while (i < irClass.declarations.size) {
|
||||
val declaration = irClass.declarations[i]
|
||||
var delete = false
|
||||
irClass.declarations.transformFlat { declaration ->
|
||||
when (declaration) {
|
||||
is IrEnumEntry -> {
|
||||
enumEntries.add(declaration)
|
||||
delete = true
|
||||
val correspondingClass = declaration.correspondingClass
|
||||
declaration.correspondingClass = null
|
||||
listOfNotNull(correspondingClass)
|
||||
}
|
||||
|
||||
is IrFunction -> {
|
||||
val body = declaration.body
|
||||
if (body is IrSyntheticBody) {
|
||||
when (body.kind) {
|
||||
IrSyntheticBodyKind.ENUM_VALUEOF ->
|
||||
declaration.body = createSyntheticValueOfMethodBody(declaration)
|
||||
IrSyntheticBodyKind.ENUM_VALUES ->
|
||||
declaration.body = createSyntheticValuesMethodBody(declaration)
|
||||
declaration.body = when (body.kind) {
|
||||
IrSyntheticBodyKind.ENUM_VALUEOF -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) {
|
||||
+irReturn(with(enumsSupport) { irEnumValueOf(irClass, irGet(declaration.valueParameters[0])) })
|
||||
}
|
||||
|
||||
IrSyntheticBodyKind.ENUM_VALUES -> context.createIrBuilder(declaration.symbol).irBlockBody(declaration) {
|
||||
+irReturn(with(enumsSupport) { irEnumValues(irClass) })
|
||||
}
|
||||
|
||||
IrSyntheticBodyKind.ENUM_ENTRIES -> TODO("KT-48872 is not yet supported")
|
||||
}
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
if (delete)
|
||||
irClass.declarations.removeAt(i)
|
||||
else
|
||||
++i
|
||||
}
|
||||
return enumEntries
|
||||
}
|
||||
|
||||
implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
|
||||
private fun defineValueGetter() {
|
||||
val valueGetter = enumsSupport.getValueGetter(irClass)
|
||||
context.createIrBuilder(valueGetter.symbol).run {
|
||||
valueGetter.body = irBlockBody(valueGetter) {
|
||||
+irReturn(irCall(arrayGet, irClass.defaultType).apply {
|
||||
dispatchReceiver = with(enumsSupport) { irGetValuesField(irClass) }
|
||||
putValueArgument(0, irGet(valueGetter.valueParameters[0]))
|
||||
})
|
||||
}
|
||||
}
|
||||
irClass.declarations.add(valueGetter)
|
||||
}
|
||||
|
||||
private fun defineImplObject(enumEntries: List<IrEnumEntry>) {
|
||||
implObject.createParameterDeclarations()
|
||||
|
||||
implObject.addSimpleDelegatingConstructor(constructorOfAny, context.irBuiltIns, true /* TODO: why primary? */)
|
||||
implObject.addFakeOverrides(context.typeSystem)
|
||||
irClass.declarations.add(implObject)
|
||||
|
||||
ImplConstructorBuilder(implObject.constructors.single()).build(enumEntries)
|
||||
}
|
||||
|
||||
private inner class ImplConstructorBuilder(val constructor: IrConstructor) {
|
||||
private val irBuilder = context.createIrBuilder(constructor.symbol, constructor.startOffset, constructor.endOffset)
|
||||
|
||||
fun build(enumEntries: List<IrEnumEntry>) {
|
||||
val statements = (constructor.body as IrBlockBody).statements
|
||||
|
||||
val companion = irClass.companionObject()
|
||||
if (companion != null) {
|
||||
// The initialization order is the following:
|
||||
// - first all enum entries in their declaration order
|
||||
// - then companion object if it exists
|
||||
val constructor = implObject.constructors.single()
|
||||
context.createIrBuilder(constructor.symbol).run {
|
||||
(constructor.body as IrBlockBody).statements += irGetObject(companion.symbol)
|
||||
}
|
||||
statements += buildValuesFieldInitializer(enumEntries)
|
||||
// Split allocation and constructors calling because enum entries can reference one another.
|
||||
statements += callEnumEntriesConstructors(enumEntries)
|
||||
|
||||
irClass.companionObject()?.let { statements += irBuilder.irGetObject(it.symbol) }
|
||||
}
|
||||
|
||||
irClass.declarations += implObject
|
||||
}
|
||||
|
||||
private val createUninitializedInstance = context.ir.symbols.createUninitializedInstance.owner
|
||||
|
||||
private fun createSyntheticValuesPropertyDeclaration(enumEntries: List<IrEnumEntry>): IrProperty {
|
||||
val startOffset = irClass.startOffset
|
||||
val endOffset = irClass.endOffset
|
||||
|
||||
val implObject = loweredEnum.implObject
|
||||
val constructor = implObject.constructors.single()
|
||||
|
||||
val irValuesInitializer = context.createArrayOfExpression(
|
||||
startOffset, endOffset,
|
||||
irClass.defaultType,
|
||||
enumEntries
|
||||
.sortedBy { it.name }
|
||||
.map {
|
||||
val initializer = it.initializerExpression?.expression
|
||||
val entryConstructorCall = when {
|
||||
initializer is IrConstructorCall -> initializer
|
||||
|
||||
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
|
||||
initializer.statements.last() as IrConstructorCall
|
||||
|
||||
else -> error("Unexpected initializer: $initializer")
|
||||
}
|
||||
val entryClass = entryConstructorCall.symbol.owner.constructedClass
|
||||
|
||||
irCall(startOffset, endOffset,
|
||||
createUninitializedInstance,
|
||||
listOf(entryClass.defaultType)
|
||||
)
|
||||
|
||||
}
|
||||
)
|
||||
val irField = loweredEnum.valuesField
|
||||
context.createIrBuilder(constructor.symbol).run {
|
||||
(constructor.body as IrBlockBody).statements +=
|
||||
irSetField(irGet(implObject.thisReceiver!!), irField, irValuesInitializer)
|
||||
}
|
||||
|
||||
val getter = loweredEnum.valuesGetter
|
||||
context.createIrBuilder(getter.symbol).run {
|
||||
getter.body = irBlockBody(irClass) { +irReturn(irGetField(irGetObject(implObject.symbol), irField)) }
|
||||
}
|
||||
|
||||
createValuesPropertyInitializer(enumEntries)
|
||||
|
||||
return with(loweredEnum.valuesField.descriptor) {
|
||||
IrPropertyImpl(
|
||||
startOffset, endOffset, DECLARATION_ORIGIN_ENUM, IrPropertySymbolImpl(this),
|
||||
name, visibility, modality, isVar, isConst, isLateInit, isDelegated, isExternal
|
||||
).apply {
|
||||
this.backingField = irField
|
||||
this.getter = getter
|
||||
this.parent = implObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val initInstanceSymbol = context.ir.symbols.initInstance
|
||||
|
||||
private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.owner.name == Name.identifier("get") }
|
||||
|
||||
private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType)
|
||||
|
||||
private fun createValuesPropertyInitializer(enumEntries: List<IrEnumEntry>) {
|
||||
val startOffset = irClass.startOffset
|
||||
val endOffset = irClass.endOffset
|
||||
|
||||
fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrConstructorCall): IrCall =
|
||||
irCall(initInstanceSymbol).apply {
|
||||
private fun IrBlockBuilder.irInitInstanceCall(instance: IrCall, constructor: IrConstructorCall): IrCall =
|
||||
irCall(initInstance).apply {
|
||||
putValueArgument(0, instance)
|
||||
putValueArgument(1, constructor)
|
||||
}
|
||||
|
||||
val implObject = loweredEnum.implObject
|
||||
val constructor = implObject.constructors.single()
|
||||
val irBuilder = context.createIrBuilder(constructor.symbol, startOffset, endOffset)
|
||||
val valuesInitializer = irBuilder.irBlock(startOffset, endOffset) {
|
||||
private fun buildValuesFieldInitializer(enumEntries: List<IrEnumEntry>) = irBuilder.run {
|
||||
val irValuesInitializer = this@EnumClassLowering.context.createArrayOfExpression(
|
||||
startOffset, endOffset,
|
||||
irClass.defaultType,
|
||||
enumEntries
|
||||
.sortedBy { it.name }
|
||||
.map {
|
||||
val initializer = it.initializerExpression?.expression
|
||||
val entryConstructorCall = when {
|
||||
initializer is IrConstructorCall -> initializer
|
||||
|
||||
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
|
||||
initializer.statements.last() as IrConstructorCall
|
||||
|
||||
else -> error("Unexpected initializer: $initializer")
|
||||
}
|
||||
val entryClass = entryConstructorCall.symbol.owner.constructedClass
|
||||
|
||||
irCall(createUninitializedInstance, listOf(entryClass.defaultType))
|
||||
}
|
||||
)
|
||||
irSetField(irGet(implObject.thisReceiver!!), valuesField, irValuesInitializer)
|
||||
}
|
||||
|
||||
private fun callEnumEntriesConstructors(enumEntries: List<IrEnumEntry>) = irBuilder.irBlock {
|
||||
val receiver = implObject.thisReceiver!!
|
||||
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
|
||||
val enumIndices = enumEntries.sortedBy { it.name }.withIndex().associate { it.value to it.index }
|
||||
val instances = irTemporary(irGetField(irGet(receiver), valuesField))
|
||||
enumEntries.forEach {
|
||||
val instance = irCall(arrayGetSymbol).apply {
|
||||
val instance = irCall(arrayGet).apply {
|
||||
dispatchReceiver = irGet(instances)
|
||||
putValueArgument(0, irInt(enumIndices[it]!!))
|
||||
putValueArgument(0, irInt(enumEntriesMap[it.name]!!.getterId))
|
||||
}
|
||||
val initializer = it.initializerExpression!!.expression
|
||||
initializer.setDeclarationsParent(constructor)
|
||||
when {
|
||||
initializer is IrConstructorCall -> +initInstanceCall(instance, initializer)
|
||||
initializer is IrConstructorCall -> +irInitInstanceCall(instance, initializer)
|
||||
|
||||
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
|
||||
val statements = initializer.statements
|
||||
val constructorCall = statements.last() as IrConstructorCall
|
||||
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
|
||||
statements[statements.lastIndex] = irInitInstanceCall(instance, constructorCall)
|
||||
+initializer
|
||||
}
|
||||
|
||||
@@ -300,22 +247,11 @@ internal class EnumClassLowering(val context: Context) : FileLoweringPass {
|
||||
}
|
||||
// Needed for legacy MM targets that do not support threads.
|
||||
if (this@EnumClassLowering.context.memoryModel != MemoryModel.EXPERIMENTAL) {
|
||||
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
|
||||
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(valuesField.type)).apply {
|
||||
extensionReceiver = irGet(receiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
(constructor.body as IrBlockBody).statements += valuesInitializer
|
||||
}
|
||||
|
||||
private fun createSyntheticValuesMethodBody(declaration: IrFunction) =
|
||||
context.createIrBuilder(declaration.symbol, irClass.startOffset, irClass.endOffset).irBlockBody {
|
||||
+irReturn(with(enumSyntheticFunctionsBuilder) { enumValues(irClass) })
|
||||
}
|
||||
|
||||
private fun createSyntheticValueOfMethodBody(declaration: IrFunction) =
|
||||
context.createIrBuilder(declaration.symbol, irClass.startOffset, irClass.endOffset).irBlockBody {
|
||||
+irReturn(with(enumSyntheticFunctionsBuilder) { enumValueOf(irClass, irGet(declaration.valueParameters[0])) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
|
||||
|
||||
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
|
||||
val name = enumEntry.name.asString()
|
||||
val ordinal = context.enumsSupport.getEnumEntryOrdinal(enumEntry)
|
||||
val ordinal = context.enumsSupport.enumEntriesMap(enumEntry.parentAsClass)[enumEntry.name]!!.ordinal
|
||||
|
||||
val startOffset = enumConstructorCall.startOffset
|
||||
val endOffset = enumConstructorCall.endOffset
|
||||
|
||||
+86
-223
@@ -5,255 +5,118 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.InternalAbi
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.konan.NativeMapping
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class EnumsSupport(private val context: Context) {
|
||||
private val enumSpecialDeclarationsFactory = EnumSpecialDeclarationsFactory(context)
|
||||
private val internalLoweredEnums = context.mapping.internalLoweredEnums
|
||||
private val externalLoweredEnums = context.mapping.externalLoweredEnums
|
||||
internal class EnumsSupport(
|
||||
mapping: NativeMapping,
|
||||
symbols: KonanSymbols,
|
||||
private val irBuiltIns: IrBuiltIns,
|
||||
private val irFactory: IrFactory,
|
||||
) {
|
||||
private val enumImplObjects = mapping.enumImplObjects
|
||||
private val enumValueGetters = mapping.enumValueGetters
|
||||
private val enumEntriesMaps = mapping.enumEntriesMaps
|
||||
private val array = symbols.array
|
||||
private val genericValueOfSymbol = symbols.valueOfForEnum
|
||||
private val genericValuesSymbol = symbols.valuesForEnum
|
||||
|
||||
fun getLoweredEnumOrNull(enumClass: IrClass): LoweredEnumAccess? {
|
||||
fun enumEntriesMap(enumClass: IrClass): Map<Name, LoweredEnumEntryDescription> {
|
||||
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
||||
return if (!context.llvmModuleSpecification.containsDeclaration(enumClass)) {
|
||||
externalLoweredEnums[enumClass]
|
||||
} else {
|
||||
internalLoweredEnums[enumClass]
|
||||
return enumEntriesMaps.getOrPut(enumClass) {
|
||||
data class NameWithOrdinal(val name: Name, val ordinal: Int)
|
||||
enumClass.declarations.asSequence()
|
||||
.filterIsInstance<IrEnumEntry>()
|
||||
.mapIndexed { index, it -> NameWithOrdinal(it.name, index) }
|
||||
.sortedBy { it.name }
|
||||
.withIndex()
|
||||
.associate { it.value.name to LoweredEnumEntryDescription(it.value.ordinal, it.index) }
|
||||
.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
fun getLoweredEnum(enumClass: IrClass): LoweredEnumAccess {
|
||||
fun getImplObject(enumClass: IrClass): IrClass {
|
||||
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
||||
return if (!context.llvmModuleSpecification.containsDeclaration(enumClass)) {
|
||||
externalLoweredEnums.getOrPut(enumClass) {
|
||||
enumSpecialDeclarationsFactory.createExternalLoweredEnum(enumClass)
|
||||
}
|
||||
} else {
|
||||
internalLoweredEnums.getOrPut(enumClass) {
|
||||
enumSpecialDeclarationsFactory.createInternalLoweredEnum(enumClass)
|
||||
return enumImplObjects.getOrPut(enumClass) {
|
||||
irFactory.buildClass {
|
||||
startOffset = enumClass.startOffset
|
||||
endOffset = enumClass.endOffset
|
||||
origin = DECLARATION_ORIGIN_ENUM
|
||||
name = "OBJECT".synthesizedName
|
||||
kind = ClassKind.OBJECT
|
||||
}.apply {
|
||||
superTypes = listOf(irBuiltIns.anyType)
|
||||
parent = enumClass
|
||||
|
||||
addChild(irFactory.buildField {
|
||||
startOffset = enumClass.startOffset
|
||||
endOffset = enumClass.endOffset
|
||||
origin = DECLARATION_ORIGIN_ENUM
|
||||
name = "VALUES".synthesizedName
|
||||
type = array.typeWith(enumClass.defaultType)
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
isFinal = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getInternalLoweredEnum(enumClass: IrClass): InternalLoweredEnum {
|
||||
fun getValueGetter(enumClass: IrClass): IrFunction {
|
||||
require(enumClass.isEnumClass) { "Expected enum class but was: ${enumClass.render()}" }
|
||||
require(context.llvmModuleSpecification.containsDeclaration(enumClass)) { "Expected enum class from current module." }
|
||||
return internalLoweredEnums.getOrPut(enumClass) {
|
||||
enumSpecialDeclarationsFactory.createInternalLoweredEnum(enumClass)
|
||||
return enumValueGetters.getOrPut(enumClass) {
|
||||
irFactory.buildFun {
|
||||
startOffset = enumClass.startOffset
|
||||
endOffset = enumClass.endOffset
|
||||
origin = DECLARATION_ORIGIN_ENUM
|
||||
name = "getEnumAt".synthesizedName
|
||||
returnType = enumClass.defaultType
|
||||
}.apply {
|
||||
parent = enumClass
|
||||
|
||||
addValueParameter {
|
||||
name = Name.identifier("getterId")
|
||||
origin = DECLARATION_ORIGIN_ENUM
|
||||
type = irBuiltIns.intType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getEnumEntryOrdinal(enumEntry: IrEnumEntry) =
|
||||
enumEntry.parentAsClass.declarations.filterIsInstance<IrEnumEntry>().indexOf(enumEntry)
|
||||
fun getValuesField(implObject: IrClass) = implObject.fields.single()
|
||||
|
||||
fun IrBuilderWithScope.irGetValuesField(enumClass: IrClass): IrExpression {
|
||||
val implObject = getImplObject(enumClass)
|
||||
val valuesField = getValuesField(implObject)
|
||||
return irGetField(irGetObject(implObject.symbol), valuesField)
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irEnumValues(enumClass: IrClass) =
|
||||
irCall(genericValuesSymbol, listOf(enumClass.defaultType)).apply {
|
||||
putValueArgument(0, irGetValuesField(enumClass))
|
||||
}
|
||||
|
||||
fun IrBuilderWithScope.irEnumValueOf(enumClass: IrClass, value: IrExpression) =
|
||||
irCall(genericValueOfSymbol, listOf(enumClass.defaultType)).apply {
|
||||
putValueArgument(0, value)
|
||||
putValueArgument(1, irGetValuesField(enumClass))
|
||||
}
|
||||
}
|
||||
|
||||
internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM")
|
||||
|
||||
internal data class LoweredEnumEntryDescription(val ordinal: Int, val getterId: Int)
|
||||
|
||||
/**
|
||||
* Common interface for both [InternalLoweredEnum] and [ExternalLoweredEnum]
|
||||
* that allows to work with lowered enum regardless of its location.
|
||||
*/
|
||||
internal interface LoweredEnumAccess {
|
||||
val valuesGetter: IrSimpleFunction
|
||||
val itemGetterSymbol: IrSimpleFunctionSymbol
|
||||
val entriesMap: Map<Name, LoweredEnumEntryDescription>
|
||||
fun getValuesField(startOffset: Int, endOffset: Int): IrExpression
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents lowered enum from current module.
|
||||
*/
|
||||
internal data class InternalLoweredEnum(
|
||||
val implObject: IrClass,
|
||||
val valuesField: IrField,
|
||||
val valuesGetterWrapper: IrSimpleFunction,
|
||||
override val valuesGetter: IrSimpleFunction,
|
||||
override val itemGetterSymbol: IrSimpleFunctionSymbol,
|
||||
override val entriesMap: Map<Name, LoweredEnumEntryDescription>
|
||||
) : LoweredEnumAccess {
|
||||
private fun internalObjectGetter(startOffset: Int, endOffset: Int) =
|
||||
IrGetObjectValueImpl(startOffset, endOffset,
|
||||
implObject.defaultType,
|
||||
implObject.symbol
|
||||
)
|
||||
|
||||
override fun getValuesField(startOffset: Int, endOffset: Int): IrExpression = IrGetFieldImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
valuesField.symbol,
|
||||
valuesField.type,
|
||||
internalObjectGetter(startOffset, endOffset)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents lowered enum that's located in external module.
|
||||
*/
|
||||
internal data class ExternalLoweredEnum(
|
||||
override val valuesGetter: IrSimpleFunction,
|
||||
override val itemGetterSymbol: IrSimpleFunctionSymbol,
|
||||
override val entriesMap: Map<Name, LoweredEnumEntryDescription>
|
||||
) : LoweredEnumAccess {
|
||||
override fun getValuesField(startOffset: Int, endOffset: Int): IrExpression =
|
||||
IrCallImpl(startOffset, endOffset, valuesGetter.returnType, valuesGetter.symbol, valuesGetter.typeParameters.size, valuesGetter.valueParameters.size)
|
||||
}
|
||||
|
||||
internal class EnumSpecialDeclarationsFactory(val context: Context) {
|
||||
private val symbols = context.ir.symbols
|
||||
|
||||
private fun enumEntriesMap(enumClass: IrClass): Map<Name, LoweredEnumEntryDescription> {
|
||||
data class NameWithOrdinal(val name: Name, val ordinal: Int)
|
||||
return enumClass.declarations.asSequence()
|
||||
.filterIsInstance<IrEnumEntry>()
|
||||
.mapIndexed { index, it -> NameWithOrdinal(it.name, index) }
|
||||
.sortedBy { it.name }
|
||||
.withIndex()
|
||||
.associate { it.value.name to LoweredEnumEntryDescription(it.value.ordinal, it.index) }
|
||||
.toMap()
|
||||
}
|
||||
|
||||
private fun findItemGetterSymbol(): IrSimpleFunctionSymbol =
|
||||
symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
|
||||
|
||||
private fun valuesArrayType(enumClass: IrClass): IrType =
|
||||
symbols.array.typeWith(enumClass.defaultType)
|
||||
|
||||
// We can't move property getter to the top-level scope.
|
||||
// So add a wrapper instead.
|
||||
private fun createValuesGetterWrapper(enumClass: IrClass, isExternal: Boolean): IrSimpleFunction =
|
||||
context.irFactory.buildFun {
|
||||
name = InternalAbi.getEnumValuesAccessorName(enumClass)
|
||||
returnType = valuesArrayType(enumClass)
|
||||
origin = InternalAbi.INTERNAL_ABI_ORIGIN
|
||||
this.isExternal = isExternal
|
||||
}.also {
|
||||
if (isExternal) {
|
||||
context.internalAbi.reference(it, enumClass.module)
|
||||
} else {
|
||||
context.internalAbi.declare(it, enumClass.module)
|
||||
}
|
||||
}
|
||||
|
||||
fun createExternalLoweredEnum(enumClass: IrClass): ExternalLoweredEnum {
|
||||
val enumEntriesMap = enumEntriesMap(enumClass)
|
||||
val itemGetterSymbol = findItemGetterSymbol()
|
||||
val valuesGetterWrapper = createValuesGetterWrapper(enumClass, isExternal = true)
|
||||
return ExternalLoweredEnum(valuesGetterWrapper, itemGetterSymbol, enumEntriesMap)
|
||||
}
|
||||
|
||||
fun createInternalLoweredEnum(enumClass: IrClass): InternalLoweredEnum {
|
||||
val startOffset = enumClass.startOffset
|
||||
val endOffset = enumClass.endOffset
|
||||
|
||||
val implObject =
|
||||
IrClassImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_ENUM,
|
||||
IrClassSymbolImpl(),
|
||||
"OBJECT".synthesizedName,
|
||||
ClassKind.OBJECT,
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
Modality.FINAL,
|
||||
isCompanion = false,
|
||||
isInner = false,
|
||||
isData = false,
|
||||
isExternal = false,
|
||||
isValue = false,
|
||||
isExpect = false,
|
||||
isFun = false
|
||||
).apply {
|
||||
parent = enumClass
|
||||
createParameterDeclarations()
|
||||
}
|
||||
|
||||
val valuesType = valuesArrayType(enumClass)
|
||||
val valuesField =
|
||||
IrFieldImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_ENUM,
|
||||
IrFieldSymbolImpl(),
|
||||
"VALUES".synthesizedName,
|
||||
valuesType,
|
||||
DescriptorVisibilities.PRIVATE,
|
||||
isFinal = true,
|
||||
isExternal = false,
|
||||
isStatic = false,
|
||||
).apply {
|
||||
parent = implObject
|
||||
}
|
||||
|
||||
val valuesGetter =
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset,
|
||||
DECLARATION_ORIGIN_ENUM,
|
||||
IrSimpleFunctionSymbolImpl(),
|
||||
"get-VALUES".synthesizedName,
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
Modality.FINAL,
|
||||
valuesType,
|
||||
isInline = false,
|
||||
isExternal = false,
|
||||
isTailrec = false,
|
||||
isSuspend = false,
|
||||
isExpect = false,
|
||||
isFakeOverride = false,
|
||||
isOperator = false,
|
||||
isInfix = false
|
||||
).apply {
|
||||
parent = implObject
|
||||
}
|
||||
|
||||
val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
|
||||
implObject.addSimpleDelegatingConstructor(
|
||||
constructorOfAny,
|
||||
context.irBuiltIns,
|
||||
true // TODO: why primary?
|
||||
)
|
||||
|
||||
implObject.superTypes += context.irBuiltIns.anyType
|
||||
implObject.addFakeOverrides(context.typeSystem)
|
||||
|
||||
val itemGetterSymbol = findItemGetterSymbol()
|
||||
val enumEntriesMap = enumEntriesMap(enumClass)
|
||||
val valuesGetterWrapper = createValuesGetterWrapper(enumClass, isExternal = false)
|
||||
context.createIrBuilder(valuesGetterWrapper.symbol).run {
|
||||
valuesGetterWrapper.body = irBlockBody {
|
||||
+irReturn(irCall(valuesGetter))
|
||||
}
|
||||
}
|
||||
return InternalLoweredEnum(
|
||||
implObject,
|
||||
valuesField,
|
||||
valuesGetterWrapper,
|
||||
valuesGetter,
|
||||
itemGetterSymbol,
|
||||
enumEntriesMap)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user