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:
committed by
Space
parent
70da19bd22
commit
ce6c8a51ba
+4
-4
@@ -127,7 +127,7 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
|
|||||||
|
|
||||||
lateinit var currentFile: IrFile
|
lateinit var currentFile: IrFile
|
||||||
|
|
||||||
private val topLevelInitializers = mutableListOf<IrExpression>()
|
private val eagerTopLevelInitializers = mutableListOf<IrExpression>()
|
||||||
private val newTopLevelDeclarations = mutableListOf<IrDeclaration>()
|
private val newTopLevelDeclarations = mutableListOf<IrDeclaration>()
|
||||||
|
|
||||||
override val irFile: IrFile
|
override val irFile: IrFile
|
||||||
@@ -142,8 +142,8 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
|
|||||||
currentFile = irFile
|
currentFile = irFile
|
||||||
irFile.transformChildrenVoid(this)
|
irFile.transformChildrenVoid(this)
|
||||||
|
|
||||||
topLevelInitializers.forEach { irFile.addTopLevelInitializer(it, context, false) }
|
eagerTopLevelInitializers.forEach { irFile.addTopLevelInitializer(it, context, threadLocal = false, eager = true) }
|
||||||
topLevelInitializers.clear()
|
eagerTopLevelInitializers.clear()
|
||||||
|
|
||||||
irFile.addChildren(newTopLevelDeclarations)
|
irFile.addChildren(newTopLevelDeclarations)
|
||||||
newTopLevelDeclarations.clear()
|
newTopLevelDeclarations.clear()
|
||||||
@@ -191,7 +191,7 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
|
|||||||
|
|
||||||
if (irClass.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
|
if (irClass.annotations.hasAnnotation(interop.exportObjCClass.fqNameSafe)) {
|
||||||
val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass)
|
val irBuilder = context.createIrBuilder(currentFile.symbol).at(irClass)
|
||||||
topLevelInitializers.add(irBuilder.getObjCClass(symbols, irClass.symbol))
|
eagerTopLevelInitializers.add(irBuilder.getObjCClass(symbols, irClass.symbol))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -62,7 +62,7 @@ internal fun irBuilder(
|
|||||||
|
|
||||||
private var topLevelInitializersCounter = 0
|
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(
|
val irField = IrFieldImpl(
|
||||||
expression.startOffset, expression.endOffset,
|
expression.startOffset, expression.endOffset,
|
||||||
IrDeclarationOrigin.DEFINED,
|
IrDeclarationOrigin.DEFINED,
|
||||||
@@ -79,6 +79,9 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: Ko
|
|||||||
if (threadLocal)
|
if (threadLocal)
|
||||||
annotations += buildSimpleAnnotation(context.irBuiltIns, startOffset, endOffset, context.ir.symbols.threadLocal.owner)
|
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)
|
initializer = IrExpressionBodyImpl(startOffset, endOffset, expression)
|
||||||
}
|
}
|
||||||
addChild(irField)
|
addChild(irField)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
language = Objective-C
|
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 \
|
headerFilter = **/interop/objc/tests/**.h \
|
||||||
Foundation/NSArray.h Foundation/NSValue.h Foundation/NSString.h Foundation/NSStream.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
|
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())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user