diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InternalAbi.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InternalAbi.kt index 7d6fb1f3759..3f160e67b5a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InternalAbi.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InternalAbi.kt @@ -89,6 +89,9 @@ internal class InternalAbi(private val context: Context) { fun getInnerClassOuterThisAccessorName(innerClass: IrClass): Name = getMangledNameFor("outerThis", innerClass) + fun getLateinitPropertyFieldAccessorName(property: IrProperty): Name = + getMangledNameFor("${property.name}_field", property.parent) + /** * Generate name for declaration that will be a part of internal ABI. */ diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt index 31c1ea4bb54..7804d2e4974 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.* import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib @@ -34,6 +35,12 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.CleanableBindingContext import org.jetbrains.kotlin.utils.DFS +object KonanStubGeneratorExtensions : StubGeneratorExtensions() { + override fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean { + return super.isPropertyWithPlatformField(descriptor) || descriptor.isLateInit + } +} + internal fun Context.psiToIr( symbolTable: SymbolTable, isProducingLibrary: Boolean, @@ -61,6 +68,7 @@ internal fun Context.psiToIr( moduleDescriptor, symbolTable, generatorContext.irBuiltIns, DescriptorByIdSignatureFinderImpl(moduleDescriptor, KonanManglerDesc), + KonanStubGeneratorExtensions ) val irBuiltInsOverDescriptors = generatorContext.irBuiltIns as IrBuiltInsOverDescriptors val functionIrClassFactory: KonanIrAbstractDescriptorBasedFunctionFactory = diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index c401f02ca90..f0b454d53f9 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -429,6 +429,35 @@ internal val exportInternalAbiPhase = makeKonanModuleOpPhase( context.internalAbi.declare(function, declaration.module) } } + + override fun visitProperty(declaration: IrProperty) { + declaration.acceptChildrenVoid(this) + + if (!declaration.isLateinit || declaration.isFakeOverride + || DescriptorVisibilities.isPrivate(declaration.visibility) || declaration.isLocal) + return + + val backingField = declaration.backingField ?: error("Lateinit property ${declaration.render()} should have a backing field") + val function = context.irFactory.buildFun { + name = InternalAbi.getLateinitPropertyFieldAccessorName(declaration) + origin = InternalAbi.INTERNAL_ABI_ORIGIN + returnType = backingField.type + } + val ownerClass = declaration.parentClassOrNull + if (ownerClass != null) + function.addValueParameter { + name = Name.identifier("owner") + origin = InternalAbi.INTERNAL_ABI_ORIGIN + type = ownerClass.defaultType + } + + context.createIrBuilder(function.symbol).apply { + function.body = irBlockBody { + +irReturn(irGetField(ownerClass?.let { irGet(function.valueParameters[0]) }, backingField)) + } + } + context.internalAbi.declare(function, declaration.module) + } } module.acceptChildrenVoid(visitor) } @@ -441,8 +470,12 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase( op = { context, module -> val companionObjectAccessors = mutableMapOf() val outerThisAccessors = mutableMapOf() + val lateinitPropertyAccessors = mutableMapOf() + val transformer = object : IrElementTransformerVoid() { override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression { + expression.transformChildrenVoid(this) + val irClass = expression.symbol.owner if (!irClass.isCompanion || context.llvmModuleSpecification.containsDeclaration(irClass)) { return expression @@ -466,35 +499,70 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase( } override fun visitGetField(expression: IrGetField): IrExpression { - val field = expression.symbol.owner - val irClass = field.parentClassOrNull ?: return expression - if (!irClass.isInner || context.llvmModuleSpecification.containsDeclaration(irClass) - || context.specialDeclarationsFactory.getOuterThisField(irClass) != field - ) { - return expression - } - val accessor = outerThisAccessors.getOrPut(irClass) { - context.irFactory.buildFun { - name = InternalAbi.getInnerClassOuterThisAccessorName(irClass) - returnType = irClass.parentAsClass.defaultType - origin = InternalAbi.INTERNAL_ABI_ORIGIN - isExternal = true - }.also { function -> - context.internalAbi.reference(function, irClass.module) + expression.transformChildrenVoid(this) - function.addValueParameter { - name = Name.identifier("innerClass") - origin = InternalAbi.INTERNAL_ABI_ORIGIN - type = irClass.defaultType + val field = expression.symbol.owner + val irClass = field.parentClassOrNull + val property = field.correspondingPropertySymbol?.owner + + return when { + context.llvmModuleSpecification.containsDeclaration(field) -> expression + + irClass?.isInner == true && context.specialDeclarationsFactory.getOuterThisField(irClass) == field -> { + val accessor = outerThisAccessors.getOrPut(irClass) { + context.irFactory.buildFun { + name = InternalAbi.getInnerClassOuterThisAccessorName(irClass) + returnType = irClass.parentAsClass.defaultType + origin = InternalAbi.INTERNAL_ABI_ORIGIN + isExternal = true + }.also { function -> + context.internalAbi.reference(function, irClass.module) + + function.addValueParameter { + name = Name.identifier("innerClass") + origin = InternalAbi.INTERNAL_ABI_ORIGIN + type = irClass.defaultType + } + } + } + return IrCallImpl( + expression.startOffset, expression.endOffset, + expression.type, accessor.symbol, + accessor.typeParameters.size, accessor.valueParameters.size + ).apply { + putValueArgument(0, expression.receiver) } } - } - return IrCallImpl( - expression.startOffset, expression.endOffset, - expression.type, accessor.symbol, - accessor.typeParameters.size, accessor.valueParameters.size - ).apply { - putValueArgument(0, expression.receiver) + + property?.isLateinit == true -> { + val accessor = lateinitPropertyAccessors.getOrPut(property) { + context.irFactory.buildFun { + name = InternalAbi.getLateinitPropertyFieldAccessorName(property) + returnType = field.type + origin = InternalAbi.INTERNAL_ABI_ORIGIN + isExternal = true + }.also { function -> + context.internalAbi.reference(function, property.module) + + if (irClass != null) + function.addValueParameter { + name = Name.identifier("owner") + origin = InternalAbi.INTERNAL_ABI_ORIGIN + type = irClass.defaultType + } + } + } + return IrCallImpl( + expression.startOffset, expression.endOffset, + expression.type, accessor.symbol, + accessor.typeParameters.size, accessor.valueParameters.size + ).apply { + if (irClass != null) + putValueArgument(0, expression.receiver) + } + } + + else -> expression } } }