diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt index e88d3f0dbe8..3741765908c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryOptions.kt @@ -15,6 +15,8 @@ object BinaryOptions : BinaryOptionRegistry() { val runtimeAssertionsMode by option() val memoryModel by option() + + val freezing by option() } open class BinaryOption( diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Freezing.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Freezing.kt new file mode 100644 index 00000000000..fecf196c7bb --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Freezing.kt @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.backend.konan + +/** + * Gradually control what parts of freezing are enabled. + * Not intended to be used with legacy MM where freezing is a must. + * + * If [enableFreezeAtRuntime] is false then `Any.freeze()` and `checkIfFrozen(ref: Any?)` are no-op. + * [freezeImplicit] enabled freezing for @Frozen types and @SharedImmutable globals (i.e. implicit calls to `Any.freeze()`). + */ +enum class Freezing(val enableFreezeAtRuntime: Boolean, val freezeImplicit: Boolean) { + /** + * Enable freezing in `Any.freeze()` as well as for @Frozen types and @SharedImmutable globals. + */ + Full(true, true), + + /** + * Enable freezing only in explicit calls to `Any.freeze()`. + */ + ExplicitOnly(true, false), + + /** + * No freezing at all. + */ + Disabled(false, false); + + companion object { + // Users might depend on runtime guarantees of freezing, so it should be enabled by default. + val Default = Full + } +} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 625f7b24ace..c2b649f2280 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -81,6 +81,19 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration val runtimeAssertsMode: RuntimeAssertsMode get() = configuration.get(BinaryOptions.runtimeAssertionsMode) ?: RuntimeAssertsMode.IGNORE val workerExceptionHandling: WorkerExceptionHandling get() = configuration.get(KonanConfigKeys.WORKER_EXCEPTION_HANDLING)!! val runtimeLogs: String? get() = configuration.get(KonanConfigKeys.RUNTIME_LOGS) + val freezing: Freezing by lazy { + val freezingMode = configuration.get(BinaryOptions.freezing) + when { + freezingMode == null -> Freezing.Default + memoryModel != MemoryModel.EXPERIMENTAL && freezingMode != Freezing.Default -> { + configuration.report( + CompilerMessageSeverity.ERROR, + "`freezing` can only be adjusted with experimental MM. Falling back to default behavior.") + Freezing.Default + } + else -> freezingMode + } + } val needVerifyIr: Boolean get() = configuration.get(KonanConfigKeys.VERIFY_IR) == true diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 9c76fefc44d..fb670e07ea1 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -88,6 +88,11 @@ val IrField.isGlobalNonPrimitive get() = when { else -> storageKind == FieldStorageKind.GLOBAL } + +internal fun IrField.shouldBeFrozen(context: Context): Boolean = + this.storageKind == FieldStorageKind.SHARED_FROZEN && + (context.memoryModel != MemoryModel.EXPERIMENTAL || context.config.freezing.freezeImplicit) + internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid { val generator = RTTIGenerator(context) @@ -341,7 +346,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map?) { val initialization = evaluateExpression(irField.initializer!!.expression) - if (irField.storageKind == FieldStorageKind.SHARED_FROZEN) + if (irField.shouldBeFrozen(context)) freeze(initialization, currentCodeContext.exceptionHandler) initialization } else { @@ -1754,7 +1759,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map(Kotlin_destroyRuntimeMode); @@ -25,3 +26,7 @@ ALWAYS_INLINE bool compiler::gcAggressive() noexcept { ALWAYS_INLINE compiler::WorkerExceptionHandling compiler::workerExceptionHandling() noexcept { return static_cast(Kotlin_workerExceptionHandling); } + +ALWAYS_INLINE bool compiler::freezingEnabled() noexcept { + return Kotlin_freezingEnabled != 0; +} diff --git a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp index 38034eced3e..b21310be196 100644 --- a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp +++ b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp @@ -69,6 +69,8 @@ ALWAYS_INLINE inline std::string_view runtimeLogs() noexcept { return Kotlin_runtimeLogs == nullptr ? std::string_view() : std::string_view(Kotlin_runtimeLogs); } +bool freezingEnabled() noexcept; + } // namespace compiler } // namespace kotlin diff --git a/kotlin-native/runtime/src/main/cpp/Worker.cpp b/kotlin-native/runtime/src/main/cpp/Worker.cpp index f885f09ee0b..a54c879f32c 100644 --- a/kotlin-native/runtime/src/main/cpp/Worker.cpp +++ b/kotlin-native/runtime/src/main/cpp/Worker.cpp @@ -1167,7 +1167,7 @@ KNativePtr Kotlin_Worker_detachObjectGraphInternal(KInt transferMode, KRef produ } void Kotlin_Worker_freezeInternal(KRef object) { - if (object != nullptr) + if (object != nullptr && compiler::freezingEnabled()) FreezeSubgraph(object); }