runtime: add trivial stack traces to exceptions

This commit is contained in:
Svyatoslav Scherbina
2016-12-02 11:23:50 +07:00
committed by SvyatoslavScherbina
parent b7b99d5684
commit f4014b0f29
9 changed files with 91 additions and 12 deletions
+2 -1
View File
@@ -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
}
+3 -3
View File
@@ -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.
}
}
+1 -1
View File
@@ -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();
}
+49
View File
@@ -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");
+3
View File
@@ -7,6 +7,9 @@
extern "C" {
#endif
// Returns current stacktrace as Array<String>.
KArrayRef GetCurrentStackTrace();
// Throws arbitrary exception.
void ThrowException(KRef exception);
+4
View File
@@ -180,4 +180,8 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex)
return result;
}
KArrayRef Kotlin_getCurrentStackTrace() {
return GetCurrentStackTrace();
}
} // extern "C"
+5 -3
View File
@@ -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
+1
View File
@@ -15,6 +15,7 @@ typedef float KFloat;
typedef double KDouble;
typedef ObjHeader* KRef;
typedef ArrayHeader* KArrayRef;
typedef const ObjHeader* KConstRef;
typedef const ArrayHeader* KString;
+23 -4
View File
@@ -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>