diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt index d32d147e397..58575fc16a1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt @@ -307,7 +307,7 @@ internal object IrTypeInlineClassesSupport : InlineClassesSupport().atMostOne { it.backingField != null }?.backingField?.type + ?: clazz.declarations.filterIsInstance().atMostOne { it.backingField?.takeUnless { it.isStatic } != null }?.backingField?.type ?: clazz.inlineClassRepresentation!!.underlyingType override fun getPackageFqName(clazz: IrClass) = diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt index 25c831fdc9b..3f235d789df 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt @@ -502,7 +502,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT } private fun getInlineClassBackingField(irClass: IrClass): IrField = - irClass.declarations.filterIsInstance().mapNotNull { it.backingField }.single() + irClass.declarations.filterIsInstance().mapNotNull { it.backingField?.takeUnless { it.isStatic } }.single() } private val Context.getLoweredInlineClassConstructor: (IrConstructor) -> IrSimpleFunction by Context.lazyMapMember { irConstructor -> diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ObjectClassLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ObjectClassLowering.kt index 7b70714cd5a..1fcfc498627 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ObjectClassLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ObjectClassLowering.kt @@ -19,33 +19,45 @@ import org.jetbrains.kotlin.backend.konan.ir.isUnit import org.jetbrains.kotlin.backend.konan.isObjCClass import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.builders.declarations.addField -import org.jetbrains.kotlin.ir.builders.declarations.buildFun +import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.irCall -import org.jetbrains.kotlin.name.Name internal fun Context.getObjectClassInstanceFunction(clazz: IrClass) = mapping.objectInstanceGetter.getOrPut(clazz) { when { clazz.isUnit() -> ir.symbols.theUnitInstance.owner clazz.isCompanion -> { require((clazz.parent as? IrClass)?.isExternalObjCClass() != true) { "External objc Classes can't be used this way"} - irFactory.buildFun { + val property = irFactory.buildProperty { + startOffset = clazz.startOffset + endOffset = clazz.endOffset name = "companion".synthesizedName - returnType = clazz.defaultType }.apply { parent = clazz.parent + addGetter { + startOffset = clazz.startOffset + endOffset = clazz.endOffset + returnType = clazz.defaultType + } } + property.getter!! } else -> { - irFactory.buildFun { + val property = irFactory.buildProperty { + startOffset = clazz.startOffset + endOffset = clazz.endOffset name = "instance".synthesizedName - returnType = clazz.defaultType }.apply { parent = clazz + addGetter { + startOffset = clazz.startOffset + endOffset = clazz.endOffset + returnType = clazz.defaultType + } } + property.getter!! } } } @@ -60,15 +72,13 @@ internal class ObjectClassLowering(val context: Context) : FileLoweringPass { if (declaration.isObject && !declaration.isCompanion && !declaration.isUnit()) { processObjectClass( declaration, - declaration, - instanceFieldName + declaration ) } declaration.declarations.singleOrNull { (it as? IrClass)?.isCompanion == true }?.let { processObjectClass( it as IrClass, - declaration, - companionFieldName + declaration ) } return declaration @@ -94,21 +104,20 @@ internal class ObjectClassLowering(val context: Context) : FileLoweringPass { fun processObjectClass( declaration: IrClass, - classToAdd: IrClass, - fieldName: Name + classToAdd: IrClass ) { val function = context.getObjectClassInstanceFunction(declaration) - classToAdd.declarations.add(function) + val property = function.correspondingPropertySymbol!!.owner + classToAdd.declarations.add(property) - val primaryConstructor = declaration.constructors.single { it.isPrimary } - require(primaryConstructor.valueParameters.isEmpty()) - val instanceField = classToAdd.addField { - name = fieldName + property.addBackingField { isFinal = true isStatic = true type = declaration.defaultType visibility = DescriptorVisibilities.PRIVATE }.also { field -> + val primaryConstructor = declaration.constructors.single { it.isPrimary } + require(primaryConstructor.valueParameters.isEmpty()) val builder = context.createIrBuilder(field.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET) val initializer = if (declaration.isCompanion && classToAdd.isObjCClass()) { builder.irGetObjCClassCompanion(declaration) @@ -131,15 +140,14 @@ internal class ObjectClassLowering(val context: Context) : FileLoweringPass { } } field.initializer = builder.irExprBody(initializer) - if (declaration.annotations.hasAnnotation(KonanFqNames.threadLocal)) { - field.annotations += buildSimpleAnnotation(context.irBuiltIns, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.ir.symbols.threadLocal.owner) - } else if (declaration.annotations.hasAnnotation(KonanFqNames.sharedImmutable) || context.memoryModel != MemoryModel.EXPERIMENTAL){ - field.annotations += buildSimpleAnnotation(context.irBuiltIns, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.ir.symbols.sharedImmutable.owner) - } + } + if (declaration.annotations.hasAnnotation(KonanFqNames.threadLocal)) { + property.annotations += buildSimpleAnnotation(context.irBuiltIns, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.ir.symbols.threadLocal.owner) + } else if (declaration.annotations.hasAnnotation(KonanFqNames.sharedImmutable) || context.memoryModel != MemoryModel.EXPERIMENTAL){ + property.annotations += buildSimpleAnnotation(context.irBuiltIns, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, context.ir.symbols.sharedImmutable.owner) } function.body = context.createIrBuilder(function.symbol, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET).irBlockBody { - val value = irGetField(null, instanceField) - +irReturn(value) + +irReturn(irGetField(null, property.backingField!!)) } } @@ -162,11 +170,6 @@ internal class ObjectClassLowering(val context: Context) : FileLoweringPass { return fields.all { it.isConst } && this.constructors.all { it.isAutogeneratedSimpleConstructor() } } - companion object { - val companionFieldName = "companionField".synthesizedName - val instanceFieldName = "instanceField".synthesizedName - - } // This is a hack to avoid early freezing. Should be removed when freezing is removed object IrStatementOriginFieldPreInit : IrStatementOriginImpl("FIELD_PRE_INIT") diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 525588518f1..1109f096d1d 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -6262,6 +6262,11 @@ fileCheckTest("filecheck_replace_invoke_with_call") { annotatedSource = project.file('filecheck/replace_invoke_with_call.kt') } +fileCheckTest("filecheck_no_frame_on_constant_object_access") { + annotatedSource = project.file('filecheck/no_frame_on_constant_object_access.kt') + enabled = project.globalTestArgs.contains('-opt') +} + fileCheckTest("filecheck_kt49847_simple_function_reference") { annotatedSource = project.file('filecheck/kt49847_simple_function_reference.kt') enabled = project.globalTestArgs.contains('-opt') diff --git a/kotlin-native/backend.native/tests/filecheck/no_frame_on_constant_object_access.kt b/kotlin-native/backend.native/tests/filecheck/no_frame_on_constant_object_access.kt new file mode 100644 index 00000000000..b8bc03c032b --- /dev/null +++ b/kotlin-native/backend.native/tests/filecheck/no_frame_on_constant_object_access.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +object A { + const val x = 5 +} + +class B(val z:Int) { + companion object { + const val y = 7 + } +} + +object C { + val x = listOf(1, 2, 3) +} + +// CHECK-LABEL: define i32 @"kfun:#f(){}kotlin.Int"() +// CHECK-NOT: EnterFrame +fun f() = A.x + B.y +// CHECK: {{^}}epilogue: + +// test that assumption on how EnterFrame looks like is not broken +// CHECK-LABEL: define void @"kfun:#g(){}"() +// CHECK: EnterFrame +fun g() { + val x = C.x +} +// CHECK: {{^}}epilogue: + + +fun main() { + f() + g() +} \ No newline at end of file