From f70852af3ff9e672704f9101c7643b1b3b44d67e Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Sun, 8 Nov 2020 17:32:44 +0300 Subject: [PATCH 01/15] Add DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED --- .../org/jetbrains/kotlin/cli/bc/K2Native.kt | 9 ++ .../cli/bc/K2NativeCompilerArguments.kt | 3 + .../backend/konan/DestroyRuntimeMode.kt | 12 +++ .../kotlin/backend/konan/KonanConfig.kt | 5 + .../backend/konan/KonanConfigurationKeys.kt | 2 + .../kotlin/backend/konan/llvm/IrToBitcode.kt | 22 +++-- backend.native/tests/build.gradle | 13 ++- .../interop/migrating_main_thread/main.cpp | 20 +++- backend.native/tests/interop/objc/smoke.kt | 2 + .../org/jetbrains/kotlin/KotlinNativeTest.kt | 8 +- runtime/src/legacymm/cpp/Memory.cpp | 50 +++++++--- runtime/src/main/cpp/Memory.h | 4 +- runtime/src/main/cpp/Runtime.cpp | 98 ++++++++++++++++--- runtime/src/main/cpp/Runtime.h | 11 +++ .../src/main/kotlin/kotlin/native/Platform.kt | 10 ++ runtime/src/mm/cpp/Stubs.cpp | 4 +- 16 files changed, 229 insertions(+), 44 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 61cfb7e85da..a2a9644ab57 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -250,6 +250,15 @@ class K2Native : CLICompiler() { put(DISABLE_FAKE_OVERRIDE_VALIDATOR, arguments.disableFakeOverrideValidator) putIfNotNull(PRE_LINK_CACHES, parsePreLinkCachesValue(configuration, arguments.preLinkCaches)) putIfNotNull(OVERRIDE_KONAN_PROPERTIES, parseOverrideKonanProperties(arguments, configuration)) + put(DESTROY_RUNTIME_MODE, when (arguments.destroyRuntimeMode) { + "legacy" -> DestroyRuntimeMode.LEGACY + "on-shutdown" -> DestroyRuntimeMode.ON_SHUTDOWN + "on-shutdown-checked" -> DestroyRuntimeMode.ON_SHUTDOWN_CHECKED + else -> { + configuration.report(ERROR, "Unsupported destroy runtime mode ${arguments.destroyRuntimeMode}") + DestroyRuntimeMode.ON_SHUTDOWN + } + }) } } } diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index e1626f30e83..51f65e38a94 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -285,6 +285,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { ) var overrideKonanProperties: Array? = null + @Argument(value="-Xdestroy-runtime-mode", valueDescription = "", description = "When to destroy runtime. 'legacy', 'on-shutdown' and 'on-shutdown-checked' are currently supported. NOTE: 'legacy' mode is deprecated and will be removed.") + var destroyRuntimeMode: String? = "on-shutdown" + override fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> = super.configureAnalysisFlags(collector).also { val useExperimental = it[AnalysisFlags.useExperimental] as List<*> diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt new file mode 100644 index 00000000000..e2d31cf9a04 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt @@ -0,0 +1,12 @@ +/* + * 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. + */ +package org.jetbrains.kotlin.backend.konan + +// Must match DestroyRuntimeMode in Runtime.h +enum class DestroyRuntimeMode(val value: Int) { + LEGACY(0), + ON_SHUTDOWN(1), + ON_SHUTDOWN_CHECKED(2) +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index ccfc2ccc813..d1a4b25f86f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -45,6 +45,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration ?: target.family.isAppleFamily // Default is true for Apple targets. val memoryModel: MemoryModel get() = configuration.get(KonanConfigKeys.MEMORY_MODEL)!! + val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)!! val needCompilerVerification: Boolean get() = configuration.get(KonanConfigKeys.VERIFY_COMPILER) ?: @@ -128,6 +129,10 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration configuration.report(CompilerMessageSeverity.STRONG_WARNING, "Experimental memory model requires threads, which are not supported on target ${target.name}. Used strict memory model.") MemoryModel.STRICT + } else if (destroyRuntimeMode == DestroyRuntimeMode.LEGACY) { + configuration.report(CompilerMessageSeverity.STRONG_WARNING, + "Experimental memory model is incompatible with 'legacy' destroy runtime mode. Used strict memory model.") + MemoryModel.STRICT } else { MemoryModel.EXPERIMENTAL } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 140a23265be..16b84887046 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -144,6 +144,8 @@ class KonanConfigKeys { = CompilerConfigurationKey.create("perform compiler caches pre-link") val OVERRIDE_KONAN_PROPERTIES: CompilerConfigurationKey> = CompilerConfigurationKey.create("override konan.properties values") + val DESTROY_RUNTIME_MODE: CompilerConfigurationKey + = CompilerConfigurationKey.create("when to destroy runtime") } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index b6eeb3a3cc5..402873761c9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -364,7 +364,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map s.contains("Memory leaks detected, 1 objects leaked!") } } diff --git a/backend.native/tests/interop/migrating_main_thread/main.cpp b/backend.native/tests/interop/migrating_main_thread/main.cpp index 40cb53a1a98..f90335d7c2e 100644 --- a/backend.native/tests/interop/migrating_main_thread/main.cpp +++ b/backend.native/tests/interop/migrating_main_thread/main.cpp @@ -8,17 +8,27 @@ #include #include +constexpr int kInitialValue = 0; +constexpr int kNewValue = 0; + +#if defined(IS_LEGACY) +// Globals were reinitialized. +constexpr int kResultValue = kInitialValue; +#else +// Globals were kept. +constexpr int kResultValue = kNewValue; +#endif + int main() { std::thread main1([]() { - assert(testlib_symbols()->kotlin.root.readFromA() == 0); - testlib_symbols()->kotlin.root.writeToA(1); - assert(testlib_symbols()->kotlin.root.readFromA() == 1); + assert(testlib_symbols()->kotlin.root.readFromA() == kInitialValue); + testlib_symbols()->kotlin.root.writeToA(kNewValue); + assert(testlib_symbols()->kotlin.root.readFromA() == kNewValue); }); main1.join(); std::thread main2([]() { - // Globals were reinitialized. - assert(testlib_symbols()->kotlin.root.readFromA() == 0); + assert(testlib_symbols()->kotlin.root.readFromA() == kResultValue); }); main2.join(); diff --git a/backend.native/tests/interop/objc/smoke.kt b/backend.native/tests/interop/objc/smoke.kt index c65be68f0bd..8ca0e9a67b0 100644 --- a/backend.native/tests/interop/objc/smoke.kt +++ b/backend.native/tests/interop/objc/smoke.kt @@ -10,6 +10,8 @@ import kotlin.native.ref.* import kotlin.test.* fun main(args: Array) { + // Test relies on full deinitialization at shutdown. + kotlin.native.Platform.forceCheckedShutdown = true autoreleasepool { run() } diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt index 3e06ca43962..cd1420545bf 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/KotlinNativeTest.kt @@ -419,8 +419,12 @@ open class KonanDynamicTest : KonanStandaloneTest() { @Input lateinit var cSource: String + @Input var clangTool = "clang" + @Input + var clangFlags: List = listOf() + // Replace testlib_api.h and all occurrences of the testlib with the actual name of the test private fun processCSource(): String { val sourceFile = File(cSource) @@ -453,7 +457,7 @@ open class KonanDynamicTest : KonanStandaloneTest() { "-c", "-o", "$executable.o", "-I", artifactsDir - ) + ) + clangFlags it.standardOutput = log it.errorOutput = log it.isIgnoreExitValue = true @@ -485,4 +489,4 @@ open class KonanDynamicTest : KonanStandaloneTest() { it.execute() } } -} \ No newline at end of file +} diff --git a/runtime/src/legacymm/cpp/Memory.cpp b/runtime/src/legacymm/cpp/Memory.cpp index b91b2997eaa..f2879ba1b2b 100644 --- a/runtime/src/legacymm/cpp/Memory.cpp +++ b/runtime/src/legacymm/cpp/Memory.cpp @@ -576,7 +576,7 @@ class ForeignRefManager { if (atomicGet(&aliveMemoryStatesCount) == 0) return; - memoryState = InitMemory(); // Required by ReleaseHeapRef. + memoryState = InitMemory(false); // Required by ReleaseHeapRef. } processEnqueuedReleaseRefsWith([](ObjHeader* obj) { @@ -585,7 +585,7 @@ class ForeignRefManager { if (hadNoStateInitialized) { // Discard the memory state. - DeinitMemory(memoryState); + DeinitMemory(memoryState, false); } } } @@ -1978,7 +1978,7 @@ void deinitForeignRef(ObjHeader* object, ForeignRefManager* manager) { } } -MemoryState* initMemory() { +MemoryState* initMemory(bool firstRuntime) { RuntimeAssert(offsetof(ArrayHeader, typeInfoOrMeta_) == offsetof(ObjHeader, typeInfoOrMeta_), @@ -2005,22 +2005,46 @@ MemoryState* initMemory() { memoryState->tlsMap = konanConstructInstance(); memoryState->foreignRefManager = ForeignRefManager::create(); bool firstMemoryState = atomicAdd(&aliveMemoryStatesCount, 1) == 1; - if (firstMemoryState) { + switch (Kotlin_destroyRuntimeMode) { + case DESTROY_RUNTIME_LEGACY: + firstRuntime = firstMemoryState; + break; + case DESTROY_RUNTIME_ON_SHUTDOWN: + case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: + // Nothing to do. + break; + } + if (firstRuntime) { #if USE_CYCLIC_GC cyclicInit(); #endif // USE_CYCLIC_GC memoryState->isMainThread = true; } + if (!firstRuntime && firstMemoryState) { + memoryState->isMainThread = true; + // This thread is now the main thread. And there was a previous main thread, because this is not the first runtime. + // Make sure this thread sees all the updates to Kotlin globals from the previous main thread. + synchronize(); + } return memoryState; } -void deinitMemory(MemoryState* memoryState) { +void deinitMemory(MemoryState* memoryState, bool destroyRuntime) { static int pendingDeinit = 0; atomicAdd(&pendingDeinit, 1); #if USE_GC bool lastMemoryState = atomicAdd(&aliveMemoryStatesCount, -1) == 0; - bool checkLeaks = Kotlin_memoryLeakCheckerEnabled() && lastMemoryState; - if (lastMemoryState) { + switch (Kotlin_destroyRuntimeMode) { + case DESTROY_RUNTIME_LEGACY: + destroyRuntime = lastMemoryState; + break; + case DESTROY_RUNTIME_ON_SHUTDOWN: + case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: + // Nothing to do. + break; + } + bool checkLeaks = Kotlin_memoryLeakCheckerEnabled() && destroyRuntime; + if (destroyRuntime) { garbageCollect(memoryState, true); #if USE_CYCLIC_GC // If there are other pending deinits (rare situation) - just skip the leak checker. @@ -2032,6 +2056,10 @@ void deinitMemory(MemoryState* memoryState) { cyclicDeinit(g_hasCyclicCollector); #endif // USE_CYCLIC_GC } + if (!destroyRuntime && memoryState->isMainThread) { + // If we are not destroying the runtime but we were the main thread, publish all changes to Kotlin globals. + synchronize(); + } // Actual GC only implemented in strict memory model at the moment. do { GC_LOG("Calling garbageCollect from DeinitMemory()\n") @@ -3231,12 +3259,12 @@ void AdoptReferenceFromSharedVariable(ObjHeader* object) { } // Public memory interface. -MemoryState* InitMemory() { - return initMemory(); +MemoryState* InitMemory(bool firstRuntime) { + return initMemory(firstRuntime); } -void DeinitMemory(MemoryState* memoryState) { - deinitMemory(memoryState); +void DeinitMemory(MemoryState* memoryState, bool destroyRuntime) { + deinitMemory(memoryState, destroyRuntime); } void RestoreMemory(MemoryState* memoryState) { diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index 46b45c36b05..be5ab005796 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -122,8 +122,8 @@ extern "C" { struct MemoryState; -MemoryState* InitMemory(); -void DeinitMemory(MemoryState*); +MemoryState* InitMemory(bool firstRuntime); +void DeinitMemory(MemoryState*, bool destroyRuntime); void RestoreMemory(MemoryState*); // diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 40d45e493c0..7a39715a3c3 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -65,6 +65,7 @@ void InitOrDeinitGlobalVariables(int initialize, MemoryState* memory) { KBoolean g_checkLeaks = KonanNeedDebugInfo; KBoolean g_checkLeakedCleaners = KonanNeedDebugInfo; +KBoolean g_forceCheckedShutdown = Kotlin_destroyRuntimeMode == DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED; constexpr RuntimeState* kInvalidRuntime = nullptr; @@ -91,11 +92,29 @@ RuntimeState* initRuntime() { RuntimeCheck(!isValidRuntime(), "No active runtimes allowed"); ::runtimeState = result; - compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning); + bool firstRuntime = false; + switch (Kotlin_destroyRuntimeMode) { + case DESTROY_RUNTIME_LEGACY: + compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning); + result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode + result->worker = WorkerInit(true); + firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1; + break; + case DESTROY_RUNTIME_ON_SHUTDOWN: + case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: + // First update `aliveRuntimesCount` and then update `globalRuntimeStatus`, for synchronization with + // runtime shutdown, which does it the other way around. + atomicAdd(&aliveRuntimesCount, 1); + auto lastStatus = compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning); + if (lastStatus == kGlobalRuntimeShutdown && Kotlin_forceCheckedShutdown()) { + konan::consoleErrorf("Kotlin runtime was shut down. Cannot create new runtimes\n"); + konan::abort(); + } + firstRuntime = lastStatus == kGlobalRuntimeUninitialized; + result->memoryState = InitMemory(firstRuntime); // The argument will be ignored for legacy DestroyRuntimeMode + result->worker = WorkerInit(true); + } - result->memoryState = InitMemory(); - result->worker = WorkerInit(true); - bool firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1; // Keep global variables in state as well. if (firstRuntime) { konan::consoleInit(); @@ -110,25 +129,34 @@ RuntimeState* initRuntime() { return result; } -void deinitRuntime(RuntimeState* state) { +void deinitRuntime(RuntimeState* state, bool destroyRuntime) { RuntimeAssert(state->status == RuntimeStatus::kRunning, "Runtime must be in the running state"); state->status = RuntimeStatus::kDestroying; // This may be called after TLS is zeroed out, so ::memoryState in Memory cannot be trusted. RestoreMemory(state->memoryState); bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0; + switch (Kotlin_destroyRuntimeMode) { + case DESTROY_RUNTIME_LEGACY: + destroyRuntime = lastRuntime; + break; + case DESTROY_RUNTIME_ON_SHUTDOWN: + case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: + // Nothing to do. + break; + } InitOrDeinitGlobalVariables(DEINIT_THREAD_LOCAL_GLOBALS, state->memoryState); - if (lastRuntime) + if (destroyRuntime) InitOrDeinitGlobalVariables(DEINIT_GLOBALS, state->memoryState); auto workerId = GetWorkerId(state->worker); WorkerDeinit(state->worker); - DeinitMemory(state->memoryState); + DeinitMemory(state->memoryState, destroyRuntime); konanDestructInstance(state); WorkerDestroyThreadDataIfNeeded(workerId); } void Kotlin_deinitRuntimeCallback(void* argument) { auto* state = reinterpret_cast(argument); - deinitRuntime(state); + deinitRuntime(state, false); } } // namespace @@ -155,17 +183,32 @@ void Kotlin_initRuntimeIfNeeded() { void Kotlin_deinitRuntimeIfNeeded() { if (isValidRuntime()) { - deinitRuntime(::runtimeState); + deinitRuntime(::runtimeState, false); ::runtimeState = kInvalidRuntime; } } // TODO: Consider exporting it to interop API. void Kotlin_shutdownRuntime() { - // TODO: If checkers are disabled, we can set status to "shutdown" here, and return. auto* runtime = ::runtimeState; RuntimeAssert(runtime != kInvalidRuntime, "Current thread must have Kotlin runtime initialized on it"); + bool needsFullShutdown = false; + switch (Kotlin_destroyRuntimeMode) { + case DESTROY_RUNTIME_LEGACY: + needsFullShutdown = true; + break; + case DESTROY_RUNTIME_ON_SHUTDOWN: + case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: + needsFullShutdown = Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled(); + break; + } + if (!needsFullShutdown) { + auto lastStatus = compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeRunning, kGlobalRuntimeShutdown); + RuntimeAssert(lastStatus == kGlobalRuntimeRunning, "Invalid runtime status for shutdown"); + return; + } + if (Kotlin_cleanersLeakCheckerEnabled()) { // Make sure to collect any lingering cleaners. PerformFullGC(runtime->memoryState); @@ -178,13 +221,22 @@ void Kotlin_shutdownRuntime() { auto lastStatus = compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeRunning, kGlobalRuntimeShutdown); RuntimeAssert(lastStatus == kGlobalRuntimeRunning, "Invalid runtime status for shutdown"); - // TODO: If we add early return at the top, this if would be unneeded. - if (Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled()) { + if (Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled()) { // First make sure workers are gone. WaitNativeWorkersTermination(); + + if (Kotlin_forceCheckedShutdown()) { + // Now check for existence of any other runtimes. + auto otherRuntimesCount = atomicGet(&aliveRuntimesCount) - 1; + RuntimeAssert(otherRuntimesCount >= 0, "Cannot be negative"); + if (otherRuntimesCount > 0) { + konan::consoleErrorf("Cannot run checkers when there are %d alive runtimes at the shutdown", otherRuntimesCount); + konan::abort(); + } + } } - deinitRuntime(runtime); + deinitRuntime(runtime, true); ::runtimeState = kInvalidRuntime; } @@ -280,4 +332,24 @@ void Konan_Platform_setCleanersLeakChecker(KBoolean value) { g_checkLeakedCleaners = value; } +bool Kotlin_forceCheckedShutdown() { + return g_forceCheckedShutdown; +} + +KBoolean Konan_Platform_getForceCheckedShutdown() { + return g_forceCheckedShutdown; +} + +void Konan_Platform_setForceCheckedShutdown(KBoolean value) { + switch (Kotlin_destroyRuntimeMode) { + case DESTROY_RUNTIME_LEGACY: + // Only applicable to ON_SHUTDOWN modes. + return; + case DESTROY_RUNTIME_ON_SHUTDOWN: + case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: + break; + } + g_forceCheckedShutdown = value; +} + } // extern "C" diff --git a/runtime/src/main/cpp/Runtime.h b/runtime/src/main/cpp/Runtime.h index 2b4e6d152ed..34845e7c135 100644 --- a/runtime/src/main/cpp/Runtime.h +++ b/runtime/src/main/cpp/Runtime.h @@ -25,6 +25,15 @@ struct InitNode; extern "C" { #endif +// Must match DestroyRuntimeMode in DestroyRuntimeMode.kt +enum DestroyRuntimeMode { + DESTROY_RUNTIME_LEGACY = 0, + DESTROY_RUNTIME_ON_SHUTDOWN = 1, + DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED = 2, +}; + +RUNTIME_WEAK extern const DestroyRuntimeMode Kotlin_destroyRuntimeMode; + void Kotlin_initRuntimeIfNeeded(); void Kotlin_deinitRuntimeIfNeeded(); @@ -41,6 +50,8 @@ bool Kotlin_memoryLeakCheckerEnabled(); bool Kotlin_cleanersLeakCheckerEnabled(); +bool Kotlin_forceCheckedShutdown(); + #ifdef __cplusplus } #endif diff --git a/runtime/src/main/kotlin/kotlin/native/Platform.kt b/runtime/src/main/kotlin/kotlin/native/Platform.kt index 6ca425e88fa..8d799af6d7f 100644 --- a/runtime/src/main/kotlin/kotlin/native/Platform.kt +++ b/runtime/src/main/kotlin/kotlin/native/Platform.kt @@ -96,6 +96,10 @@ public object Platform { public var isCleanersLeakCheckerActive: Boolean get() = Platform_getCleanersLeakChecker() set(value) = Platform_setCleanersLeakChecker(value) + + public var forceCheckedShutdown: Boolean + get() = Platform_getForceCheckedShutdown() + set(value) = Platform_setForceCheckedShutdown(value) } @SymbolName("Konan_Platform_canAccessUnaligned") @@ -127,3 +131,9 @@ private external fun Platform_getCleanersLeakChecker(): Boolean @SymbolName("Konan_Platform_setCleanersLeakChecker") private external fun Platform_setCleanersLeakChecker(value: Boolean): Unit + +@SymbolName("Konan_Platform_getForceCheckedShutdown") +private external fun Platform_getForceCheckedShutdown(): Boolean + +@SymbolName("Konan_Platform_setForceCheckedShutdown") +private external fun Platform_setForceCheckedShutdown(value: Boolean): Unit diff --git a/runtime/src/mm/cpp/Stubs.cpp b/runtime/src/mm/cpp/Stubs.cpp index cfc6582cd1d..c0b6f7b2019 100644 --- a/runtime/src/mm/cpp/Stubs.cpp +++ b/runtime/src/mm/cpp/Stubs.cpp @@ -47,11 +47,11 @@ static void destroyMetaObject(TypeInfo** location) { extern "C" { -MemoryState* InitMemory() { +MemoryState* InitMemory(bool firstRuntime) { RuntimeCheck(false, "Unimplemented"); } -void DeinitMemory(MemoryState*) { +void DeinitMemory(MemoryState*, bool destroyRuntime) { RuntimeCheck(false, "Unimplemented"); } From 331d545416206ee5df2e75b825966a375713851e Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Mon, 9 Nov 2020 12:26:49 +0300 Subject: [PATCH 02/15] REMOVE ME: debugging --- runtime/src/main/cpp/Runtime.cpp | 4 ++++ runtime/src/main/kotlin/kotlin/native/Platform.kt | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 7a39715a3c3..e01268fa822 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -352,4 +352,8 @@ void Konan_Platform_setForceCheckedShutdown(KBoolean value) { g_forceCheckedShutdown = value; } +KInt Konan_getThingy() { + return Kotlin_destroyRuntimeMode; +} + } // extern "C" diff --git a/runtime/src/main/kotlin/kotlin/native/Platform.kt b/runtime/src/main/kotlin/kotlin/native/Platform.kt index 8d799af6d7f..b69d4e3eab1 100644 --- a/runtime/src/main/kotlin/kotlin/native/Platform.kt +++ b/runtime/src/main/kotlin/kotlin/native/Platform.kt @@ -100,8 +100,14 @@ public object Platform { public var forceCheckedShutdown: Boolean get() = Platform_getForceCheckedShutdown() set(value) = Platform_setForceCheckedShutdown(value) + + public val thingy: Int + get() = getThingy() } +@SymbolName("Konan_getThingy") +private external fun getThingy(): Int + @SymbolName("Konan_Platform_canAccessUnaligned") private external fun Platform_canAccessUnaligned(): Int From 3e90862929fa5d8f0e7b7997ebb0ed2b90b27b78 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Mon, 9 Nov 2020 14:03:01 +0300 Subject: [PATCH 03/15] Fixing globals --- .../org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 402873761c9..b8c210009bc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2390,9 +2390,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map Date: Mon, 9 Nov 2020 14:04:45 +0300 Subject: [PATCH 04/15] Fix a test --- backend.native/tests/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index d9e2db9ab23..3822273d783 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -4362,8 +4362,7 @@ dynamicTest("interop_cleaners_leak") { } dynamicTest("interop_migrating_main_thread_legacy") { - // TODO: Fix it. - disabled = (project.testTarget != null && project.testTarget != project.hostName) + disabled = (project.target.name != project.hostName) source = "interop/migrating_main_thread/lib.kt" flags = ['-Xdestroy-runtime-mode=legacy'] clangFlags = ['-DIS_LEGACY'] From 3b8c8995b56d80b533357b8521ec30ac00b05afa Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Mon, 9 Nov 2020 14:20:32 +0300 Subject: [PATCH 05/15] Fixing globals --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 45 ++++++++++++++----- runtime/src/legacymm/cpp/Memory.cpp | 4 +- runtime/src/main/cpp/Runtime.cpp | 18 +++++--- runtime/src/main/cpp/Runtime.h | 2 +- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index b8c210009bc..203f55838bc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -364,6 +364,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: MaptlsMap = konanConstructInstance(); memoryState->foreignRefManager = ForeignRefManager::create(); bool firstMemoryState = atomicAdd(&aliveMemoryStatesCount, 1) == 1; - switch (Kotlin_destroyRuntimeMode) { + switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: firstRuntime = firstMemoryState; break; @@ -2034,7 +2034,7 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) { atomicAdd(&pendingDeinit, 1); #if USE_GC bool lastMemoryState = atomicAdd(&aliveMemoryStatesCount, -1) == 0; - switch (Kotlin_destroyRuntimeMode) { + switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: destroyRuntime = lastMemoryState; break; diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index e01268fa822..11cec69de0d 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -31,6 +31,12 @@ struct InitNode { InitNode* next; }; +RUNTIME_WEAK DestroyRuntimeMode Kotlin_destroyRuntimeMode = DESTROY_RUNTIME_ON_SHUTDOWN; + +DestroyRuntimeMode Kotlin_getDestroyRuntimeMode() { + return Kotlin_destroyRuntimeMode; +} + namespace { InitNode* initHeadNode = nullptr; @@ -65,7 +71,7 @@ void InitOrDeinitGlobalVariables(int initialize, MemoryState* memory) { KBoolean g_checkLeaks = KonanNeedDebugInfo; KBoolean g_checkLeakedCleaners = KonanNeedDebugInfo; -KBoolean g_forceCheckedShutdown = Kotlin_destroyRuntimeMode == DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED; +KBoolean g_forceCheckedShutdown = Kotlin_getDestroyRuntimeMode() == DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED; constexpr RuntimeState* kInvalidRuntime = nullptr; @@ -93,7 +99,7 @@ RuntimeState* initRuntime() { ::runtimeState = result; bool firstRuntime = false; - switch (Kotlin_destroyRuntimeMode) { + switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning); result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode @@ -135,7 +141,7 @@ void deinitRuntime(RuntimeState* state, bool destroyRuntime) { // This may be called after TLS is zeroed out, so ::memoryState in Memory cannot be trusted. RestoreMemory(state->memoryState); bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0; - switch (Kotlin_destroyRuntimeMode) { + switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: destroyRuntime = lastRuntime; break; @@ -194,7 +200,7 @@ void Kotlin_shutdownRuntime() { RuntimeAssert(runtime != kInvalidRuntime, "Current thread must have Kotlin runtime initialized on it"); bool needsFullShutdown = false; - switch (Kotlin_destroyRuntimeMode) { + switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: needsFullShutdown = true; break; @@ -341,7 +347,7 @@ KBoolean Konan_Platform_getForceCheckedShutdown() { } void Konan_Platform_setForceCheckedShutdown(KBoolean value) { - switch (Kotlin_destroyRuntimeMode) { + switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: // Only applicable to ON_SHUTDOWN modes. return; @@ -353,7 +359,7 @@ void Konan_Platform_setForceCheckedShutdown(KBoolean value) { } KInt Konan_getThingy() { - return Kotlin_destroyRuntimeMode; + return Kotlin_getDestroyRuntimeMode(); } } // extern "C" diff --git a/runtime/src/main/cpp/Runtime.h b/runtime/src/main/cpp/Runtime.h index 34845e7c135..f15d20b3bf0 100644 --- a/runtime/src/main/cpp/Runtime.h +++ b/runtime/src/main/cpp/Runtime.h @@ -32,7 +32,7 @@ enum DestroyRuntimeMode { DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED = 2, }; -RUNTIME_WEAK extern const DestroyRuntimeMode Kotlin_destroyRuntimeMode; +DestroyRuntimeMode Kotlin_getDestroyRuntimeMode(); void Kotlin_initRuntimeIfNeeded(); void Kotlin_deinitRuntimeIfNeeded(); From 49818bb01daf63bf27f199434b1b95a4130458cc Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Tue, 10 Nov 2020 11:24:33 +0300 Subject: [PATCH 06/15] REMOVE ME: debugging --- .../kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt index abe200aefc7..0b707ab9268 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt @@ -41,7 +41,7 @@ open class KonanCacheTask: DefaultTask() { } @Input - var cacheKind: KonanCacheKind = KonanCacheKind.STATIC + var cacheKind: KonanCacheKind = KonanCacheKind.DYNAMIC @Input /** Path to a compiler distribution that is used to build this cache. */ @@ -66,4 +66,4 @@ open class KonanCacheTask: DefaultTask() { ) KonanCompilerRunner(project, konanHome = compilerDistributionPath.get().absolutePath).run(args) } -} \ No newline at end of file +} From d1d5726bb2b065751391e960b99aaba336fef354 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Tue, 10 Nov 2020 19:32:34 +0300 Subject: [PATCH 07/15] Tweaking --- .../jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 203f55838bc..03aad8e103a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2381,6 +2381,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map Date: Tue, 10 Nov 2020 19:49:33 +0300 Subject: [PATCH 08/15] Revert "REMOVE ME: debugging" This reverts commit 860ef4ab238940aea6c1c2bf773d189ae07fcd5e. --- .../kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt index 0b707ab9268..abe200aefc7 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanCacheTask.kt @@ -41,7 +41,7 @@ open class KonanCacheTask: DefaultTask() { } @Input - var cacheKind: KonanCacheKind = KonanCacheKind.DYNAMIC + var cacheKind: KonanCacheKind = KonanCacheKind.STATIC @Input /** Path to a compiler distribution that is used to build this cache. */ @@ -66,4 +66,4 @@ open class KonanCacheTask: DefaultTask() { ) KonanCompilerRunner(project, konanHome = compilerDistributionPath.get().absolutePath).run(args) } -} +} \ No newline at end of file From d5d8a87fd87dbff07461edd5c3c5f41db262d022 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Tue, 10 Nov 2020 19:50:07 +0300 Subject: [PATCH 09/15] Revert "REMOVE ME: debugging" This reverts commit 85e77a15851777671b205428a366806a851ba3e3. --- runtime/src/main/cpp/Runtime.cpp | 4 ---- runtime/src/main/kotlin/kotlin/native/Platform.kt | 6 ------ 2 files changed, 10 deletions(-) diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 11cec69de0d..8844b1e6090 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -358,8 +358,4 @@ void Konan_Platform_setForceCheckedShutdown(KBoolean value) { g_forceCheckedShutdown = value; } -KInt Konan_getThingy() { - return Kotlin_getDestroyRuntimeMode(); -} - } // extern "C" diff --git a/runtime/src/main/kotlin/kotlin/native/Platform.kt b/runtime/src/main/kotlin/kotlin/native/Platform.kt index b69d4e3eab1..8d799af6d7f 100644 --- a/runtime/src/main/kotlin/kotlin/native/Platform.kt +++ b/runtime/src/main/kotlin/kotlin/native/Platform.kt @@ -100,14 +100,8 @@ public object Platform { public var forceCheckedShutdown: Boolean get() = Platform_getForceCheckedShutdown() set(value) = Platform_setForceCheckedShutdown(value) - - public val thingy: Int - get() = getThingy() } -@SymbolName("Konan_getThingy") -private external fun getThingy(): Int - @SymbolName("Konan_Platform_canAccessUnaligned") private external fun Platform_canAccessUnaligned(): Int From f4b261e41c1d317bc9dc76ea6b5f325cf703f143 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 11 Nov 2020 11:25:55 +0300 Subject: [PATCH 10/15] Remove ON_SHUTDOWN_CHECKED --- .../cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt | 1 - .../jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt | 2 +- .../jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt | 1 - runtime/src/legacymm/cpp/Memory.cpp | 2 -- runtime/src/main/cpp/Runtime.cpp | 6 +----- runtime/src/main/cpp/Runtime.h | 1 - 6 files changed, 2 insertions(+), 11 deletions(-) diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index a2a9644ab57..267c4777719 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -253,7 +253,6 @@ class K2Native : CLICompiler() { put(DESTROY_RUNTIME_MODE, when (arguments.destroyRuntimeMode) { "legacy" -> DestroyRuntimeMode.LEGACY "on-shutdown" -> DestroyRuntimeMode.ON_SHUTDOWN - "on-shutdown-checked" -> DestroyRuntimeMode.ON_SHUTDOWN_CHECKED else -> { configuration.report(ERROR, "Unsupported destroy runtime mode ${arguments.destroyRuntimeMode}") DestroyRuntimeMode.ON_SHUTDOWN diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index 51f65e38a94..09dd3304088 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -285,7 +285,7 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { ) var overrideKonanProperties: Array? = null - @Argument(value="-Xdestroy-runtime-mode", valueDescription = "", description = "When to destroy runtime. 'legacy', 'on-shutdown' and 'on-shutdown-checked' are currently supported. NOTE: 'legacy' mode is deprecated and will be removed.") + @Argument(value="-Xdestroy-runtime-mode", valueDescription = "", description = "When to destroy runtime. 'legacy' and 'on-shutdown' are currently supported. NOTE: 'legacy' mode is deprecated and will be removed.") var destroyRuntimeMode: String? = "on-shutdown" override fun configureAnalysisFlags(collector: MessageCollector): MutableMap, Any> = diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt index e2d31cf9a04..21ecea9242b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt @@ -8,5 +8,4 @@ package org.jetbrains.kotlin.backend.konan enum class DestroyRuntimeMode(val value: Int) { LEGACY(0), ON_SHUTDOWN(1), - ON_SHUTDOWN_CHECKED(2) } diff --git a/runtime/src/legacymm/cpp/Memory.cpp b/runtime/src/legacymm/cpp/Memory.cpp index 9e22cf75bfe..9c1cbc6287e 100644 --- a/runtime/src/legacymm/cpp/Memory.cpp +++ b/runtime/src/legacymm/cpp/Memory.cpp @@ -2010,7 +2010,6 @@ MemoryState* initMemory(bool firstRuntime) { firstRuntime = firstMemoryState; break; case DESTROY_RUNTIME_ON_SHUTDOWN: - case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: // Nothing to do. break; } @@ -2039,7 +2038,6 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) { destroyRuntime = lastMemoryState; break; case DESTROY_RUNTIME_ON_SHUTDOWN: - case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: // Nothing to do. break; } diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 8844b1e6090..1c9f28a5954 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -71,7 +71,7 @@ void InitOrDeinitGlobalVariables(int initialize, MemoryState* memory) { KBoolean g_checkLeaks = KonanNeedDebugInfo; KBoolean g_checkLeakedCleaners = KonanNeedDebugInfo; -KBoolean g_forceCheckedShutdown = Kotlin_getDestroyRuntimeMode() == DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED; +KBoolean g_forceCheckedShutdown = false; constexpr RuntimeState* kInvalidRuntime = nullptr; @@ -107,7 +107,6 @@ RuntimeState* initRuntime() { firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1; break; case DESTROY_RUNTIME_ON_SHUTDOWN: - case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: // First update `aliveRuntimesCount` and then update `globalRuntimeStatus`, for synchronization with // runtime shutdown, which does it the other way around. atomicAdd(&aliveRuntimesCount, 1); @@ -146,7 +145,6 @@ void deinitRuntime(RuntimeState* state, bool destroyRuntime) { destroyRuntime = lastRuntime; break; case DESTROY_RUNTIME_ON_SHUTDOWN: - case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: // Nothing to do. break; } @@ -205,7 +203,6 @@ void Kotlin_shutdownRuntime() { needsFullShutdown = true; break; case DESTROY_RUNTIME_ON_SHUTDOWN: - case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: needsFullShutdown = Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled(); break; } @@ -352,7 +349,6 @@ void Konan_Platform_setForceCheckedShutdown(KBoolean value) { // Only applicable to ON_SHUTDOWN modes. return; case DESTROY_RUNTIME_ON_SHUTDOWN: - case DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED: break; } g_forceCheckedShutdown = value; diff --git a/runtime/src/main/cpp/Runtime.h b/runtime/src/main/cpp/Runtime.h index f15d20b3bf0..d5779db9b10 100644 --- a/runtime/src/main/cpp/Runtime.h +++ b/runtime/src/main/cpp/Runtime.h @@ -29,7 +29,6 @@ extern "C" { enum DestroyRuntimeMode { DESTROY_RUNTIME_LEGACY = 0, DESTROY_RUNTIME_ON_SHUTDOWN = 1, - DESTROY_RUNTIME_ON_SHUTDOWN_CHECKED = 2, }; DestroyRuntimeMode Kotlin_getDestroyRuntimeMode(); From c2b48856e7637b69fdf89feeff314827693d6ce3 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 11 Nov 2020 11:34:33 +0300 Subject: [PATCH 11/15] Fix a comment --- runtime/src/main/cpp/Runtime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 1c9f28a5954..30bd592fdce 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -116,7 +116,7 @@ RuntimeState* initRuntime() { konan::abort(); } firstRuntime = lastStatus == kGlobalRuntimeUninitialized; - result->memoryState = InitMemory(firstRuntime); // The argument will be ignored for legacy DestroyRuntimeMode + result->memoryState = InitMemory(firstRuntime); result->worker = WorkerInit(true); } From cf784c6ee4ef3570d73104b8de40feb3018d7f2f Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 11 Nov 2020 12:15:52 +0300 Subject: [PATCH 12/15] Little fixes --- .../interop/migrating_main_thread/main.cpp | 4 +--- backend.native/tests/interop/objc/smoke.kt | 2 +- runtime/src/main/cpp/Runtime.cpp | 10 +++++----- .../src/main/kotlin/kotlin/native/Platform.kt | 10 ---------- .../kotlin/native/internal/Debugging.kt | 20 +++++++++++++++++++ 5 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt diff --git a/backend.native/tests/interop/migrating_main_thread/main.cpp b/backend.native/tests/interop/migrating_main_thread/main.cpp index f90335d7c2e..c722750c000 100644 --- a/backend.native/tests/interop/migrating_main_thread/main.cpp +++ b/backend.native/tests/interop/migrating_main_thread/main.cpp @@ -27,9 +27,7 @@ int main() { }); main1.join(); - std::thread main2([]() { - assert(testlib_symbols()->kotlin.root.readFromA() == kResultValue); - }); + std::thread main2([]() { assert(testlib_symbols()->kotlin.root.readFromA() == kResultValue); }); main2.join(); return 0; diff --git a/backend.native/tests/interop/objc/smoke.kt b/backend.native/tests/interop/objc/smoke.kt index 8ca0e9a67b0..b01f0680854 100644 --- a/backend.native/tests/interop/objc/smoke.kt +++ b/backend.native/tests/interop/objc/smoke.kt @@ -11,7 +11,7 @@ import kotlin.test.* fun main(args: Array) { // Test relies on full deinitialization at shutdown. - kotlin.native.Platform.forceCheckedShutdown = true + kotlin.native.internal.Debugging.forceCheckedShutdown = true autoreleasepool { run() } diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 30bd592fdce..461de5f385e 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -111,9 +111,8 @@ RuntimeState* initRuntime() { // runtime shutdown, which does it the other way around. atomicAdd(&aliveRuntimesCount, 1); auto lastStatus = compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning); - if (lastStatus == kGlobalRuntimeShutdown && Kotlin_forceCheckedShutdown()) { - konan::consoleErrorf("Kotlin runtime was shut down. Cannot create new runtimes\n"); - konan::abort(); + if (Kotlin_forceCheckedShutdown()) { + RuntimeAssert(lastStatus != kGlobalRuntimeShutdown, "Kotlin runtime was shut down. Cannot create new runtimes."); } firstRuntime = lastStatus == kGlobalRuntimeUninitialized; result->memoryState = InitMemory(firstRuntime); @@ -224,6 +223,7 @@ void Kotlin_shutdownRuntime() { auto lastStatus = compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeRunning, kGlobalRuntimeShutdown); RuntimeAssert(lastStatus == kGlobalRuntimeRunning, "Invalid runtime status for shutdown"); + // TODO: When legacy mode is gone, this `if` will become unnecessary. if (Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled()) { // First make sure workers are gone. WaitNativeWorkersTermination(); @@ -339,11 +339,11 @@ bool Kotlin_forceCheckedShutdown() { return g_forceCheckedShutdown; } -KBoolean Konan_Platform_getForceCheckedShutdown() { +KBoolean Kotlin_Debugging_getForceCheckedShutdown() { return g_forceCheckedShutdown; } -void Konan_Platform_setForceCheckedShutdown(KBoolean value) { +void Kotlin_Debugging_setForceCheckedShutdown(KBoolean value) { switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: // Only applicable to ON_SHUTDOWN modes. diff --git a/runtime/src/main/kotlin/kotlin/native/Platform.kt b/runtime/src/main/kotlin/kotlin/native/Platform.kt index 8d799af6d7f..6ca425e88fa 100644 --- a/runtime/src/main/kotlin/kotlin/native/Platform.kt +++ b/runtime/src/main/kotlin/kotlin/native/Platform.kt @@ -96,10 +96,6 @@ public object Platform { public var isCleanersLeakCheckerActive: Boolean get() = Platform_getCleanersLeakChecker() set(value) = Platform_setCleanersLeakChecker(value) - - public var forceCheckedShutdown: Boolean - get() = Platform_getForceCheckedShutdown() - set(value) = Platform_setForceCheckedShutdown(value) } @SymbolName("Konan_Platform_canAccessUnaligned") @@ -131,9 +127,3 @@ private external fun Platform_getCleanersLeakChecker(): Boolean @SymbolName("Konan_Platform_setCleanersLeakChecker") private external fun Platform_setCleanersLeakChecker(value: Boolean): Unit - -@SymbolName("Konan_Platform_getForceCheckedShutdown") -private external fun Platform_getForceCheckedShutdown(): Boolean - -@SymbolName("Konan_Platform_setForceCheckedShutdown") -private external fun Platform_setForceCheckedShutdown(value: Boolean): Unit diff --git a/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt b/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt new file mode 100644 index 00000000000..b2273209649 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt @@ -0,0 +1,20 @@ +/* + * 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. + */ +package kotlin.native.internal + +/* + * Internal utilities for debugging K/N compiler and runtime itself. + */ +public object Debugging { + public var forceCheckedShutdown: Boolean + get() = Debugging_getForceCheckedShutdown() + set(value) = Debugging_setForceCheckedShutdown(value) +} + +@SymbolName("Kotlin_Debugging_getForceCheckedShutdown") +private external fun Debugging_getForceCheckedShutdown(): Boolean + +@SymbolName("Kotlin_Debugging_setForceCheckedShutdown") +private external fun Debugging_setForceCheckedShutdown(value: Boolean): Unit From 1ea6bdc791c9814b8d89d43b7e24c1473fbf05e7 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 11 Nov 2020 14:10:45 +0300 Subject: [PATCH 13/15] More fixes --- .../kotlin/backend/konan/DestroyRuntimeMode.kt | 2 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 2 +- runtime/src/legacymm/cpp/Memory.cpp | 17 +++++++++-------- .../kotlin/kotlin/native/internal/Debugging.kt | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt index 21ecea9242b..e55b9955df1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DestroyRuntimeMode.kt @@ -4,7 +4,7 @@ */ package org.jetbrains.kotlin.backend.konan -// Must match DestroyRuntimeMode in Runtime.h +// Must match `DestroyRuntimeMode` in Runtime.h enum class DestroyRuntimeMode(val value: Int) { LEGACY(0), ON_SHUTDOWN(1), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 03aad8e103a..0c0483c2131 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2392,7 +2392,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: MapisMainThread) { + // If we are not destroying the runtime but we were the main thread, publish all changes to Kotlin globals. + // This `synchronize` should be before `aliveMemoryStatesCount` decrement to synchronize with + // `initMemory` which does this in the reverse order. + synchronize(); + } + atomicAdd(&aliveMemoryStatesCount, -1); break; } bool checkLeaks = Kotlin_memoryLeakCheckerEnabled() && destroyRuntime; @@ -2054,10 +2059,6 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) { cyclicDeinit(g_hasCyclicCollector); #endif // USE_CYCLIC_GC } - if (!destroyRuntime && memoryState->isMainThread) { - // If we are not destroying the runtime but we were the main thread, publish all changes to Kotlin globals. - synchronize(); - } // Actual GC only implemented in strict memory model at the moment. do { GC_LOG("Calling garbageCollect from DeinitMemory()\n") @@ -2077,7 +2078,7 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) { atomicAdd(&pendingDeinit, -1); #if TRACE_MEMORY - if (IsStrictMemoryModel && lastMemoryState && allocCount > 0) { + if (IsStrictMemoryModel && destroyRuntime && allocCount > 0) { MEMORY_LOG("*** Memory leaks, leaked %d containers ***\n", allocCount); dumpReachable("", memoryState->containers); } diff --git a/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt b/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt index b2273209649..638e0363df9 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/Debugging.kt @@ -5,7 +5,7 @@ package kotlin.native.internal /* - * Internal utilities for debugging K/N compiler and runtime itself. + * Internal utilities for debugging K/N compiler and runtime. */ public object Debugging { public var forceCheckedShutdown: Boolean From b1f96018e5e39c66f1a93d06c69bd5817994edb8 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Thu, 12 Nov 2020 11:14:50 +0300 Subject: [PATCH 14/15] Address review comments --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 9 ++++--- .../interop/migrating_main_thread/lib.kt | 8 +++++- .../interop/migrating_main_thread/main.cpp | 25 ++++++++++--------- runtime/src/legacymm/cpp/Memory.cpp | 17 +++---------- runtime/src/main/cpp/Runtime.cpp | 1 + 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 0c0483c2131..cf5e2106446 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -365,7 +365,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map constexpr int kInitialValue = 0; -constexpr int kNewValue = 0; - -#if defined(IS_LEGACY) -// Globals were reinitialized. -constexpr int kResultValue = kInitialValue; -#else -// Globals were kept. -constexpr int kResultValue = kNewValue; -#endif +constexpr int kNewValue = 1; +constexpr int kErrorValue = 2; int main() { std::thread main1([]() { - assert(testlib_symbols()->kotlin.root.readFromA() == kInitialValue); + assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kInitialValue); testlib_symbols()->kotlin.root.writeToA(kNewValue); - assert(testlib_symbols()->kotlin.root.readFromA() == kNewValue); + assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kNewValue); }); main1.join(); - std::thread main2([]() { assert(testlib_symbols()->kotlin.root.readFromA() == kResultValue); }); + std::thread main2([]() { +#if defined(IS_LEGACY) + // Globals were reinitialized. + assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kInitialValue); +#else + // Globals are not accessible. + assert(testlib_symbols()->kotlin.root.tryReadFromA(kErrorValue) == kErrorValue); +#endif + }); main2.join(); return 0; diff --git a/runtime/src/legacymm/cpp/Memory.cpp b/runtime/src/legacymm/cpp/Memory.cpp index cc630e2b8ef..01e3b2dbade 100644 --- a/runtime/src/legacymm/cpp/Memory.cpp +++ b/runtime/src/legacymm/cpp/Memory.cpp @@ -2019,12 +2019,6 @@ MemoryState* initMemory(bool firstRuntime) { #endif // USE_CYCLIC_GC memoryState->isMainThread = true; } - if (!firstRuntime && firstMemoryState) { - memoryState->isMainThread = true; - // This thread is now the main thread. And there was a previous main thread, because this is not the first runtime. - // Make sure this thread sees all the updates to Kotlin globals from the previous main thread. - synchronize(); - } return memoryState; } @@ -2032,18 +2026,13 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) { static int pendingDeinit = 0; atomicAdd(&pendingDeinit, 1); #if USE_GC + bool lastMemoryState = atomicAdd(&aliveMemoryStatesCount, -1) == 0; switch (Kotlin_getDestroyRuntimeMode()) { case DESTROY_RUNTIME_LEGACY: - destroyRuntime = atomicAdd(&aliveMemoryStatesCount, -1) == 0; + destroyRuntime = lastMemoryState; break; case DESTROY_RUNTIME_ON_SHUTDOWN: - if (!destroyRuntime && memoryState->isMainThread) { - // If we are not destroying the runtime but we were the main thread, publish all changes to Kotlin globals. - // This `synchronize` should be before `aliveMemoryStatesCount` decrement to synchronize with - // `initMemory` which does this in the reverse order. - synchronize(); - } - atomicAdd(&aliveMemoryStatesCount, -1); + // Nothing to do break; } bool checkLeaks = Kotlin_memoryLeakCheckerEnabled() && destroyRuntime; diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 461de5f385e..9c81ded50df 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -31,6 +31,7 @@ struct InitNode { InitNode* next; }; +// This global is overriden by the compiler. RUNTIME_WEAK DestroyRuntimeMode Kotlin_destroyRuntimeMode = DESTROY_RUNTIME_ON_SHUTDOWN; DestroyRuntimeMode Kotlin_getDestroyRuntimeMode() { From 30545f921b00624feed05cd71ce433daeca07e9b Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Thu, 12 Nov 2020 12:55:11 +0300 Subject: [PATCH 15/15] Update comments --- .../src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt | 2 +- .../backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index cf5e2106446..f2044d3c6fc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2381,7 +2381,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map