Native: fix @ExportObjCClass with the new memory manager

Previous implementation of `@ExportObjCClass` relied on the fact that
initialization of top-level fields was eager, i.e. happened during
Kotlin runtime initialization, when Kotlin code is accesses for the
first time.

With the new MM, initialization of top-level fields became lazy, it
happens when the particular file is accessed for the first time.

This commit fixes `@ExportObjCClass` with the new MM by making the
initialization of particular top-level fields eager.

^KT-53373 Fixed
This commit is contained in:
Svyatoslav Scherbina
2022-08-02 12:59:00 +02:00
committed by Space
parent 70da19bd22
commit ce6c8a51ba
5 changed files with 27 additions and 7 deletions
@@ -127,7 +127,7 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
lateinit var currentFile: IrFile
private val topLevelInitializers = mutableListOf<IrExpression>()
private val eagerTopLevelInitializers = mutableListOf<IrExpression>()
private val newTopLevelDeclarations = mutableListOf<IrDeclaration>()
override val irFile: IrFile
@@ -142,8 +142,8 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
currentFile = irFile
irFile.transformChildrenVoid(this)
topLevelInitializers.forEach { irFile.addTopLevelInitializer(it, context, false) }
topLevelInitializers.clear()
eagerTopLevelInitializers.forEach { irFile.addTopLevelInitializer(it, context, threadLocal = false, eager = true) }
eagerTopLevelInitializers.clear()
irFile.addChildren(newTopLevelDeclarations)
newTopLevelDeclarations.clear()
@@ -191,7 +191,7 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
if (irClass.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass)
topLevelInitializers.add(irBuilder.getObjCClass(symbols, irClass.symbol))
eagerTopLevelInitializers.add(irBuilder.getObjCClass(symbols, irClass.symbol))
}
}
@@ -62,7 +62,7 @@ internal fun irBuilder(
private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean, eager: Boolean) {
val irField = IrFieldImpl(
expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED,
@@ -79,6 +79,9 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: Ko
if (threadLocal)
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.threadLocal.owner)
if (eager)
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.eagerInitialization.owner)
initializer = IrExpressionBodyImpl(startOffset, endOffset, expression)
}
addChild(irField)
@@ -1,6 +1,8 @@
language = Objective-C
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h Foundation/NSBundle.h
headers = Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h Foundation/NSBundle.h \
objc/runtime.h
headerFilter = **/interop/objc/tests/**.h \
Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.h \
objc/objc.h Foundation/NSBundle.h
objc/objc.h Foundation/NSBundle.h \
objc/runtime.h
linkerOpts = -lobjctests
@@ -0,0 +1,5 @@
import objcTests.*
import kotlinx.cinterop.*
@ExportObjCClass
class KT53373 : NSObject()
@@ -0,0 +1,10 @@
import kotlinx.cinterop.*
import kotlin.test.*
import objcTests.*
@Test
fun testKT53373() {
val kt53373Class = objc_lookUpClass("KT53373")
assertNotNull(kt53373Class)
assertEquals("KT53373", class_getName(kt53373Class)?.toKString())
}