diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt index 721ad0a9030..10fb6b139e2 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt @@ -22,20 +22,20 @@ import org.jetbrains.kotlin.native.interop.indexer.GlobalDecl class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : KotlinStub, NativeBacked { - val getAddressExpression: KotlinExpression - val header: String - val getter: KotlinExpression - val setter: KotlinExpression? - - init { - getAddressExpression = stubGenerator.simpleBridgeGenerator.kotlinToNative( + private val getAddressExpression: KotlinExpression by lazy { + stubGenerator.simpleBridgeGenerator.kotlinToNative( nativeBacked = this, returnType = BridgedType.NATIVE_PTR, kotlinValues = emptyList() ) { "&${global.name}" } + } + val header: String + val getter: KotlinExpression + val setter: KotlinExpression? + init { val kotlinScope = stubGenerator.kotlinFile // TODO: consider sharing the logic below with field generator. @@ -50,14 +50,38 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot getter = mirror.info.argFromBridged(getAddressExpression, kotlinScope, nativeBacked = this) + "!!" setter = null } else { - val pointedTypeName = mirror.pointedType.render(kotlinScope) - val storagePointed = "interpretPointed<$pointedTypeName>($getAddressExpression)" if (mirror is TypeMirror.ByValue) { + getter = mirror.info.argFromBridged(stubGenerator.simpleBridgeGenerator.kotlinToNative( + nativeBacked = this, + returnType = mirror.info.bridgedType, + kotlinValues = emptyList() + ) { + mirror.info.cToBridged(expr = global.name) + }, kotlinScope, nativeBacked = this) + + setter = if (global.isConst) { + null + } else { + val bridgedValue = BridgeTypedKotlinValue(mirror.info.bridgedType, mirror.info.argToBridged("value")) + + stubGenerator.simpleBridgeGenerator.kotlinToNative( + nativeBacked = this, + returnType = BridgedType.VOID, + kotlinValues = listOf(bridgedValue) + ) { nativeValues -> + out("${global.name} = ${mirror.info.cFromBridged( + nativeValues.single(), + scope, + nativeBacked = this@GlobalVariableStub + )};") + "" + } + } + kotlinType = mirror.argType - val valueProperty = "$storagePointed.value" - getter = valueProperty - setter = if (global.isConst) null else "$valueProperty = value" } else { + val pointedTypeName = mirror.pointedType.render(kotlinScope) + val storagePointed = "interpretPointed<$pointedTypeName>($getAddressExpression)" kotlinType = mirror.pointedType getter = storagePointed setter = null diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index abd144b230d..c87f0721f54 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -2324,7 +2324,9 @@ if (isMac()) { task interop_objc_smoke(type: RunInteropKonanTest) { disabled = (project.testTarget == 'wasm32') // No interop for wasm yet. goldValue = "84\nFoo\nHello, World!\nKotlin says: Hello, everybody!\nHello from Kotlin\n2, 1\n" + - "true\ntrue\nDeallocated\nDeallocated\n" + "true\ntrue\n" + + "Global string\nAnother global string\nnull\nglobal object\n" + + "Deallocated\nDeallocated\n" source = "interop/objc/smoke.kt" interop = 'objcSmoke' diff --git a/backend.native/tests/interop/objc/smoke.h b/backend.native/tests/interop/objc/smoke.h index b3ff2028541..ef0ca056a9d 100644 --- a/backend.native/tests/interop/objc/smoke.h +++ b/backend.native/tests/interop/objc/smoke.h @@ -52,3 +52,6 @@ void invoke2(void (^block)(void)) { int (^getSupplier(int x))(void); Class (^ _Nonnull getClassGetter(NSObject* obj))(void); + +extern NSString* globalString; +extern NSObject* globalObject; diff --git a/backend.native/tests/interop/objc/smoke.kt b/backend.native/tests/interop/objc/smoke.kt index 2be949479fb..e57b1aa69ce 100644 --- a/backend.native/tests/interop/objc/smoke.kt +++ b/backend.native/tests/interop/objc/smoke.kt @@ -48,6 +48,18 @@ fun run() { // toString (virtually): println(map.keys.map { it.toString() }.min() == foo.description()) } + + println(globalString) + autoreleasepool { + globalString = "Another global string" + } + println(globalString) + + println(globalObject) + globalObject = object : NSObject() { + override fun description() = "global object" + } + println(globalObject) } fun MutablePairProtocol.swap() { diff --git a/backend.native/tests/interop/objc/smoke.m b/backend.native/tests/interop/objc/smoke.m index cce1924ceaa..1d3b8aa0191 100644 --- a/backend.native/tests/interop/objc/smoke.m +++ b/backend.native/tests/interop/objc/smoke.m @@ -57,3 +57,6 @@ int (^getSupplier(int x))(void) { Class (^ _Nonnull getClassGetter(NSObject* obj))() { return ^{ return obj.class; }; } + +NSString* globalString = @"Global string"; +NSObject* globalObject = nil;