Add a separate compiler switch for runtime asserts

This commit is contained in:
Alexander Shabalin
2021-07-28 07:43:08 +00:00
committed by Space
parent c3515cc338
commit 48a2b23b3a
18 changed files with 199 additions and 104 deletions
@@ -321,6 +321,15 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
true true
} }
}) })
put(RUNTIME_ASSERTS_MODE, when (arguments.runtimeAssertsMode) {
"ignore" -> RuntimeAssertsMode.IGNORE
"log" -> RuntimeAssertsMode.LOG
"panic" -> RuntimeAssertsMode.PANIC
else -> {
configuration.report(ERROR, "Unsupported runtime asserts mode ${arguments.runtimeAssertsMode}")
RuntimeAssertsMode.IGNORE
}
})
} }
} }
} }
@@ -321,6 +321,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
) )
var checkLldCompatibility: String? = null var checkLldCompatibility: String? = null
@Argument(value="-Xruntime-asserts-mode", valueDescription = "<mode>", description = "Enable asserts in runtime. Possible values: 'ignore', 'log', 'panic'")
var runtimeAssertsMode: String? = "ignore"
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> = override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector, languageVersion).also { super.configureAnalysisFlags(collector, languageVersion).also {
val useExperimental = it[AnalysisFlags.useExperimental] as List<*> val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
@@ -4,7 +4,7 @@
*/ */
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
// Must match `DestroyRuntimeMode` in Runtime.h // Must match `DestroyRuntimeMode` in CompilerConstants.hpp
enum class DestroyRuntimeMode(val value: Int) { enum class DestroyRuntimeMode(val value: Int) {
LEGACY(0), LEGACY(0),
ON_SHUTDOWN(1), ON_SHUTDOWN(1),
@@ -49,6 +49,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)!! val destroyRuntimeMode: DestroyRuntimeMode get() = configuration.get(KonanConfigKeys.DESTROY_RUNTIME_MODE)!!
val gc: GC get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR)!! val gc: GC get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR)!!
val gcAggressive: Boolean get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR_AGRESSIVE)!! val gcAggressive: Boolean get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR_AGRESSIVE)!!
val runtimeAssertsMode: RuntimeAssertsMode get() = configuration.get(KonanConfigKeys.RUNTIME_ASSERTS_MODE)!!
val needVerifyIr: Boolean val needVerifyIr: Boolean
get() = configuration.get(KonanConfigKeys.VERIFY_IR) == true get() = configuration.get(KonanConfigKeys.VERIFY_IR) == true
@@ -159,6 +159,7 @@ class KonanConfigKeys {
val GARBAGE_COLLECTOR: CompilerConfigurationKey<GC> = CompilerConfigurationKey.create("gc") val GARBAGE_COLLECTOR: CompilerConfigurationKey<GC> = CompilerConfigurationKey.create("gc")
val GARBAGE_COLLECTOR_AGRESSIVE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("turn on agressive GC mode") val GARBAGE_COLLECTOR_AGRESSIVE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("turn on agressive GC mode")
val CHECK_LLD_COMPATIBILITY: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("check compatibility with LLD") val CHECK_LLD_COMPATIBILITY: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("check compatibility with LLD")
val RUNTIME_ASSERTS_MODE: CompilerConfigurationKey<RuntimeAssertsMode> = CompilerConfigurationKey.create("enable runtime asserts")
} }
} }
@@ -0,0 +1,12 @@
/*
* 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.
*/
package org.jetbrains.kotlin.backend.konan
// Must match `RuntimeAssertsMode` in CompilerConstants.hpp
enum class RuntimeAssertsMode(val value: Int) {
IGNORE(0),
LOG(1),
PANIC(2),
}
@@ -358,7 +358,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
codegen.objCDataGenerator?.finishModule() codegen.objCDataGenerator?.finishModule()
context.coverage.writeRegionInfo() context.coverage.writeRegionInfo()
appendDebugSelector() setRuntimeConstGlobals()
overrideRuntimeGlobals() overrideRuntimeGlobals()
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals) appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals) appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
@@ -2417,16 +2417,23 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata") LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata")
} }
// TODO: Consider migrating `KonanNeedDebugInfo` to the `overrideRuntimeGlobal` mechanism from below. // Globals set this way will be const, but can only be built into runtime-containing module. Which
private fun appendDebugSelector() { // means they are set at stdlib-cache compilation time.
if (!context.producedLlvmModuleContainsStdlib) return private fun setRuntimeConstGlobal(name: String, value: ConstValue) {
val llvmDebugSelector = val global = context.llvm.staticData.placeGlobal(name, value)
context.llvm.staticData.placeGlobal("KonanNeedDebugInfo", global.setConstant(true)
Int32(if (context.shouldContainDebugInfo()) 1 else 0)) global.setLinkage(LLVMLinkage.LLVMExternalLinkage)
llvmDebugSelector.setConstant(true)
llvmDebugSelector.setLinkage(LLVMLinkage.LLVMExternalLinkage)
} }
private fun setRuntimeConstGlobals() {
if (!context.producedLlvmModuleContainsStdlib)
return
setRuntimeConstGlobal("KonanNeedDebugInfo", Int32(if (context.shouldContainDebugInfo()) 1 else 0))
setRuntimeConstGlobal("Kotlin_runtimeAssertsMode", Int32(context.config.runtimeAssertsMode.value))
}
// Globals set this way cannot be const, but are overridable when producing final executable.
private fun overrideRuntimeGlobal(name: String, value: ConstValue) { private fun overrideRuntimeGlobal(name: String, value: ConstValue) {
// TODO: A similar mechanism is used in `ObjCExportCodeGenerator`. Consider merging them. // TODO: A similar mechanism is used in `ObjCExportCodeGenerator`. Consider merging them.
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) { if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
@@ -117,6 +117,17 @@ if (ext.isExperimentalMM) {
} }
} }
// TODO: It also makes sense to test -g without asserts, and also to test -opt with asserts.
if (project.globalTestArgs.contains("-g")) {
tasks.withType(KonanCompileNativeBinary.class).configureEach {
extraOpts "-Xruntime-asserts-mode=panic"
}
tasks.withType(RunExternalTestGroup.class).configureEach {
flags = (flags ?: []) + "-Xruntime-asserts-mode=panic"
}
}
allprojects { allprojects {
// Root directories for test output (logs, compiled files, statistics etc). Only single path must be in each set. // Root directories for test output (logs, compiled files, statistics etc). Only single path must be in each set.
// backend.native/tests // backend.native/tests
@@ -5,6 +5,7 @@
#include "SameThreadMarkAndSweep.hpp" #include "SameThreadMarkAndSweep.hpp"
#include "CompilerConstants.hpp"
#include "GlobalData.hpp" #include "GlobalData.hpp"
#include "MarkAndSweepUtils.hpp" #include "MarkAndSweepUtils.hpp"
#include "Memory.h" #include "Memory.h"
@@ -111,7 +112,7 @@ void gc::SameThreadMarkAndSweep::ThreadData::SafePointRegular(size_t weight) noe
} }
gc::SameThreadMarkAndSweep::SameThreadMarkAndSweep() noexcept { gc::SameThreadMarkAndSweep::SameThreadMarkAndSweep() noexcept {
if (Kotlin_getGcAggressive()) { if (compiler::gcAggressive()) {
// TODO: Make it even more aggressive and run on a subset of backend.native tests. // TODO: Make it even more aggressive and run on a subset of backend.native tests.
threshold_ = 1000; threshold_ = 1000;
allocationThresholdBytes_ = 10000; allocationThresholdBytes_ = 10000;
@@ -35,6 +35,7 @@
#include "KAssert.h" #include "KAssert.h"
#include "Atomic.h" #include "Atomic.h"
#include "Cleaner.h" #include "Cleaner.h"
#include "CompilerConstants.hpp"
#if USE_CYCLIC_GC #if USE_CYCLIC_GC
#include "CyclicCollector.h" #include "CyclicCollector.h"
#endif // USE_CYCLIC_GC #endif // USE_CYCLIC_GC
@@ -220,7 +221,7 @@ class CycleDetector : private kotlin::Pinned, public KonanAllocatorAware {
} }
static bool canBeACandidate(KRef object) { static bool canBeACandidate(KRef object) {
return KonanNeedDebugInfo && return kotlin::compiler::shouldContainDebugInfo() &&
Kotlin_memoryLeakCheckerEnabled() && Kotlin_memoryLeakCheckerEnabled() &&
(object->type_info()->flags_ & TF_LEAK_DETECTOR_CANDIDATE) != 0; (object->type_info()->flags_ & TF_LEAK_DETECTOR_CANDIDATE) != 0;
} }
@@ -2044,11 +2045,11 @@ MemoryState* initMemory(bool firstRuntime) {
memoryState->tls.Init(); memoryState->tls.Init();
memoryState->foreignRefManager = ForeignRefManager::create(); memoryState->foreignRefManager = ForeignRefManager::create();
bool firstMemoryState = atomicAdd(&aliveMemoryStatesCount, 1) == 1; bool firstMemoryState = atomicAdd(&aliveMemoryStatesCount, 1) == 1;
switch (Kotlin_getDestroyRuntimeMode()) { switch (kotlin::compiler::destroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY: case kotlin::compiler::DestroyRuntimeMode::kLegacy:
firstRuntime = firstMemoryState; firstRuntime = firstMemoryState;
break; break;
case DESTROY_RUNTIME_ON_SHUTDOWN: case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// Nothing to do. // Nothing to do.
break; break;
} }
@@ -2066,11 +2067,11 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) {
atomicAdd(&pendingDeinit, 1); atomicAdd(&pendingDeinit, 1);
#if USE_GC #if USE_GC
bool lastMemoryState = atomicAdd(&aliveMemoryStatesCount, -1) == 0; bool lastMemoryState = atomicAdd(&aliveMemoryStatesCount, -1) == 0;
switch (Kotlin_getDestroyRuntimeMode()) { switch (kotlin::compiler::destroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY: case kotlin::compiler::DestroyRuntimeMode::kLegacy:
destroyRuntime = lastMemoryState; destroyRuntime = lastMemoryState;
break; break;
case DESTROY_RUNTIME_ON_SHUTDOWN: case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// Nothing to do // Nothing to do
break; break;
} }
@@ -3557,7 +3558,7 @@ KBoolean Kotlin_native_internal_GC_getTuneThreshold(KRef) {
OBJ_GETTER(Kotlin_native_internal_GC_detectCycles, KRef) { OBJ_GETTER(Kotlin_native_internal_GC_detectCycles, KRef) {
#if USE_CYCLE_DETECTOR #if USE_CYCLE_DETECTOR
if (!KonanNeedDebugInfo && !Kotlin_memoryLeakCheckerEnabled()) RETURN_OBJ(nullptr); if (!kotlin::compiler::shouldContainDebugInfo() && !Kotlin_memoryLeakCheckerEnabled()) RETURN_OBJ(nullptr);
RETURN_RESULT_OF0(detectCyclicReferences); RETURN_RESULT_OF0(detectCyclicReferences);
#else #else
RETURN_OBJ(nullptr); RETURN_OBJ(nullptr);
@@ -0,0 +1,22 @@
/*
* 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.
*/
#include "CompilerConstants.hpp"
#include "Common.h"
using namespace kotlin;
// These are defined by overrideRuntimeGlobals in IrToBitcode.kt
RUNTIME_WEAK int32_t Kotlin_destroyRuntimeMode = 1;
RUNTIME_WEAK int32_t Kotiln_gcAggressive = 0;
ALWAYS_INLINE compiler::DestroyRuntimeMode compiler::destroyRuntimeMode() noexcept {
return static_cast<compiler::DestroyRuntimeMode>(Kotlin_destroyRuntimeMode);
}
ALWAYS_INLINE bool compiler::gcAggressive() noexcept {
return Kotiln_gcAggressive != 0;
}
@@ -0,0 +1,50 @@
/*
* 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.
*/
#ifndef RUNTIME_COMPILER_CONSTANTS_H
#define RUNTIME_COMPILER_CONSTANTS_H
#include <cstdint>
#include "Common.h"
// Prefer to use getter functions below. These constants are exposed to simplify the job of the inliner.
// These are defined by setRuntimeConstGlobals in IrToBitcode.kt
extern "C" const int32_t KonanNeedDebugInfo;
extern "C" const int32_t Kotlin_runtimeAssertsMode;
namespace kotlin {
namespace compiler {
// Must match DestroyRuntimeMode in DestroyRuntimeMode.kt
enum class DestroyRuntimeMode : int32_t {
kLegacy = 0,
kOnShutdown = 1,
};
// Must match RuntimeAssertsMode in RuntimeAssertsMode.kt
enum class RuntimeAssertsMode : int32_t {
kIgnore = 0,
kLog = 1,
kPanic = 2,
};
DestroyRuntimeMode destroyRuntimeMode() noexcept;
bool gcAggressive() noexcept;
ALWAYS_INLINE inline bool shouldContainDebugInfo() noexcept {
return KonanNeedDebugInfo != 0;
}
ALWAYS_INLINE inline RuntimeAssertsMode runtimeAssertsMode() noexcept {
return static_cast<RuntimeAssertsMode>(Kotlin_runtimeAssertsMode);
}
} // namespace compiler
} // namespace kotlin
#endif // RUNTIME_COMPILER_CONSTANTS_H
+18 -18
View File
@@ -8,14 +8,14 @@
#include "Porting.h" #include "Porting.h"
#include "StackTrace.hpp" #include "StackTrace.hpp"
using namespace kotlin;
namespace { namespace {
// TODO: Enable stacktraces for asserts when stacktrace printing is more mature. // TODO: Enable stacktraces for asserts when stacktrace printing is more mature.
inline constexpr bool kEnableStacktraces = false; inline constexpr bool kEnableStacktraces = false;
} // namespace void PrintAssert(const char* location, const char* format, std::va_list args) noexcept {
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* format, ...) {
char buf[1024]; char buf[1024];
int written = -1; int written = -1;
@@ -28,10 +28,7 @@ RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* form
// Write the message. // Write the message.
if (written >= 0 && static_cast<size_t>(written) < sizeof(buf)) { if (written >= 0 && static_cast<size_t>(written) < sizeof(buf)) {
std::va_list args;
va_start(args, format);
konan::vsnprintf(buf + written, sizeof(buf) - written, format, args); konan::vsnprintf(buf + written, sizeof(buf) - written, format, args);
va_end(args);
} }
konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf))); konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf)));
@@ -39,18 +36,21 @@ RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* form
if constexpr (kEnableStacktraces) { if constexpr (kEnableStacktraces) {
kotlin::PrintStackTraceStderr(); kotlin::PrintStackTraceStderr();
} }
konan::abort();
} }
// TODO: this function is not used by runtime, but apparently there are } // namespace
// third-party libraries that use it (despite the fact it is not a public API).
// Keeping the function here for now for backward compatibility, to be removed later. void internal::RuntimeAssertFailedLog(const char* location, const char* format, ...) {
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* message) { std::va_list args;
char buf[1024]; va_start(args, format);
if (location != nullptr) PrintAssert(location, format, args);
konan::snprintf(buf, sizeof(buf), "%s: runtime assert: %s\n", location, message); va_end(args);
else }
konan::snprintf(buf, sizeof(buf), "runtime assert: %s\n", message);
konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf))); RUNTIME_NORETURN void internal::RuntimeAssertFailedPanic(const char* location, const char* format, ...) {
konan::abort(); std::va_list args;
va_start(args, format);
PrintAssert(location, format, args);
va_end(args);
konan::abort();
} }
+25 -29
View File
@@ -18,73 +18,69 @@
#define RUNTIME_ASSERT_H #define RUNTIME_ASSERT_H
#include "Common.h" #include "Common.h"
#include "CompilerConstants.hpp"
// To avoid cluttering optimized code with asserts, they could be turned off.
#define KONAN_ENABLE_ASSERT 1
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x) #define TOSTRING(x) STRINGIFY(x)
#if KONAN_ENABLE_ASSERT
#define CURRENT_SOURCE_LOCATION __FILE__ ":" TOSTRING(__LINE__) #define CURRENT_SOURCE_LOCATION __FILE__ ":" TOSTRING(__LINE__)
#else
// Do not generate location strings, when asserts are disabled to reduce code size.
#define CURRENT_SOURCE_LOCATION nullptr
#endif
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* format, ...) __attribute__((format(printf, 2, 3)));
namespace kotlin {
namespace internal { namespace internal {
void RuntimeAssertFailedLog(const char* location, const char* format, ...) __attribute__((format(printf, 2, 3)));
RUNTIME_NORETURN void RuntimeAssertFailedPanic(const char* location, const char* format, ...) __attribute__((format(printf, 2, 3)));
inline RUNTIME_NORETURN void TODOImpl(const char* location) { inline RUNTIME_NORETURN void TODOImpl(const char* location) {
RuntimeAssertFailed(location, "Unimplemented"); RuntimeAssertFailedPanic(location, "Unimplemented");
} }
// TODO: Support format string when `RuntimeAssertFailed` supports it. // TODO: Support format string when `RuntimeAssertFailed` supports it.
inline RUNTIME_NORETURN void TODOImpl(const char* location, const char* message) { inline RUNTIME_NORETURN void TODOImpl(const char* location, const char* message) {
RuntimeAssertFailed(location, "%s", message); RuntimeAssertFailedPanic(location, "%s", message);
} }
} // namespace internal } // namespace internal
} // namespace kotlin
// During codegeneration we set this constant to 1 or 0 to allow bitcode optimizer
// to get rid of code behind condition.
extern "C" const int KonanNeedDebugInfo;
#if KONAN_ENABLE_ASSERT
// Use RuntimeAssert() in internal state checks, which could be ignored in production. // Use RuntimeAssert() in internal state checks, which could be ignored in production.
#define RuntimeAssert(condition, format, ...) \ #define RuntimeAssert(condition, format, ...) \
do { \ do { \
if (KonanNeedDebugInfo && (!(condition))) { \ switch (::kotlin::compiler::runtimeAssertsMode()) { \
RuntimeAssertFailed(CURRENT_SOURCE_LOCATION, format, ##__VA_ARGS__); \ case ::kotlin::compiler::RuntimeAssertsMode::kIgnore: break; \
case ::kotlin::compiler::RuntimeAssertsMode::kLog: \
if (!(condition)) { \
::kotlin::internal::RuntimeAssertFailedLog(CURRENT_SOURCE_LOCATION, format, ##__VA_ARGS__); \
} \
break; \
case ::kotlin::compiler::RuntimeAssertsMode::kPanic: \
if (!(condition)) { \
::kotlin::internal::RuntimeAssertFailedPanic(CURRENT_SOURCE_LOCATION, format, ##__VA_ARGS__); \
} \
break; \
} \ } \
} while (false) } while (false)
#else
#define RuntimeAssert(condition, format, ...) \
do { \
} while (false)
#endif
// Use RuntimeCheck() in runtime checks that could fail due to external condition and shall lead // Use RuntimeCheck() in runtime checks that could fail due to external condition and shall lead
// to program termination. Never compiled out. // to program termination. Never compiled out.
// TODO: Consider using `CURRENT_SOURCE_LOCATION` when `KonanNeedDebugInfo` is `true`. // TODO: Consider using `CURRENT_SOURCE_LOCATION` when `kotlin::compiler::runtimeAssertsMode()` is not `kIgnore`.
#define RuntimeCheck(condition, format, ...) \ #define RuntimeCheck(condition, format, ...) \
do { \ do { \
if (!(condition)) { \ if (!(condition)) { \
RuntimeAssertFailed(nullptr, format, ##__VA_ARGS__); \ ::kotlin::internal::RuntimeAssertFailedPanic(nullptr, format, ##__VA_ARGS__); \
} \ } \
} while (false) } while (false)
#define TODO(...) \ #define TODO(...) \
do { \ do { \
::internal::TODOImpl(CURRENT_SOURCE_LOCATION, ##__VA_ARGS__); \ ::kotlin::internal::TODOImpl(CURRENT_SOURCE_LOCATION, ##__VA_ARGS__); \
} while (false) } while (false)
// Use RuntimeFail() to unconditionally fail, signifying compiler/runtime bug. // Use RuntimeFail() to unconditionally fail, signifying compiler/runtime bug.
// TODO: Consider using `CURRENT_SOURCE_LOCATION` when `KonanNeedDebugInfo` is `true`. // TODO: Consider using `CURRENT_SOURCE_LOCATION` when `kotlin::compiler::runtimeAssertsMode()` is not `kIgnore`.
#define RuntimeFail(format, ...) \ #define RuntimeFail(format, ...) \
do { \ do { \
RuntimeAssertFailed(nullptr, format, ##__VA_ARGS__); \ ::kotlin::internal::RuntimeAssertFailedPanic(nullptr, format, ##__VA_ARGS__); \
} while (false) } while (false)
#endif // RUNTIME_ASSERT_H #endif // RUNTIME_ASSERT_H
@@ -33,6 +33,7 @@
#include <chrono> #include <chrono>
#include "Common.h" #include "Common.h"
#include "CompilerConstants.hpp"
#include "Porting.h" #include "Porting.h"
#include "KAssert.h" #include "KAssert.h"
@@ -105,13 +106,13 @@ int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) {
if (::ReadConsoleW(stdInHandle, buffer, bufferLength, &bufferRead, NULL)) { if (::ReadConsoleW(stdInHandle, buffer, bufferLength, &bufferRead, NULL)) {
length = ::WideCharToMultiByte(CP_UTF8, 0, buffer, bufferRead, (char*) utf8, length = ::WideCharToMultiByte(CP_UTF8, 0, buffer, bufferRead, (char*) utf8,
maxSizeBytes - 1, NULL, NULL); maxSizeBytes - 1, NULL, NULL);
if (!length && KonanNeedDebugInfo) { if (!length && kotlin::compiler::shouldContainDebugInfo()) {
char msg[512]; char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg)); auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("UTF-16 to UTF-8 conversion error %d: %s", errCode, msg); consoleErrorf("UTF-16 to UTF-8 conversion error %d: %s", errCode, msg);
} }
((char*) utf8)[length] = 0; ((char*) utf8)[length] = 0;
} else if (KonanNeedDebugInfo) { } else if (kotlin::compiler::shouldContainDebugInfo()) {
char msg[512]; char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg)); auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("Console read failure: %d %s", errCode, msg); consoleErrorf("Console read failure: %d %s", errCode, msg);
+14 -25
View File
@@ -17,6 +17,7 @@
#include "Alloc.h" #include "Alloc.h"
#include "Atomic.h" #include "Atomic.h"
#include "Cleaner.h" #include "Cleaner.h"
#include "CompilerConstants.hpp"
#include "Exceptions.h" #include "Exceptions.h"
#include "KAssert.h" #include "KAssert.h"
#include "Memory.h" #include "Memory.h"
@@ -31,18 +32,6 @@ struct InitNode {
InitNode* next; InitNode* next;
}; };
// These globals are overriden by the compiler.
RUNTIME_WEAK DestroyRuntimeMode Kotlin_destroyRuntimeMode = DESTROY_RUNTIME_ON_SHUTDOWN;
RUNTIME_WEAK KInt Kotlin_gcAggressive = 0;
DestroyRuntimeMode Kotlin_getDestroyRuntimeMode() {
return Kotlin_destroyRuntimeMode;
}
bool Kotlin_getGcAggressive() {
return Kotlin_gcAggressive != 0;
}
namespace { namespace {
InitNode* initHeadNode = nullptr; InitNode* initHeadNode = nullptr;
@@ -108,8 +97,8 @@ RuntimeState* initRuntime() {
bool firstRuntime = false; bool firstRuntime = false;
// We set this guard in the `switch` below, after memory initialization. // We set this guard in the `switch` below, after memory initialization.
kotlin::ThreadStateGuard stateGuard; kotlin::ThreadStateGuard stateGuard;
switch (Kotlin_getDestroyRuntimeMode()) { switch (kotlin::compiler::destroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY: case kotlin::compiler::DestroyRuntimeMode::kLegacy:
compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning); compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning);
result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode
// Switch thread state because worker and globals inits require the runnable state. // Switch thread state because worker and globals inits require the runnable state.
@@ -122,7 +111,7 @@ RuntimeState* initRuntime() {
konan::abort(); konan::abort();
} }
break; break;
case DESTROY_RUNTIME_ON_SHUTDOWN: case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// First update `aliveRuntimesCount` and then update `globalRuntimeStatus`, for synchronization with // First update `aliveRuntimesCount` and then update `globalRuntimeStatus`, for synchronization with
// runtime shutdown, which does it the other way around. // runtime shutdown, which does it the other way around.
atomicAdd(&aliveRuntimesCount, 1); atomicAdd(&aliveRuntimesCount, 1);
@@ -168,11 +157,11 @@ void deinitRuntime(RuntimeState* state, bool destroyRuntime) {
::runtimeState = state; ::runtimeState = state;
RestoreMemory(state->memoryState); RestoreMemory(state->memoryState);
bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0; bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0;
switch (Kotlin_getDestroyRuntimeMode()) { switch (kotlin::compiler::destroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY: case kotlin::compiler::DestroyRuntimeMode::kLegacy:
destroyRuntime = lastRuntime; destroyRuntime = lastRuntime;
break; break;
case DESTROY_RUNTIME_ON_SHUTDOWN: case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// Nothing to do. // Nothing to do.
break; break;
} }
@@ -234,11 +223,11 @@ void Kotlin_shutdownRuntime() {
RuntimeAssert(runtime != kInvalidRuntime, "Current thread must have Kotlin runtime initialized on it"); RuntimeAssert(runtime != kInvalidRuntime, "Current thread must have Kotlin runtime initialized on it");
bool needsFullShutdown = false; bool needsFullShutdown = false;
switch (Kotlin_getDestroyRuntimeMode()) { switch (kotlin::compiler::destroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY: case kotlin::compiler::DestroyRuntimeMode::kLegacy:
needsFullShutdown = true; needsFullShutdown = true;
break; break;
case DESTROY_RUNTIME_ON_SHUTDOWN: case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
needsFullShutdown = Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled(); needsFullShutdown = Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled();
break; break;
} }
@@ -349,7 +338,7 @@ KInt Konan_Platform_getMemoryModel() {
} }
KBoolean Konan_Platform_isDebugBinary() { KBoolean Konan_Platform_isDebugBinary() {
return KonanNeedDebugInfo ? true : false; return kotlin::compiler::shouldContainDebugInfo();
} }
bool Kotlin_memoryLeakCheckerEnabled() { bool Kotlin_memoryLeakCheckerEnabled() {
@@ -385,11 +374,11 @@ KBoolean Kotlin_Debugging_getForceCheckedShutdown() {
} }
void Kotlin_Debugging_setForceCheckedShutdown(KBoolean value) { void Kotlin_Debugging_setForceCheckedShutdown(KBoolean value) {
switch (Kotlin_getDestroyRuntimeMode()) { switch (kotlin::compiler::destroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY: case kotlin::compiler::DestroyRuntimeMode::kLegacy:
// Only applicable to ON_SHUTDOWN modes. // Only applicable to ON_SHUTDOWN modes.
return; return;
case DESTROY_RUNTIME_ON_SHUTDOWN: case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
break; break;
} }
g_forceCheckedShutdown = value; g_forceCheckedShutdown = value;
@@ -25,15 +25,6 @@ struct InitNode;
extern "C" { extern "C" {
#endif #endif
// Must match DestroyRuntimeMode in DestroyRuntimeMode.kt
enum DestroyRuntimeMode {
DESTROY_RUNTIME_LEGACY = 0,
DESTROY_RUNTIME_ON_SHUTDOWN = 1,
};
DestroyRuntimeMode Kotlin_getDestroyRuntimeMode();
bool Kotlin_getGcAggressive();
// For experimental MM, if runtime gets initialized, it will be in the native state after this. // For experimental MM, if runtime gets initialized, it will be in the native state after this.
RUNTIME_NOTHROW void Kotlin_initRuntimeIfNeeded(); RUNTIME_NOTHROW void Kotlin_initRuntimeIfNeeded();
void Kotlin_deinitRuntimeIfNeeded(); void Kotlin_deinitRuntimeIfNeeded();
@@ -56,8 +56,8 @@ testing::StrictMock<testing::MockFunction<void(KInt, bool)>>* shutdownCleanerWor
extern "C" { extern "C" {
// Set to 1 to enable runtime assertions. extern const int32_t KonanNeedDebugInfo = 1;
extern const int KonanNeedDebugInfo = 1; extern const int32_t Kotlin_runtimeAssertsMode = static_cast<int32_t>(kotlin::compiler::RuntimeAssertsMode::kPanic);
extern const TypeInfo* theAnyTypeInfo = theAnyTypeInfoHolder.typeInfo(); extern const TypeInfo* theAnyTypeInfo = theAnyTypeInfoHolder.typeInfo();
extern const TypeInfo* theArrayTypeInfo = theArrayTypeInfoHolder.typeInfo(); extern const TypeInfo* theArrayTypeInfo = theArrayTypeInfoHolder.typeInfo();