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
@@ -5,6 +5,7 @@
#include "SameThreadMarkAndSweep.hpp"
#include "CompilerConstants.hpp"
#include "GlobalData.hpp"
#include "MarkAndSweepUtils.hpp"
#include "Memory.h"
@@ -111,7 +112,7 @@ void gc::SameThreadMarkAndSweep::ThreadData::SafePointRegular(size_t weight) noe
}
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.
threshold_ = 1000;
allocationThresholdBytes_ = 10000;
@@ -35,6 +35,7 @@
#include "KAssert.h"
#include "Atomic.h"
#include "Cleaner.h"
#include "CompilerConstants.hpp"
#if USE_CYCLIC_GC
#include "CyclicCollector.h"
#endif // USE_CYCLIC_GC
@@ -220,7 +221,7 @@ class CycleDetector : private kotlin::Pinned, public KonanAllocatorAware {
}
static bool canBeACandidate(KRef object) {
return KonanNeedDebugInfo &&
return kotlin::compiler::shouldContainDebugInfo() &&
Kotlin_memoryLeakCheckerEnabled() &&
(object->type_info()->flags_ & TF_LEAK_DETECTOR_CANDIDATE) != 0;
}
@@ -2044,11 +2045,11 @@ MemoryState* initMemory(bool firstRuntime) {
memoryState->tls.Init();
memoryState->foreignRefManager = ForeignRefManager::create();
bool firstMemoryState = atomicAdd(&aliveMemoryStatesCount, 1) == 1;
switch (Kotlin_getDestroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY:
switch (kotlin::compiler::destroyRuntimeMode()) {
case kotlin::compiler::DestroyRuntimeMode::kLegacy:
firstRuntime = firstMemoryState;
break;
case DESTROY_RUNTIME_ON_SHUTDOWN:
case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// Nothing to do.
break;
}
@@ -2066,11 +2067,11 @@ void deinitMemory(MemoryState* memoryState, bool destroyRuntime) {
atomicAdd(&pendingDeinit, 1);
#if USE_GC
bool lastMemoryState = atomicAdd(&aliveMemoryStatesCount, -1) == 0;
switch (Kotlin_getDestroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY:
switch (kotlin::compiler::destroyRuntimeMode()) {
case kotlin::compiler::DestroyRuntimeMode::kLegacy:
destroyRuntime = lastMemoryState;
break;
case DESTROY_RUNTIME_ON_SHUTDOWN:
case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// Nothing to do
break;
}
@@ -3557,7 +3558,7 @@ KBoolean Kotlin_native_internal_GC_getTuneThreshold(KRef) {
OBJ_GETTER(Kotlin_native_internal_GC_detectCycles, KRef) {
#if USE_CYCLE_DETECTOR
if (!KonanNeedDebugInfo && !Kotlin_memoryLeakCheckerEnabled()) RETURN_OBJ(nullptr);
if (!kotlin::compiler::shouldContainDebugInfo() && !Kotlin_memoryLeakCheckerEnabled()) RETURN_OBJ(nullptr);
RETURN_RESULT_OF0(detectCyclicReferences);
#else
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 "StackTrace.hpp"
using namespace kotlin;
namespace {
// TODO: Enable stacktraces for asserts when stacktrace printing is more mature.
inline constexpr bool kEnableStacktraces = false;
} // namespace
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* format, ...) {
void PrintAssert(const char* location, const char* format, std::va_list args) noexcept {
char buf[1024];
int written = -1;
@@ -28,10 +28,7 @@ RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* form
// Write the message.
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);
va_end(args);
}
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) {
kotlin::PrintStackTraceStderr();
}
konan::abort();
}
// TODO: this function is not used by runtime, but apparently there are
// 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.
RUNTIME_NORETURN void RuntimeAssertFailed(const char* location, const char* message) {
char buf[1024];
if (location != nullptr)
konan::snprintf(buf, sizeof(buf), "%s: runtime assert: %s\n", location, message);
else
konan::snprintf(buf, sizeof(buf), "runtime assert: %s\n", message);
konan::consoleErrorUtf8(buf, konan::strnlen(buf, sizeof(buf)));
konan::abort();
} // namespace
void internal::RuntimeAssertFailedLog(const char* location, const char* format, ...) {
std::va_list args;
va_start(args, format);
PrintAssert(location, format, args);
va_end(args);
}
RUNTIME_NORETURN void internal::RuntimeAssertFailedPanic(const char* location, const char* format, ...) {
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
#include "Common.h"
// To avoid cluttering optimized code with asserts, they could be turned off.
#define KONAN_ENABLE_ASSERT 1
#include "CompilerConstants.hpp"
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#if KONAN_ENABLE_ASSERT
#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 {
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) {
RuntimeAssertFailed(location, "Unimplemented");
RuntimeAssertFailedPanic(location, "Unimplemented");
}
// TODO: Support format string when `RuntimeAssertFailed` supports it.
inline RUNTIME_NORETURN void TODOImpl(const char* location, const char* message) {
RuntimeAssertFailed(location, "%s", message);
RuntimeAssertFailedPanic(location, "%s", message);
}
} // 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.
#define RuntimeAssert(condition, format, ...) \
do { \
if (KonanNeedDebugInfo && (!(condition))) { \
RuntimeAssertFailed(CURRENT_SOURCE_LOCATION, format, ##__VA_ARGS__); \
switch (::kotlin::compiler::runtimeAssertsMode()) { \
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)
#else
#define RuntimeAssert(condition, format, ...) \
do { \
} while (false)
#endif
// Use RuntimeCheck() in runtime checks that could fail due to external condition and shall lead
// 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, ...) \
do { \
if (!(condition)) { \
RuntimeAssertFailed(nullptr, format, ##__VA_ARGS__); \
::kotlin::internal::RuntimeAssertFailedPanic(nullptr, format, ##__VA_ARGS__); \
} \
} while (false)
#define TODO(...) \
do { \
::internal::TODOImpl(CURRENT_SOURCE_LOCATION, ##__VA_ARGS__); \
::kotlin::internal::TODOImpl(CURRENT_SOURCE_LOCATION, ##__VA_ARGS__); \
} while (false)
// 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, ...) \
do { \
RuntimeAssertFailed(nullptr, format, ##__VA_ARGS__); \
::kotlin::internal::RuntimeAssertFailedPanic(nullptr, format, ##__VA_ARGS__); \
} while (false)
#endif // RUNTIME_ASSERT_H
@@ -33,6 +33,7 @@
#include <chrono>
#include "Common.h"
#include "CompilerConstants.hpp"
#include "Porting.h"
#include "KAssert.h"
@@ -105,13 +106,13 @@ int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) {
if (::ReadConsoleW(stdInHandle, buffer, bufferLength, &bufferRead, NULL)) {
length = ::WideCharToMultiByte(CP_UTF8, 0, buffer, bufferRead, (char*) utf8,
maxSizeBytes - 1, NULL, NULL);
if (!length && KonanNeedDebugInfo) {
if (!length && kotlin::compiler::shouldContainDebugInfo()) {
char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("UTF-16 to UTF-8 conversion error %d: %s", errCode, msg);
}
((char*) utf8)[length] = 0;
} else if (KonanNeedDebugInfo) {
} else if (kotlin::compiler::shouldContainDebugInfo()) {
char msg[512];
auto errCode = getLastErrorMessage(msg, sizeof(msg));
consoleErrorf("Console read failure: %d %s", errCode, msg);
+14 -25
View File
@@ -17,6 +17,7 @@
#include "Alloc.h"
#include "Atomic.h"
#include "Cleaner.h"
#include "CompilerConstants.hpp"
#include "Exceptions.h"
#include "KAssert.h"
#include "Memory.h"
@@ -31,18 +32,6 @@ struct InitNode {
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 {
InitNode* initHeadNode = nullptr;
@@ -108,8 +97,8 @@ RuntimeState* initRuntime() {
bool firstRuntime = false;
// We set this guard in the `switch` below, after memory initialization.
kotlin::ThreadStateGuard stateGuard;
switch (Kotlin_getDestroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY:
switch (kotlin::compiler::destroyRuntimeMode()) {
case kotlin::compiler::DestroyRuntimeMode::kLegacy:
compareAndSwap(&globalRuntimeStatus, kGlobalRuntimeUninitialized, kGlobalRuntimeRunning);
result->memoryState = InitMemory(false); // The argument will be ignored for legacy DestroyRuntimeMode
// Switch thread state because worker and globals inits require the runnable state.
@@ -122,7 +111,7 @@ RuntimeState* initRuntime() {
konan::abort();
}
break;
case DESTROY_RUNTIME_ON_SHUTDOWN:
case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// First update `aliveRuntimesCount` and then update `globalRuntimeStatus`, for synchronization with
// runtime shutdown, which does it the other way around.
atomicAdd(&aliveRuntimesCount, 1);
@@ -168,11 +157,11 @@ void deinitRuntime(RuntimeState* state, bool destroyRuntime) {
::runtimeState = state;
RestoreMemory(state->memoryState);
bool lastRuntime = atomicAdd(&aliveRuntimesCount, -1) == 0;
switch (Kotlin_getDestroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY:
switch (kotlin::compiler::destroyRuntimeMode()) {
case kotlin::compiler::DestroyRuntimeMode::kLegacy:
destroyRuntime = lastRuntime;
break;
case DESTROY_RUNTIME_ON_SHUTDOWN:
case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
// Nothing to do.
break;
}
@@ -234,11 +223,11 @@ void Kotlin_shutdownRuntime() {
RuntimeAssert(runtime != kInvalidRuntime, "Current thread must have Kotlin runtime initialized on it");
bool needsFullShutdown = false;
switch (Kotlin_getDestroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY:
switch (kotlin::compiler::destroyRuntimeMode()) {
case kotlin::compiler::DestroyRuntimeMode::kLegacy:
needsFullShutdown = true;
break;
case DESTROY_RUNTIME_ON_SHUTDOWN:
case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
needsFullShutdown = Kotlin_forceCheckedShutdown() || Kotlin_memoryLeakCheckerEnabled() || Kotlin_cleanersLeakCheckerEnabled();
break;
}
@@ -349,7 +338,7 @@ KInt Konan_Platform_getMemoryModel() {
}
KBoolean Konan_Platform_isDebugBinary() {
return KonanNeedDebugInfo ? true : false;
return kotlin::compiler::shouldContainDebugInfo();
}
bool Kotlin_memoryLeakCheckerEnabled() {
@@ -385,11 +374,11 @@ KBoolean Kotlin_Debugging_getForceCheckedShutdown() {
}
void Kotlin_Debugging_setForceCheckedShutdown(KBoolean value) {
switch (Kotlin_getDestroyRuntimeMode()) {
case DESTROY_RUNTIME_LEGACY:
switch (kotlin::compiler::destroyRuntimeMode()) {
case kotlin::compiler::DestroyRuntimeMode::kLegacy:
// Only applicable to ON_SHUTDOWN modes.
return;
case DESTROY_RUNTIME_ON_SHUTDOWN:
case kotlin::compiler::DestroyRuntimeMode::kOnShutdown:
break;
}
g_forceCheckedShutdown = value;
@@ -25,15 +25,6 @@ struct InitNode;
extern "C" {
#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.
RUNTIME_NOTHROW void Kotlin_initRuntimeIfNeeded();
void Kotlin_deinitRuntimeIfNeeded();
@@ -56,8 +56,8 @@ testing::StrictMock<testing::MockFunction<void(KInt, bool)>>* shutdownCleanerWor
extern "C" {
// Set to 1 to enable runtime assertions.
extern const int KonanNeedDebugInfo = 1;
extern const int32_t 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* theArrayTypeInfo = theArrayTypeInfoHolder.typeInfo();