runtime: add trivial stack traces to exceptions
This commit is contained in:
committed by
SvyatoslavScherbina
parent
b7b99d5684
commit
f4014b0f29
@@ -90,7 +90,8 @@ abstract class KonanTest extends DefaultTask {
|
||||
println "${bcFile.absolutePath} -> ${outputFile.absolutePath}"
|
||||
println "tool: ${llvmLlc}"
|
||||
project.exec {
|
||||
commandLine "${llvmLlc}", "-o", "${outputFile.absolutePath}" , "${bcFile}"
|
||||
commandLine "${llvmLlc}", "-o", "${outputFile.absolutePath}" , "${bcFile}",
|
||||
'-disable-fp-elim' // currently required for stack traces
|
||||
}
|
||||
return outputFile
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ private fun Konan_start(args: Array<String>) {
|
||||
main(args)
|
||||
|
||||
} catch (e: Throwable) {
|
||||
// TODO: Remove .toString() when println is more capable,
|
||||
// and may be add some more info.
|
||||
// TODO: may be add some more info.
|
||||
print("Uncaught exception from Kotlin's main: ")
|
||||
println(e.toString())
|
||||
e.printStackTrace()
|
||||
// TODO: should exit with non-zero code.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ KRef Kotlin_Array_get(const ArrayHeader* obj, KInt index) {
|
||||
return *ArrayAddressOfElementAt(obj, index);
|
||||
}
|
||||
|
||||
void Kotlin_Array_set(ArrayHeader* obj, KInt index, KRef value) {
|
||||
void Kotlin_Array_set(ArrayHeader* obj, KInt index, KConstRef value) {
|
||||
if (static_cast<uint32_t>(index) >= obj->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <execinfo.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Assert.h"
|
||||
#include "Exceptions.h"
|
||||
#include "Natives.h"
|
||||
#include "Types.h"
|
||||
|
||||
class KotlinException {
|
||||
@@ -16,10 +21,54 @@ class KotlinException {
|
||||
};
|
||||
};
|
||||
|
||||
// TODO: it seems to be very common case; does C++ std library provide something like this?
|
||||
class AutoFree {
|
||||
private:
|
||||
void* mem_;
|
||||
|
||||
public:
|
||||
AutoFree(void* mem): mem_(mem) {}
|
||||
|
||||
~AutoFree() {
|
||||
free(mem_);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: this method ignores the encoding
|
||||
KString CreateKotlinStringFromCString(const char* str) {
|
||||
int32_t length = strlen(str);
|
||||
ArrayHeader* result = ArrayContainer(theStringTypeInfo, length).GetPlace();
|
||||
memcpy(
|
||||
ByteArrayAddressOfElementAt(result, 0),
|
||||
str, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// TODO: this implementation is just a hack, e.g. the result is inexact;
|
||||
// however it is better to have an inexact stacktrace than not to have any.
|
||||
KArrayRef GetCurrentStackTrace() {
|
||||
const int maxSize = 32;
|
||||
void* buffer[maxSize];
|
||||
|
||||
int size = backtrace(buffer, maxSize);
|
||||
char** symbols = backtrace_symbols(buffer, size);
|
||||
RuntimeAssert(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
|
||||
|
||||
AutoFree autoFree(symbols);
|
||||
KArrayRef result = AllocArrayInstance(theArrayTypeInfo, SCOPE_GLOBAL, size);
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
KString symbol = CreateKotlinStringFromCString(symbols[i]);
|
||||
Kotlin_Array_set(result, i, symbol);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ThrowException(KRef exception) {
|
||||
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
|
||||
"Throwing something non-throwable");
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Returns current stacktrace as Array<String>.
|
||||
KArrayRef GetCurrentStackTrace();
|
||||
|
||||
// Throws arbitrary exception.
|
||||
void ThrowException(KRef exception);
|
||||
|
||||
|
||||
@@ -180,4 +180,8 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex)
|
||||
return result;
|
||||
}
|
||||
|
||||
KArrayRef Kotlin_getCurrentStackTrace() {
|
||||
return GetCurrentStackTrace();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -37,8 +37,8 @@ inline const T* PrimitiveArrayAddressOfElementAt(
|
||||
return reinterpret_cast<const T*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline KRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<KRef*>(obj + 1) + index;
|
||||
inline KConstRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<KConstRef*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
|
||||
@@ -60,7 +60,7 @@ KString Kotlin_Any_toString(KConstRef thiz);
|
||||
// TODO: those must be compiler intrinsics afterwards.
|
||||
ArrayHeader* Kotlin_Array_clone(const ArrayHeader* thiz);
|
||||
KRef Kotlin_Array_get(const ArrayHeader* thiz, KInt index);
|
||||
void Kotlin_Array_set(ArrayHeader* thiz, KInt index, KRef value);
|
||||
void Kotlin_Array_set(ArrayHeader* thiz, KInt index, KConstRef value);
|
||||
KInt Kotlin_Array_getArrayLength(const ArrayHeader* thiz);
|
||||
|
||||
ArrayHeader* Kotlin_ByteArray_clone(const ArrayHeader* thiz);
|
||||
@@ -98,6 +98,8 @@ KString Kotlin_String_plusImpl(KString thiz, KString other);
|
||||
KInt Kotlin_String_getStringLength(KString thiz);
|
||||
KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex);
|
||||
|
||||
KArrayRef Kotlin_getCurrentStackTrace();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@ typedef float KFloat;
|
||||
typedef double KDouble;
|
||||
|
||||
typedef ObjHeader* KRef;
|
||||
typedef ArrayHeader* KArrayRef;
|
||||
typedef const ObjHeader* KConstRef;
|
||||
typedef const ArrayHeader* KString;
|
||||
|
||||
|
||||
@@ -8,16 +8,35 @@ package kotlin
|
||||
*/
|
||||
@ExportTypeInfo("theThrowableTypeInfo")
|
||||
public open class Throwable(open val message: String?, open val cause: Throwable?) {
|
||||
|
||||
constructor(message: String?) : this(message, null)
|
||||
|
||||
constructor(cause: Throwable?) : this(cause?.toString(), cause)
|
||||
|
||||
constructor() : this(null, null)
|
||||
|
||||
private val stacktrace: Array<String> = getCurrentStackTrace()
|
||||
|
||||
fun printStackTrace() {
|
||||
println(this.toString())
|
||||
for (element in stacktrace) {
|
||||
println(" at " + element)
|
||||
}
|
||||
|
||||
this.cause?.printEnclosedStackTrace(this)
|
||||
}
|
||||
|
||||
private fun printEnclosedStackTrace(enclosing: Throwable) {
|
||||
// TODO: should skip common stack frames
|
||||
print("Caused by: ")
|
||||
this.printStackTrace()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
/* enable, once codegen is improved.
|
||||
val s = "Throwable"
|
||||
return if (message != null) s + ": " + message.toString() else s */
|
||||
return "Throwable"
|
||||
val s = "Throwable" // TODO: should be class name
|
||||
return if (message != null) s + ": " + message.toString() else s
|
||||
}
|
||||
}
|
||||
|
||||
@SymbolName("Kotlin_getCurrentStackTrace")
|
||||
private external fun getCurrentStackTrace(): Array<String>
|
||||
Reference in New Issue
Block a user