[K/N] Deprecated freezing ^KT-50541

Starting with 1.7.20 freezing is deprecated. See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation for details.

Merge-request: KT-MR-6399
Merged-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>
This commit is contained in:
Alexander Shabalin
2022-06-16 09:04:14 +00:00
committed by Space
parent b482b0e86d
commit 29f3445721
99 changed files with 321 additions and 68 deletions
@@ -28,6 +28,7 @@ typealias ObjCObjectMeta = ObjCClass
interface ObjCProtocol : ObjCObject
@ExportTypeInfo("theForeignObjCObjectTypeInfo")
@OptIn(FreezingIsDeprecated::class)
@kotlin.native.internal.Frozen
internal open class ForeignObjCObject : kotlin.native.internal.ObjCObjectWrapper
+51 -4
View File
@@ -60,7 +60,7 @@ If `kotlin.native.isExperimentalMM()` returns `true`, you've successfully enable
To improve the performance, please also consider enabling a concurrent implementation
for the sweep phase of the garbage collector. See more details
[here](https://kotlinlang.org/docs/whatsnew1620.html#concurrent-implementation-for-the-sweep-phase-in-new-memory-manager).
It will be switched on by default in Kotlin 1.7.0.
Since 1.7.0 this is the default GC implementation for the new MM.
### Update the libraries
@@ -91,11 +91,53 @@ Other libraries might also have compatibility issues. If you encounter any, repo
Known issues:
* SQLDelight: https://github.com/cashapp/sqldelight/issues/2556
## Freezing deprecation
Starting with 1.7.20 freezing API is deprecated.
To temporarily support code for both new and legacy MM, ignore deprecation warnings by:
* either annotating usages of deprecated API with `@OptIn(FreezingIsDeprecated::class)`,
* or applying `languageSettings.optIn("kotlin.native.FreezingIsDeprecated")` to all kotlin source sets in gradle,
* or passing compiler flag `-opt-in=kotlin.native.FreezingIsDeprecated`.
See [Opt-in requirements](https://kotlinlang.org/docs/opt-in-requirements.html) for more details.
To support new MM only, remove usages of the affected API:
* [`@SharedImmutable`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-shared-immutable/):
remove usages. Its usage does not trigger any warning.
* [`class FreezableAtomicReference`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-freezable-atomic-reference/):
use [`class AtomicReference`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-atomic-reference/) instead.
* [`class FreezingException`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-freezing-exception/):
remove usages.
* [`class InvalidMutabilityException`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-invalid-mutability-exception/):
remove usages.
* [`class IncorrectDereferenceException`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native/-incorrect-dereference-exception/):
remove usages.
* [`fun <T> T.freeze()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/freeze.html):
remove usages.
* [`val Any?.isFrozen`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/is-frozen.html):
remove usages assuming it always returns `false`.
* [`fun Any.ensureNeverFrozen()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/ensure-never-frozen.html):
remove usages.
* [`fun <T> atomicLazy(…)`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/atomic-lazy.html):
use [`fun <T> lazy(…)`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/lazy.html) instead.
* [`class MutableData`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-mutable-data/):
use any regular collection instead.
* [`class WorkerBoundReference<out T : Any>`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-worker-bound-reference/):
use `T` directly.
* [`class DetachedObjectGraph<T>`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-detached-object-graph/):
use `T` directly. To pass the value through the C interop, use [`class StableRef<T>`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/-stable-ref/).
Additionally, setting `freezing` binary option to anything but `disabled` with the new MM is deprecated. Currently, usage causes a diagnostics message - not a warning.
## Performance issues
For the first preview, we're using the simplest scheme for garbage collection: single-threaded stop-the-world
mark-and-sweep algorithm, which is triggered after enough functions, loop iterations, and allocations were executed. This greatly hinders the performance, and one of our top priorities now is addressing these performance issues.
> Starting with 1.7.0 we use stop-the-world mark & concurrent sweep GC with a conventional GC scheduler that tracks alive heap size. This significantly
improves performance.
We don't have nice instruments to monitor the GC performance yet. So far, diagnosing requires looking at GC logs. To enable the logs, add the compilation flag `-Xruntime-logs=gc=info` in a Gradle build script:
```kotlin
// build.gradle.kts
@@ -111,7 +153,7 @@ Currently, the logs are only printed to stderr. _Note that the exact contents of
The list of known performance issues:
* Since the collector is single-threaded stop-the-world, the pause time of every thread linearly depends on the number of objects in the heap. The more objects that are kept alive, the longer the pauses are. Long pauses on the main thread can result in laggy UI event handling. Both the pause time and the number of objects in the heap are printed to the logs for each GC cycle.
* Since the collector has stop-the-world mark phase, the pause time of every thread linearly depends on the number of objects in the heap. The more objects that are kept alive, the longer the pauses are. Long pauses on the main thread can result in laggy UI event handling. Both the pause time and the number of objects in the heap are printed to the logs for each GC cycle.
* Being stop-the-world also means that all threads with Kotlin/Native runtime active on them need to synchronize simultaneously for the collection to begin. This also affects the pause time.
* There is a complicated relationship between Swift/ObjC objects and their Kotlin/Native counterparts, which causes Swift/ObjC objects to linger longer than necessary. It means that their Kotlin/Native counterparts are kept in the heap longer, contributing to the slower collection time. This typically doesn't happen, but in some corner cases, for example, when a long loop creates several temporary objects that cross the Swift/ObjC interop boundary on each iteration (for example, calling a Kotlin callback from a loop in Swift or vice versa).
In the logs, there's a number of stable refs in the root set. If this number keeps growing, it may indicate that the Swift/ObjC objects are not being freed when they should. Try putting `autoreleasepool` around loop bodies (both in Swift/ObjC and Kotlin) that do interop calls.
@@ -119,6 +161,7 @@ The list of known performance issues:
This manifests in time between cycles being close (or even less) than the pause time. Both of these numbers are printed to the logs.
Try increasing `kotlin.native.internal.GC.threshold` and `kotlin.native.internal.GC.thresholdAllocations` to force GC to happen less often. Note that the exact meaning of `threshold` and `thresholdAllocations` may change in the future.
* Freezing is currently implemented suboptimally: internally, a separate memory allocation may occur for each frozen object (this recursively includes the object subgraph), which puts unnecessary pressure on the heap.
Won't be fixed, because [freezing is deprecated](#freezing-deprecation) since 1.7.20.
* Unterminated `Worker`s and unconsumed `Future`s have objects pinned to the heap, contributing to the pause time. Like Swift/ObjC interop, this also manifests in a growing number of stable refs in the root set.
To mitigate:
* Look for calls to `Worker.execute` with the resulting `Future` objects that are never consumed using `Future.consume` or `Future.result`.
@@ -131,18 +174,22 @@ If you observe regressions more significant than 5x, please report to [this perf
## Known bugs
* Compiler caches are not supported, so the compilation of debug binaries will be slower.
* Compiler caches are only supported since 1.7.20, so the compilation of debug binaries will be slower with previous compiler versions.
* Freezing machinery is not thread-safe: if an object is being frozen on one thread, and its subgraph is being modified on another, by the end, the object will be frozen, but some subgraph of it might be not.
This will not be fixed, because [freezing is deprecated](#freezing-deprecation) since 1.7.20.
* Documentation is not updated to reflect changes for the new MM.
* There's no application state handling on iOS: the collector will not be throttled down if the application goes into the background.
However, the collection is not forced upon going into the background, which leaves the application with a larger memory footprint than necessary, making it a more likely target to be terminated by the OS.
* WASM (or any target that doesn't have pthreads) is not supported with the new MM.
## Workarounds
### Unexpected object freezing
> Since 1.7.20 [freezing is deprecated](#freezing-deprecation). Setting `freezing` to anything but `disabled` is deprecated.
> Since 1.6.20 freezing is disabled by default with the new MM.
Some libraries might not be ready for the new MM and freeze-transparency of `kotlinx.coroutines`, so unexpected `InvalidMutabilityException` or `FreezingException` might appear.
To workaround such cases, we added a `freezing` binary option that disables freezing fully (`disabled`) or partially (`explicitOnly`).
@@ -132,4 +132,4 @@ class CacheSupport(
configuration.reportCompilationError("Cache cannot be used in optimized compilation")
}
}
}
}
@@ -73,14 +73,13 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
MemoryModel.STRICT -> MemoryModel.STRICT
MemoryModel.RELAXED -> {
configuration.report(CompilerMessageSeverity.ERROR,
"Relaxed memory model is deprecated and isn't expected to work right way with current Kotlin version." +
" Use strict as default. ")
"Relaxed MM is deprecated and isn't expected to work right way with current Kotlin version. Using legacy MM.")
MemoryModel.STRICT
}
MemoryModel.EXPERIMENTAL -> {
if (!target.supportsThreads()) {
configuration.report(CompilerMessageSeverity.STRONG_WARNING,
"Experimental memory model requires threads, which are not supported on target ${target.name}. Used strict memory model.")
"New MM requires threads, which are not supported on target ${target.name}. Using legacy MM.")
MemoryModel.STRICT
} else {
MemoryModel.EXPERIMENTAL
@@ -90,7 +89,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
}.also {
if (it == MemoryModel.EXPERIMENTAL && destroyRuntimeMode == DestroyRuntimeMode.LEGACY) {
configuration.report(CompilerMessageSeverity.ERROR,
"Experimental memory model is incompatible with 'legacy' destroy runtime mode.")
"New MM is incompatible with 'legacy' destroy runtime mode.")
}
}
}
@@ -127,9 +126,19 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
memoryModel != MemoryModel.EXPERIMENTAL && freezingMode != Freezing.Full -> {
configuration.report(
CompilerMessageSeverity.ERROR,
"`freezing` can only be adjusted with experimental MM. Falling back to default behavior.")
"`freezing` can only be adjusted with new MM. Falling back to default behavior.")
Freezing.Full
}
memoryModel == MemoryModel.EXPERIMENTAL && freezingMode != Freezing.Disabled -> {
// INFO because deprecation is currently ignorable via OptIn. Using WARNING will require silencing (for warnings-as-errors)
// by some compiler flag.
// TODO: When moving into proper deprecation cycle replace with WARNING.
configuration.report(
CompilerMessageSeverity.INFO,
"`freezing` should not be enabled with the new MM. Freezing API is deprecated since 1.7.20. See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation for details"
)
freezingMode
}
else -> freezingMode
}
}
@@ -646,7 +646,7 @@ internal abstract class FunctionGenerationContext(
fun switchThreadState(state: ThreadState) {
check(context.memoryModel == MemoryModel.EXPERIMENTAL) {
"Thread state switching is allowed in the experimental memory model only."
"Thread state switching is allowed in the new MM only."
}
check(!forbidRuntime) {
"Attempt to switch the thread state when runtime is forbidden"
@@ -106,6 +106,12 @@ if (project.globalTestArgs.contains("-g")) {
}
}
if (!isExperimentalMM) {
tasks.withType(KonanCompileNativeBinary.class).configureEach {
extraOpts "-opt-in=kotlin.native.FreezingIsDeprecated"
}
}
allprojects {
// Root directories for test output (logs, compiled files, statistics etc). Only single path must be in each set.
// backend.native/tests
@@ -2,7 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package codegen.enum.isFrozen
import kotlin.test.*
@@ -9,6 +9,7 @@ class X(val s: String)
val x = X("zzz")
// FILE: lib2.kt
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
class Z(val x: Int)
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package codegen.objectDeclaration.isFrozen
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.freeze
// KT-47828
@@ -2,6 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
class A {
var i = 0
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
import kotlin.test.*
import platform.Foundation.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlinx.cinterop.*
import kotlin.native.concurrent.*
import objcTests.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
import kotlinx.cinterop.*
import kotlin.test.*
@@ -2,6 +2,7 @@
* Copyright 2010-2021 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.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
import kotlin.native.internal.Debugging
@@ -2,6 +2,7 @@
* Copyright 2010-2021 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.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
import kotlin.native.internal.Debugging
@@ -5,6 +5,7 @@
// All classes and methods should be used in tests
@file:Suppress("UNUSED")
@file:OptIn(FreezingIsDeprecated::class)
package conversions
@@ -856,8 +857,11 @@ class SharedRefs {
mutableListOf()
}
@OptIn(FreezingIsDeprecated::class)
fun createFrozenRegularObject() = createRegularObject().freeze()
@OptIn(FreezingIsDeprecated::class)
fun createFrozenLambda() = createLambda().freeze()
@OptIn(FreezingIsDeprecated::class)
fun createFrozenCollection() = createCollection().freeze()
fun hasAliveObjects(): Boolean {
@@ -4,6 +4,7 @@
*/
// FILE: hello.kt
@file:OptIn(FreezingIsDeprecated::class)
import kotlinx.cinterop.*
@@ -2,6 +2,7 @@
* Copyright 2010-2021 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.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
import kotlin.native.internal.*
@@ -2,7 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
package runtime.basic.cleaner_basic
@@ -2,7 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
package runtime.basic.cleaner_workers
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.collections.typed_array1
import kotlin.test.*
@@ -2,6 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.concurrent.worker_bound_reference0
@@ -2,6 +2,8 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.test.*
import kotlin.native.concurrent.*
@@ -2,7 +2,7 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
import kotlin.test.*
@@ -2,6 +2,8 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.test.*
import kotlin.native.concurrent.*
@@ -2,7 +2,7 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
import kotlin.test.*
@@ -2,7 +2,7 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
import kotlin.test.*
@@ -2,7 +2,7 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
import kotlin.test.*
@@ -2,6 +2,8 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.test.*
import kotlin.native.concurrent.*
@@ -2,7 +2,7 @@
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(ExperimentalStdlibApi::class)
@file:OptIn(ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
import kotlin.test.*
@@ -2,6 +2,7 @@
* Copyright 2010-2021 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.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.test.*
import kotlin.native.concurrent.*
@@ -2,6 +2,7 @@
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.memory.stable_ref_cross_thread_check
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.atomic0
import kotlin.test.*
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze0
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze1
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze2
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze3
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze4
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze6
@@ -2,6 +2,7 @@
* 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.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze_disabled
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.freeze_stress
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.lazy0
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.lazy1
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
import kotlin.native.ref.*
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.lazy4
import kotlin.test.*
@@ -1,3 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.mutableData1
import kotlin.native.concurrent.*
@@ -1,3 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker10
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker11
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker4
import kotlin.test.*
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker6
import kotlin.test.*
@@ -2,6 +2,7 @@
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker8
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker9
import kotlin.test.*
@@ -3,6 +3,7 @@
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker9_experimentalMM
import kotlin.test.*
@@ -1,3 +1,4 @@
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker_exception_messages
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker_exceptions
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
package runtime.workers.worker_exceptions_legacy
import kotlin.test.*
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
fun main() {
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
fun main() {
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
fun main() {
@@ -1,3 +1,5 @@
@file:OptIn(FreezingIsDeprecated::class)
import kotlin.native.concurrent.*
fun main() {
@@ -2,6 +2,7 @@
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
@file:OptIn(FreezingIsDeprecated::class)
package test.text
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// We benchmark both new and legacy MM.
@file:OptIn(FreezingIsDeprecated::class)
package org.jetbrains.ring
@@ -19,7 +19,7 @@ import kotlin.native.isExperimentalMM
* Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on
* the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future.
*/
@OptIn(kotlin.ExperimentalStdlibApi::class)
@OptIn(kotlin.ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
public actual fun <T> lazy(initializer: () -> T): Lazy<T> =
if (isExperimentalMM())
SynchronizedLazyImpl(initializer)
@@ -38,7 +38,7 @@ public actual fun <T> lazy(initializer: () -> T): Lazy<T> =
* Also this behavior can be changed in the future.
*/
@FixmeConcurrency
@OptIn(kotlin.ExperimentalStdlibApi::class)
@OptIn(kotlin.ExperimentalStdlibApi::class, FreezingIsDeprecated::class)
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
LazyThreadSafetyMode.SYNCHRONIZED -> if (isExperimentalMM()) SynchronizedLazyImpl(initializer) else throw UnsupportedOperationException()
@@ -10,6 +10,7 @@ import kotlin.native.internal.Frozen
import kotlin.native.internal.GCUnsafeCall
@ExportTypeInfo("theStringTypeInfo")
@OptIn(FreezingIsDeprecated::class)
@Frozen
public final class String : Comparable<String>, CharSequence {
public companion object {
@@ -19,6 +19,7 @@ import kotlin.native.internal.NativePtrArray
* @param cause the cause of this throwable.
*/
@ExportTypeInfo("theThrowableTypeInfo")
@OptIn(FreezingIsDeprecated::class)
public open class Throwable(open val message: String?, open val cause: Throwable?) {
constructor(message: String?) : this(message, null)
@@ -173,6 +174,7 @@ public actual inline fun Throwable.printStackTrace(): Unit = printStackTrace()
* Does nothing if this [Throwable] is frozen.
*/
@SinceKotlin("1.4")
@OptIn(FreezingIsDeprecated::class)
public actual fun Throwable.addSuppressed(exception: Throwable) {
if (this !== exception && !this.isFrozen) {
val suppressed = suppressedExceptionsList
@@ -13,6 +13,7 @@ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
@PublishedApi
@SinceKotlin("1.3")
@OptIn(FreezingIsDeprecated::class)
internal actual class SafeContinuation<in T>
internal actual constructor(
private val delegate: Continuation<T>,
@@ -57,6 +57,7 @@ public typealias Throws = kotlin.Throws
public typealias ThreadLocal = kotlin.native.concurrent.ThreadLocal
/** @suppress */
// Not @FreezingIsDeprecated: Lots of usages. Usages will trigger INFO reports in the frontend.
public typealias SharedImmutable = kotlin.native.concurrent.SharedImmutable
/**
@@ -82,4 +83,3 @@ public annotation class EagerInitialization
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
public actual annotation class CName(actual val externName: String = "", actual val shortName: String = "")
@@ -28,6 +28,7 @@ external public fun deinitRuntimeIfNeeded(): Unit
/**
* Exception thrown when top level variable is accessed from incorrect execution context.
*/
@FreezingIsDeprecated
public class IncorrectDereferenceException : RuntimeException {
constructor() : super()
@@ -55,6 +56,7 @@ public typealias ReportUnhandledExceptionHook = Function1<Throwable, Unit>
* i.e. top level main(), or when Objective-C to Kotlin call not marked with @Throws throws an exception.
* Hook must be a frozen lambda, so that it could be called from any thread/worker.
*/
@OptIn(FreezingIsDeprecated::class)
public fun setUnhandledExceptionHook(hook: ReportUnhandledExceptionHook): ReportUnhandledExceptionHook? {
try {
return UnhandledExceptionHookHolder.hook.swap(hook)
@@ -68,6 +70,7 @@ public fun setUnhandledExceptionHook(hook: ReportUnhandledExceptionHook): Report
*/
@ExperimentalStdlibApi
@SinceKotlin("1.6")
@OptIn(FreezingIsDeprecated::class)
public fun getUnhandledExceptionHook(): ReportUnhandledExceptionHook? {
return UnhandledExceptionHookHolder.hook.value
}
@@ -20,6 +20,8 @@ package kotlin.native.concurrent
public actual annotation class ThreadLocal
/**
* Note: with the new MM this annotation has no effect.
*
* Marks a top level property with a backing field as immutable.
* It is possible to share the value of such property between multiple threads, but it becomes deeply frozen,
* so no changes can be made to its state or the state of objects it refers to.
@@ -27,7 +29,10 @@ public actual annotation class ThreadLocal
* The annotation has effect only in Kotlin/Native platform.
*
* PLEASE NOTE THAT THIS ANNOTATION MAY GO AWAY IN UPCOMING RELEASES.
*
* Since 1.7.20 usage of this annotation is deprecated. See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation for details.
*/
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.BINARY)
// Not @FreezingIsDeprecated: Lots of usages, only the doc updated.
public actual annotation class SharedImmutable
@@ -14,6 +14,7 @@ import kotlin.native.internal.*
* in frozen subgraphs. So shared frozen objects can have fields of atomic types.
*/
@Frozen
@OptIn(FreezingIsDeprecated::class)
public class AtomicInt(private var value_: Int) {
/**
* The value being held by this class.
@@ -81,6 +82,7 @@ public class AtomicInt(private var value_: Int) {
}
@Frozen
@OptIn(FreezingIsDeprecated::class)
public class AtomicLong(private var value_: Long = 0) {
/**
* The value being held by this class.
@@ -156,6 +158,7 @@ public class AtomicLong(private var value_: Long = 0) {
}
@Frozen
@OptIn(FreezingIsDeprecated::class)
public class AtomicNativePtr(private var value_: NativePtr) {
/**
* The value being held by this class.
@@ -218,6 +221,7 @@ private fun debugString(value: Any?): String {
@FrozenLegacyMM
@LeakDetectorCandidate
@NoReorderFields
@OptIn(FreezingIsDeprecated::class)
public class AtomicReference<T> {
private var value_: T
@@ -311,6 +315,7 @@ public class AtomicReference<T> {
@NoReorderFields
@LeakDetectorCandidate
@ExportTypeInfo("theFreezableAtomicReferenceTypeInfo")
@FreezingIsDeprecated
public class FreezableAtomicReference<T>(private var value_: T) {
// A spinlock to fix potential ARC race.
private var lock: Int = 0
@@ -8,6 +8,7 @@ package kotlin.native.concurrent
import kotlin.native.internal.*
import kotlinx.cinterop.*
@OptIn(FreezingIsDeprecated::class)
public class Continuation0(block: () -> Unit,
private val invoker: CPointer<CFunction<(COpaquePointer?) -> Unit>>,
private val singleShot: Boolean = false): Function0<Unit> {
@@ -31,6 +32,7 @@ public class Continuation0(block: () -> Unit,
}
}
@OptIn(FreezingIsDeprecated::class)
public class Continuation1<T1>(
block: (p1: T1) -> Unit,
private val invoker: CPointer<CFunction<(COpaquePointer?) -> Unit>>,
@@ -62,6 +64,7 @@ public class Continuation1<T1>(
}
}
@OptIn(FreezingIsDeprecated::class)
public class Continuation2<T1, T2>(
block: (p1: T1, p2: T2) -> Unit,
private val invoker: CPointer<CFunction<(COpaquePointer?) -> Unit>>,
@@ -13,6 +13,7 @@ import kotlin.native.internal.GCUnsafeCall
* @param toFreeze an object intended to be frozen.
* @param blocker an object preventing freezing, usually one marked with [ensureNeverFrozen] earlier.
*/
@FreezingIsDeprecated
public class FreezingException(toFreeze: Any, blocker: Any) :
RuntimeException("freezing of $toFreeze has failed, first blocker is $blocker")
@@ -21,6 +22,7 @@ public class FreezingException(toFreeze: Any, blocker: Any) :
*
* @param where a frozen object that was attempted to mutate
*/
@FreezingIsDeprecated
public class InvalidMutabilityException(message: String) : RuntimeException(message)
/**
@@ -31,6 +33,7 @@ public class InvalidMutabilityException(message: String) : RuntimeException(mess
* @return the object itself
* @see ensureNeverFrozen
*/
@FreezingIsDeprecated
public fun <T> T.freeze(): T {
freezeInternal(this)
return this
@@ -41,6 +44,7 @@ public fun <T> T.freeze(): T {
*
* @return true if given object is null or frozen or permanent
*/
@FreezingIsDeprecated
public val Any?.isFrozen
get() = isFrozenInternal(this)
@@ -52,4 +56,5 @@ public val Any?.isFrozen
* @see freeze
*/
@GCUnsafeCall("Kotlin_Worker_ensureNeverFrozen")
@FreezingIsDeprecated
public external fun Any.ensureNeverFrozen()
@@ -15,6 +15,7 @@ import kotlin.reflect.KClass
import kotlinx.cinterop.*
@GCUnsafeCall("Kotlin_Any_isShareable")
@FreezingIsDeprecated
external internal fun Any?.isShareable(): Boolean
// Implementation details.
@@ -94,28 +95,34 @@ external internal fun detachObjectGraphInternal(mode: Int, producer: () -> Any?)
external internal fun attachObjectGraphInternal(stable: NativePtr): Any?
@GCUnsafeCall("Kotlin_Worker_freezeInternal")
@FreezingIsDeprecated
internal external fun freezeInternal(it: Any?)
@GCUnsafeCall("Kotlin_Worker_isFrozenInternal")
@FreezingIsDeprecated
internal external fun isFrozenInternal(it: Any?): Boolean
@ExportForCppRuntime
@FreezingIsDeprecated
internal fun ThrowFreezingException(toFreeze: Any, blocker: Any): Nothing =
throw FreezingException(toFreeze, blocker)
@ExportForCppRuntime
@FreezingIsDeprecated
internal fun ThrowInvalidMutabilityException(where: Any): Nothing {
val description = debugDescription(where::class, where.identityHashCode())
throw InvalidMutabilityException("mutation attempt of frozen $description")
}
@ExportForCppRuntime
@FreezingIsDeprecated
internal fun ThrowIllegalObjectSharingException(typeInfo: NativePtr, address: NativePtr) {
val description = DescribeObjectForDebugging(typeInfo, address)
throw IncorrectDereferenceException("illegal attempt to access non-shared $description from other thread")
}
@GCUnsafeCall("Kotlin_AtomicReference_checkIfFrozen")
@FreezingIsDeprecated
external internal fun checkIfFrozen(ref: Any?)
@InternalForKotlinNative
@@ -7,6 +7,7 @@ package kotlin.native.concurrent
import kotlin.native.internal.Frozen
@FreezingIsDeprecated
internal class FreezeAwareLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
private val value_ = FreezableAtomicReference<Any?>(UNINITIALIZED)
// This cannot be made atomic because of the legacy MM. See https://github.com/JetBrains/kotlin-native/pull/3944
@@ -67,6 +68,7 @@ internal class FreezeAwareLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
value.toString() else "Lazy value not initialized yet"
}
@OptIn(FreezingIsDeprecated::class)
internal object UNINITIALIZED {
// So that single-threaded configs can use those as well.
init {
@@ -74,6 +76,7 @@ internal object UNINITIALIZED {
}
}
@OptIn(FreezingIsDeprecated::class)
internal object INITIALIZING {
// So that single-threaded configs can use those as well.
init {
@@ -81,6 +84,7 @@ internal object INITIALIZING {
}
}
@FreezingIsDeprecated
@Frozen
internal class AtomicLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
private val initializer_ = AtomicReference<Function0<T>?>(initializer.freeze())
@@ -120,9 +124,11 @@ internal class AtomicLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
* leak memory, so it is recommended to use `atomicLazy` in cases of objects living forever,
* such as object signletons, or in cases where it's guaranteed not to have cyclical garbage.
*/
@FreezingIsDeprecated
public fun <T> atomicLazy(initializer: () -> T): Lazy<T> = AtomicLazyImpl(initializer)
@Suppress("UNCHECKED_CAST")
@OptIn(FreezingIsDeprecated::class)
internal class SynchronizedLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
private var initializer = FreezableAtomicReference<(() -> T)?>(initializer)
private var valueRef = FreezableAtomicReference<Any?>(UNINITIALIZED)
@@ -162,6 +168,7 @@ internal class SynchronizedLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
@Suppress("UNCHECKED_CAST")
@OptIn(FreezingIsDeprecated::class)
internal class SafePublicationLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
private var initializer = FreezableAtomicReference<(() -> T)?>(initializer)
private var valueRef = FreezableAtomicReference<Any?>(UNINITIALIZED)
@@ -8,11 +8,13 @@ package kotlin.native.concurrent
import kotlin.native.internal.Frozen
@ThreadLocal
@OptIn(FreezingIsDeprecated::class)
private object CurrentThread {
val id = Any().freeze()
}
@Frozen
@OptIn(FreezingIsDeprecated::class)
internal class Lock {
private val locker_ = AtomicInt(0)
private val reenterCount_ = AtomicInt(0)
@@ -22,6 +22,7 @@ internal external fun readHeapRefNoLock(where: Any, index: Int): Any?
*/
@Frozen
@NoReorderFields
@FreezingIsDeprecated
public class MutableData constructor(capacity: Int = 16) {
init {
if (capacity <= 0) throw IllegalArgumentException()
@@ -32,6 +32,7 @@ import kotlin.native.internal.Frozen
*
* @see [kotlin.native.internal.GC.collect].
*/
// Not @FreezingIsDeprecated: every `Worker.execute` uses this.
public enum class TransferMode(val value: Int) {
/**
* Reachibility check is performed.
@@ -49,6 +50,7 @@ public enum class TransferMode(val value: Int) {
* externally, until it is attached with the [attach] extension function.
*/
@Frozen
@FreezingIsDeprecated
public class DetachedObjectGraph<T> internal constructor(pointer: NativePtr) {
@PublishedApi
internal val stable = AtomicNativePtr(pointer)
@@ -78,6 +80,7 @@ public class DetachedObjectGraph<T> internal constructor(pointer: NativePtr) {
* make sense anymore, and shall be discarded, so attach of one DetachedObjectGraph object can only
* happen once.
*/
@FreezingIsDeprecated
public inline fun <reified T> DetachedObjectGraph<T>.attach(): T {
var rawStable: NativePtr
do {
@@ -27,6 +27,7 @@ import kotlinx.cinterop.*
* Class representing worker.
*/
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
@OptIn(FreezingIsDeprecated::class)
public value class Worker @PublishedApi internal constructor(val id: Int) {
companion object {
/**
@@ -30,6 +30,7 @@ external private fun describeWorkerBoundReference(ref: NativePtr): String
@ExportTypeInfo("theWorkerBoundReferenceTypeInfo")
@HasFinalizer
@HasFreezeHook
@FreezingIsDeprecated
public class WorkerBoundReference<out T : Any>(value: T) {
private var ptr = NativePtr.NULL
@@ -46,6 +46,7 @@ public annotation class ExportForCompiler
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
@FreezingIsDeprecated
internal annotation class Frozen
/**
@@ -53,6 +54,7 @@ internal annotation class Frozen
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
@FreezingIsDeprecated
internal annotation class FrozenLegacyMM
/**
@@ -161,6 +163,7 @@ internal annotation class InternalForKotlinNative
* Marks a class that has a freeze hook.
*/
@Target(AnnotationTarget.CLASS)
@FreezingIsDeprecated
internal annotation class HasFreezeHook
/**
@@ -69,6 +69,7 @@ public interface Cleaner
// by function name in the compiler.
@ExperimentalStdlibApi
@ExportForCompiler
@OptIn(FreezingIsDeprecated::class)
fun <T> createCleaner(argument: T, block: (T) -> Unit): Cleaner {
if (!argument.isShareable())
throw IllegalArgumentException("$argument must be shareable")
@@ -8,6 +8,7 @@ package kotlin.native.internal
import kotlinx.cinterop.*
@Frozen
@OptIn(FreezingIsDeprecated::class)
class NativePtrBox(val value: NativePtr) {
override fun equals(other: Any?): Boolean {
if (other !is NativePtrBox) {
@@ -25,6 +26,7 @@ class NativePtrBox(val value: NativePtr) {
fun boxNativePtr(value: NativePtr) = NativePtrBox(value)
@Frozen
@OptIn(FreezingIsDeprecated::class)
class NativePointedBox(val value: NativePointed) {
override fun equals(other: Any?): Boolean {
if (other !is NativePointedBox) {
@@ -46,6 +48,7 @@ fun boxNativePointed(value: NativePointed?) = if (value != null) NativePointedBo
fun unboxNativePointed(box: NativePointedBox?) = box?.value
@Frozen
@OptIn(FreezingIsDeprecated::class)
class CPointerBox(val value: CPointer<CPointed>) : CValuesRef<CPointed>() {
override fun equals(other: Any?): Boolean {
if (other !is CPointerBox) {
@@ -101,6 +101,7 @@ internal fun ThrowCharacterCodingException(): Nothing {
}
@ExportForCppRuntime
@FreezingIsDeprecated
internal fun ThrowIncorrectDereferenceException() {
throw IncorrectDereferenceException(
"Trying to access top level value not marked as @ThreadLocal or @SharedImmutable from non-main thread")
@@ -133,6 +134,7 @@ internal fun ReportUnhandledException(throwable: Throwable) {
// Using object to make sure that `hook` is initialized when it's needed instead of
// in a normal global initialization flow. This is important if some global happens
// to throw an exception during it's initialization before this hook would've been initialized.
@OptIn(FreezingIsDeprecated::class)
internal object UnhandledExceptionHookHolder {
internal val hook: FreezableAtomicReference<ReportUnhandledExceptionHook?> =
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
@@ -145,6 +147,7 @@ internal object UnhandledExceptionHookHolder {
// TODO: Can be removed only when native-mt coroutines stop using it.
@PublishedApi
@ExportForCppRuntime
@OptIn(FreezingIsDeprecated::class)
internal fun OnUnhandledException(throwable: Throwable) {
val handler = UnhandledExceptionHookHolder.hook.value
if (handler == null) {
@@ -159,6 +162,7 @@ internal fun OnUnhandledException(throwable: Throwable) {
}
@ExportForCppRuntime("Kotlin_runUnhandledExceptionHook")
@OptIn(FreezingIsDeprecated::class)
internal fun runUnhandledExceptionHook(throwable: Throwable) {
val handler = UnhandledExceptionHookHolder.hook.value ?: throw throwable
handler(throwable)
@@ -37,6 +37,7 @@ fun main(args: Array<String>) {
}
}
@OptIn(FreezingIsDeprecated::class)
fun worker(args: Array<String>) {
val worker = Worker.start()
val exitCode = worker.execute(TransferMode.SAFE, { args.freeze() }) {
@@ -37,6 +37,7 @@ import kotlin.native.internal.Escapes
// Clear holding the counter object, which refers to the actual object.
@NoReorderFields
@Frozen
@OptIn(FreezingIsDeprecated::class)
internal class WeakReferenceCounter(var referred: COpaquePointer?) : WeakReferenceImpl() {
// Spinlock, potentially taken when materializing or removing 'referred' object.
var lock: Int = 0
@@ -20,9 +20,9 @@ data class SharedDataMember(val double: Double)
data class SharedData(val string: String, val int: Int, val member: SharedDataMember)
// Here we access the same shared frozen Kotlin object from multiple threads.
// Here we access the same shared Kotlin object from multiple threads.
val globalObject: SharedData?
get() = sharedData.frozenKotlinObject?.asStableRef<SharedData>()?.get()
get() = sharedData.kotlinObject?.asStableRef<SharedData>()?.get()
fun dumpShared(prefix: String) {
println("""
@@ -39,16 +39,11 @@ fun main() {
sharedData.f = 0.5f
sharedData.string = "Hello Kotlin!".cstr.getPointer(arena)
// Here we create detached mutable object, which could be later reattached by another thread.
sharedData.kotlinObject = DetachedObjectGraph {
SharedData("A string", 42, SharedDataMember(2.39))
}.asCPointer()
// Here we create shared frozen object reference,
val stableRef = StableRef.create(SharedData("Shared", 239, SharedDataMember(2.71)).freeze())
sharedData.frozenKotlinObject = stableRef.asCPointer()
// Here we create shared object reference,
val stableRef = StableRef.create(SharedData("Shared", 239, SharedDataMember(2.71)))
sharedData.kotlinObject = stableRef.asCPointer()
dumpShared("thread1")
println("frozen is $globalObject")
println("shared is $globalObject")
// Start a new thread, that sees the variable.
// memScoped is needed to pass thread's local address to pthread_create().
@@ -57,12 +52,12 @@ fun main() {
pthread_create(thread.ptr, null, staticCFunction { argC ->
initRuntimeIfNeeded()
dumpShared("thread2")
val kotlinObject = DetachedObjectGraph<SharedData>(sharedData.kotlinObject).attach()
val arg = DetachedObjectGraph<SharedDataMember>(argC).attach()
println("thread arg is $arg Kotlin object is $kotlinObject frozen is $globalObject")
val arg = argC!!.asStableRef<SharedDataMember>()
println("thread arg is ${arg.get()} shared is $globalObject")
arg.dispose()
// Workaround for compiler issue.
null as COpaquePointer?
}, DetachedObjectGraph { SharedDataMember(3.14)}.asCPointer() ).ensureUnixCallResult("pthread_create")
}, StableRef.create(SharedDataMember(3.14)).asCPointer() ).ensureUnixCallResult("pthread_create")
pthread_join(thread.value, null).ensureUnixCallResult("pthread_join")
}
@@ -6,7 +6,6 @@ typedef struct {
float f;
char* string;
void* kotlinObject;
void* frozenKotlinObject;
} SharedDataStruct;
SharedDataStruct sharedData;
@@ -1,6 +1,6 @@
package sample.objc
import kotlinx.cinterop.staticCFunction
import kotlinx.cinterop.*
import platform.Foundation.NSOperationQueue
import platform.Foundation.NSThread
import platform.darwin.dispatch_async_f
@@ -10,11 +10,12 @@ import kotlin.native.concurrent.*
import kotlin.test.assertNotNull
inline fun <reified T> executeAsync(queue: NSOperationQueue, crossinline producerConsumer: () -> Pair<T, (T) -> Unit>) {
dispatch_async_f(queue.underlyingQueue, DetachedObjectGraph {
dispatch_async_f(queue.underlyingQueue, StableRef.create(
producerConsumer()
}.asCPointer(), staticCFunction { it ->
val result = DetachedObjectGraph<Pair<T, (T) -> Unit>>(it).attach()
result.second(result.first)
).asCPointer(), staticCFunction { it ->
val result = it!!.asStableRef<Pair<T, (T) -> Unit>>()
result.get().second(result.get().first)
result.dispose()
})
}
@@ -60,8 +61,7 @@ object Continuator {
fun wrap(operation: () -> Unit, after: () -> Unit): () -> Unit {
assert(NSThread.isMainThread())
assert(operation.isFrozen)
val id = Any().freeze()
val id = Any()
map[id] = Pair(0, after)
return {
initRuntimeIfNeeded()
@@ -69,13 +69,12 @@ object Continuator {
executeAsync(NSOperationQueue.mainQueue) {
Pair(id, { id: Any -> Continuator.execute(id) })
}
}.freeze()
}
}
fun <P> wrap(operation: () -> P, block: (P) -> Unit): () -> Unit {
assert(NSThread.isMainThread())
assert(operation.isFrozen)
val id = Any().freeze()
val id = Any()
map[id] = Pair(1, block)
return {
initRuntimeIfNeeded()
@@ -85,7 +84,7 @@ object Continuator {
Continuator.execute(it.first, it.second)
})
}
}.freeze()
}
}
fun execute(id: Any) {
@@ -18,14 +18,8 @@ import kotlin.test.assertNotNull
data class QueryResult(val json: Map<String, *>?, val error: String?)
private fun MutableData.asNSData() = this.withPointerLocked { it, size ->
val result = NSMutableData.create(length = size.convert())!!
memcpy(result.mutableBytes, it, size.convert())
result
}
private fun MutableData.asJSON(): Map<String, *>? =
NSJSONSerialization.JSONObjectWithData(this.asNSData(), 0, null) as? Map<String, *>
private val NSData.json: Map<String, *>?
get() = NSJSONSerialization.JSONObjectWithData(this, 0, null) as? Map<String, *>
fun main() {
autoreleasepool {
@@ -60,7 +54,7 @@ class Controller : NSObject() {
// Here we call continuator service to ensure we can access mutable state from continuation.
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND.convert(), 0),
Continuator.wrap({ println("In queue ${dispatch_get_current_queue()}")}.freeze()) {
Continuator.wrap({ println("In queue ${dispatch_get_current_queue()}")}) {
println("After in queue ${dispatch_get_current_queue()}: $index")
})
@@ -88,14 +82,10 @@ class Controller : NSObject() {
class HttpDelegate: NSObject(), NSURLSessionDataDelegateProtocol {
private val asyncQueue = NSOperationQueue()
private val receivedData = MutableData()
init {
freeze()
}
private var receivedData: NSData? = null
fun fetchUrl(url: String) {
receivedData.reset()
receivedData = null
val session = NSURLSession.sessionWithConfiguration(
NSURLSessionConfiguration.defaultSessionConfiguration(),
this,
@@ -106,7 +96,7 @@ class Controller : NSObject() {
override fun URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData: NSData) {
initRuntimeIfNeeded()
receivedData.append(didReceiveData.bytes, didReceiveData.length.convert())
receivedData = didReceiveData
}
override fun URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError: NSError?) {
@@ -117,7 +107,7 @@ class Controller : NSObject() {
Pair(when {
response == null -> QueryResult(null, didCompleteWithError?.localizedDescription)
response.statusCode.toInt() != 200 -> QueryResult(null, "${response.statusCode.toInt()})")
else -> QueryResult(receivedData.asJSON(), null)
else -> QueryResult(receivedData?.json, null)
}, { result: QueryResult ->
appDelegate.contentText.string = result.json?.toString() ?: "Error: ${result.error}"
appDelegate.canClick = true
@@ -6,7 +6,9 @@
package kotlin.collections
import kotlin.native.concurrent.isFrozen
import kotlin.native.FreezingIsDeprecated
@OptIn(FreezingIsDeprecated::class)
actual class HashMap<K, V> private constructor(
private var keysArray: Array<K>,
private var valuesArray: Array<V>?, // allocated only when actually used, always null in pure HashSet
@@ -0,0 +1,36 @@
/*
* 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.
*/
package kotlin.native
// This is here instead of kotlin-native/runtime because some of native-wasm uses this annotation.
/**
* Freezing API is deprecated since 1.7.20.
*
* See [NEW_MM.md#freezing-deprecation](https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation) for details
*/
// Note: when changing level of deprecation here, also change
// * `freezing` mode handling in KonanConfig.kt
// * frontend diagnostics in ErrorsNative.kt
@SinceKotlin("1.7")
@RequiresOptIn(
message = "Freezing API is deprecated since 1.7.20. See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation for details",
level = RequiresOptIn.Level.WARNING,
)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.PROPERTY,
AnnotationTarget.FIELD,
AnnotationTarget.LOCAL_VARIABLE,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.TYPEALIAS,
)
@Retention(AnnotationRetention.BINARY)
actual annotation class FreezingIsDeprecated
@@ -27,6 +27,7 @@ import kotlin.collections.associate
import kotlin.native.concurrent.AtomicReference
import kotlin.native.concurrent.freeze
import kotlin.native.BitSet
import kotlin.native.FreezingIsDeprecated
/**
* Unicode category (i.e. Ll, Lu).
@@ -48,6 +49,7 @@ internal class UnicodeCategoryScope(category: Int) : UnicodeCategory(category) {
* This class represents character classes, i.e. sets of character either predefined or user defined.
* Note: this class represent a token, not node, so being constructed by lexer.
*/
@OptIn(FreezingIsDeprecated::class)
internal abstract class AbstractCharClass : SpecialToken() {
/**
* Show if the class has alternative meaning:
@@ -16,3 +16,33 @@ package kotlin.native
@Retention(AnnotationRetention.BINARY)
@OptionalExpectation
public expect annotation class CName(val externName: String = "", val shortName: String = "")
/**
* Freezing API is deprecated since 1.7.20.
*
* See [NEW_MM.md#freezing-deprecation](https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation) for details
*/
// Note: when changing level of deprecation here, also change
// * `freezing` mode handling in KonanConfig.kt
// * frontend diagnostics in ErrorsNative.kt
@SinceKotlin("1.7")
@RequiresOptIn(
message = "Freezing API is deprecated since 1.7.20. See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation for details",
level = RequiresOptIn.Level.WARNING,
)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.PROPERTY,
AnnotationTarget.FIELD,
AnnotationTarget.LOCAL_VARIABLE,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.TYPEALIAS,
)
@Retention(AnnotationRetention.BINARY)
@OptionalExpectation
expect annotation class FreezingIsDeprecated
@@ -21,6 +21,8 @@ package kotlin.native.concurrent
public expect annotation class ThreadLocal()
/**
* Note: with the new MM this annotation has no effect.
*
* Marks a top level property with a backing field as immutable.
* It is possible to share the value of such property between multiple threads, but it becomes deeply frozen,
* so no changes can be made to its state or the state of objects it refers to.
@@ -28,9 +30,12 @@ public expect annotation class ThreadLocal()
* The annotation has effect only in Kotlin/Native platform.
*
* PLEASE NOTE THAT THIS ANNOTATION MAY GO AWAY IN UPCOMING RELEASES.
*
* Since 1.7.20 usage of this annotation is deprecated. See https://github.com/JetBrains/kotlin/blob/master/kotlin-native/NEW_MM.md#freezing-deprecation for details.
*/
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.BINARY)
// Not @FreezingIsDeprecated: Lots of usages, only the doc updated.
@OptionalExpectation
public expect annotation class SharedImmutable()
@@ -27,13 +27,13 @@ object ErrorsNative {
@JvmField
val INAPPLICABLE_SHARED_IMMUTABLE_TOP_LEVEL = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
@JvmField
val VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL = DiagnosticFactory0.create<KtElement>(Severity.WARNING)
val VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL = DiagnosticFactory0.create<KtElement>(Severity.INFO)
@JvmField
val INAPPLICABLE_THREAD_LOCAL = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
@JvmField
val INAPPLICABLE_THREAD_LOCAL_TOP_LEVEL = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
@JvmField
val VARIABLE_IN_ENUM = DiagnosticFactory0.create<KtElement>(Severity.WARNING)
val VARIABLE_IN_ENUM = DiagnosticFactory0.create<KtElement>(Severity.INFO)
@JvmField
val INVALID_CHARACTERS_NATIVE = DiagnosticFactoryForDeprecation1.create<PsiElement, String>(LanguageFeature.ProhibitInvalidCharsInNativeIdentifiers)