I started to do a little proof of concept today to...
# kotlin-native
s
I started to do a little proof of concept today to see how well Kotlin Native objects would behave when being scripted from Javascript. I quickly hit a wall when I noticed that the
.def
file for
JavaScriptCore
is disabled. Does this not work at all? Or was it disabled a long time ago and nobody had checked it out since?
I see why it is disabled. The generated kotlin file doesn't compile properly. Even if one copies out the generated file and fixes the syntax problem it still won't compile properly. I ended up moving the JavaScriptCore logic out of the kotlin framework and into Swift code. I defined a protocol inheriting from
JSExports
and extending it in Swift.
Copy code
@objc protocol SecretTellerExports: JSExport {
    var platform: String { get }
    func tell() -> String
    static func create() -> SecretTeller
}

extension SecretTeller: SecretTellerExports {
    static func create() -> SecretTeller {
        return SecretTeller.Companion().createAndFreeze()
    }
}
Everything looked like it worked until the JS garbage collector tried to access the
SecretTeller
object I had instantiated in a script. Freezing the object appears to work. In my simple test this is ok. I'm just not sure how restricting these limitations will be for more complicated projects.
o
.def files are not currently supported for JS interop, only C and Objective-C. Also see https://github.com/JetBrains/kotlin-native/pull/1656 for somewhat related activity.
n
Are you referring to JS interop via WASM?
s
No. Embedding JavaScriptCore inside of an iOS app and exposing Kotlin objects into the JSContext object.
s
Everything looked like it worked until the JS garbage collector tried to access the
SecretTeller
object I had instantiated in a script.
Could you share the backtrace?
s
I’ll share the repo on GitHub when I get to a computer. The exception was an illegal state exception because the garbage collector runs in a different thread. Frozen objects worked fine with the collector.
Here is a link to the repo. https://github.com/samus/KnJsTest Specifically the commit
f7dfb5cc83a1223f4618a5c7a04252b537b24db0
is where I changed it to call
freeze
on the Kotlin/Native object that is passed into the JavaScript engine.
The exception stack trace is:
Copy code
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared com.synappticlabs.knjstest.SecretTeller@3b823e8 from other thread
        at 0   app                                 0x00000001061efa76 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 70 (/opt/teamcity-agent/work/4d622a065c544371/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:5)
        at 1   app                                 0x00000001061ef996 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 70 (/opt/teamcity-agent/work/4d622a065c544371/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:5)
        at 2   app                                 0x0000000106224606 kfun:kotlin.native.IncorrectDereferenceException.<init>(kotlin.String)kotlin.native.IncorrectDereferenceException + 70 (/opt/teamcity-agent/work/4d622a065c544371/runtime/src/main/kotlin/kotlin/native/Runtime.kt:28:5)
        at 3   app                                 0x0000000106224c71 ThrowIllegalObjectSharingException + 289 (/opt/teamcity-agent/work/4d622a065c544371/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt:84:11)
        at 4   app                                 0x000000010622e479 _ZNK16KRefSharedHolder14verifyRefOwnerEv + 105
s
Thank you for providing the details. I confirm that JavaScriptCore appears to perform GC on background thread. So currently using Kotlin objects with
JSExport
requires freezing them. Note that you can still have mutable state in these objects by wrapping it in
StableRef
and ensuring that it is accessed from proper thread.
Note that
StableRef
must be disposed manually using
.dispose()
on it.