Add a separate compiler switch for runtime asserts
This commit is contained in:
committed by
Space
parent
c3515cc338
commit
48a2b23b3a
@@ -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
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -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<*>
|
||||||
|
|||||||
+1
-1
@@ -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),
|
||||||
|
|||||||
+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
|
||||||
|
|||||||
+1
@@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
@@ -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),
|
||||||
|
}
|
||||||
+16
-9
@@ -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
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user