Lazy stacktrace (#2036)
* stringify stacktrace lazily * Introduce NativePtrArray * Added Throwable::getStackTrace
This commit is contained in:
+2
-1
@@ -97,7 +97,8 @@ internal val arrayTypes = setOf(
|
|||||||
"kotlin.FloatArray",
|
"kotlin.FloatArray",
|
||||||
"kotlin.DoubleArray",
|
"kotlin.DoubleArray",
|
||||||
"kotlin.BooleanArray",
|
"kotlin.BooleanArray",
|
||||||
"kotlin.native.ImmutableBlob"
|
"kotlin.native.ImmutableBlob",
|
||||||
|
"kotlin.native.internal.NativePtrArray"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -109,7 +109,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
"kotlin.DoubleArray" to LLVMDoubleType()!!,
|
"kotlin.DoubleArray" to LLVMDoubleType()!!,
|
||||||
"kotlin.BooleanArray" to LLVMInt8Type()!!,
|
"kotlin.BooleanArray" to LLVMInt8Type()!!,
|
||||||
"kotlin.String" to LLVMInt16Type()!!,
|
"kotlin.String" to LLVMInt16Type()!!,
|
||||||
"kotlin.native.ImmutableBlob" to LLVMInt8Type()!!
|
"kotlin.native.ImmutableBlob" to LLVMInt8Type()!!,
|
||||||
|
"kotlin.native.internal.NativePtrArray" to kInt8Ptr
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keep in sync with Konan_RuntimeType.
|
// Keep in sync with Konan_RuntimeType.
|
||||||
|
|||||||
@@ -48,6 +48,26 @@ inline void copyImpl(KConstRef thiz, KInt fromIndex,
|
|||||||
count * sizeof(T));
|
count * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void PrimitiveArraySet(KRef thiz, KInt index, T value) {
|
||||||
|
ArrayHeader* array = thiz->array();
|
||||||
|
if (static_cast<uint32_t>(index) >= array->count_) {
|
||||||
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
mutabilityCheck(thiz);
|
||||||
|
*PrimitiveArrayAddressOfElementAt<T>(array, index) = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T PrimitiveArrayGet(KConstRef thiz, KInt index) {
|
||||||
|
const ArrayHeader* array = thiz->array();
|
||||||
|
if (static_cast<uint32_t>(index) >= array->count_) {
|
||||||
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
return *PrimitiveArrayAddressOfElementAt<T>(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -278,20 +298,11 @@ void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) {
|
KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KChar>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KChar>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) {
|
void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KChar>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_CharArray_copyOf, KConstRef thiz, KInt newSize) {
|
OBJ_GETTER(Kotlin_CharArray_copyOf, KConstRef thiz, KInt newSize) {
|
||||||
@@ -315,20 +326,11 @@ KInt Kotlin_CharArray_getArrayLength(KConstRef thiz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KShort Kotlin_ShortArray_get(KConstRef thiz, KInt index) {
|
KShort Kotlin_ShortArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KShort>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KShort>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) {
|
void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KShort>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) {
|
||||||
@@ -337,20 +339,11 @@ KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_IntArray_get(KConstRef thiz, KInt index) {
|
KInt Kotlin_IntArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KInt>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KInt>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) {
|
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KInt>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_IntArray_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_IntArray_getArrayLength(KConstRef thiz) {
|
||||||
@@ -410,21 +403,11 @@ void Kotlin_BooleanArray_copyImpl(KConstRef thiz, KInt fromIndex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
KLong Kotlin_LongArray_get(KConstRef thiz, KInt index) {
|
KLong Kotlin_LongArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KLong>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KLong>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) {
|
void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KLong>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) {
|
||||||
@@ -433,20 +416,11 @@ KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KFloat Kotlin_FloatArray_get(KConstRef thiz, KInt index) {
|
KFloat Kotlin_FloatArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KFloat>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KFloat>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) {
|
void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KFloat>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) {
|
||||||
@@ -455,20 +429,11 @@ KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KDouble Kotlin_DoubleArray_get(KConstRef thiz, KInt index) {
|
KDouble Kotlin_DoubleArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KDouble>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KDouble>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) {
|
void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KDouble>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) {
|
||||||
@@ -477,20 +442,11 @@ KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KBoolean Kotlin_BooleanArray_get(KConstRef thiz, KInt index) {
|
KBoolean Kotlin_BooleanArray_get(KConstRef thiz, KInt index) {
|
||||||
const ArrayHeader* array = thiz->array();
|
return PrimitiveArrayGet<KBoolean>(thiz, index);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
return *PrimitiveArrayAddressOfElementAt<KBoolean>(array, index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) {
|
void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) {
|
||||||
ArrayHeader* array = thiz->array();
|
PrimitiveArraySet(thiz, index, value);
|
||||||
if (static_cast<uint32_t>(index) >= array->count_) {
|
|
||||||
ThrowArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
mutabilityCheck(thiz);
|
|
||||||
*PrimitiveArrayAddressOfElementAt<KBoolean>(array, index) = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) {
|
KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) {
|
||||||
@@ -498,6 +454,19 @@ KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) {
|
|||||||
return array->count_;
|
return array->count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index) {
|
||||||
|
return PrimitiveArrayGet<KNativePtr>(thiz, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kotlin_NativePtrArray_set(KRef thiz, KInt index, KNativePtr value) {
|
||||||
|
PrimitiveArraySet(thiz, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
KInt Kotlin_NativePtrArray_getArrayLength(KConstRef thiz) {
|
||||||
|
const ArrayHeader* array = thiz->array();
|
||||||
|
return array->count_;
|
||||||
|
}
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_ImmutableBlob_toByteArray, KConstRef thiz, KInt start, KInt count) {
|
OBJ_GETTER(Kotlin_ImmutableBlob_toByteArray, KConstRef thiz, KInt start, KInt count) {
|
||||||
const ArrayHeader* array = thiz->array();
|
const ArrayHeader* array = thiz->array();
|
||||||
if (start < 0 || count < 0 || start > array->count_ - count) {
|
if (start < 0 || count < 0 || start > array->count_ - count) {
|
||||||
|
|||||||
@@ -60,17 +60,17 @@ class AutoFree {
|
|||||||
#if USE_GCC_UNWIND
|
#if USE_GCC_UNWIND
|
||||||
struct Backtrace {
|
struct Backtrace {
|
||||||
Backtrace(int count, int skip) : index(0), skipCount(skip) {
|
Backtrace(int count, int skip) : index(0), skipCount(skip) {
|
||||||
auto result = AllocArrayInstance(
|
uint32_t size = count - skipCount;
|
||||||
theArrayTypeInfo, count - skipCount, arrayHolder.slot());
|
if (size < 0) {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
auto result = AllocArrayInstance(theNativePtrArrayTypeInfo, size, arrayHolder.slot());
|
||||||
// TODO: throw cached OOME?
|
// TODO: throw cached OOME?
|
||||||
RuntimeCheck(result != nullptr, "Cannot create backtrace array");
|
RuntimeCheck(result != nullptr, "Cannot create backtrace array");
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNextElement(const char* element) {
|
void setNextElement(_Unwind_Ptr element) {
|
||||||
auto result = CreateStringFromCString(
|
Kotlin_NativePtrArray_set(obj(), index++, (KNativePtr) element);
|
||||||
element, ArrayAddressOfElementAt(obj()->array(), index++));
|
|
||||||
// TODO: throw cached OOME?
|
|
||||||
RuntimeCheck(result != nullptr, "Cannot create backtrace array element");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjHeader* obj() { return arrayHolder.obj(); }
|
ObjHeader* obj() { return arrayHolder.obj(); }
|
||||||
@@ -100,17 +100,8 @@ _Unwind_Reason_Code unwindCallback(
|
|||||||
#else
|
#else
|
||||||
_Unwind_Ptr address = _Unwind_GetIP(context);
|
_Unwind_Ptr address = _Unwind_GetIP(context);
|
||||||
#endif
|
#endif
|
||||||
|
backtrace->setNextElement(address);
|
||||||
|
|
||||||
char symbol[512];
|
|
||||||
if (!AddressToSymbol((const void*)address, symbol, sizeof(symbol))) {
|
|
||||||
// Make empty string:
|
|
||||||
symbol[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
char line[512];
|
|
||||||
konan::snprintf(line, sizeof(line) - 1, "%s (%p)",
|
|
||||||
symbol, (void*)(intptr_t)address);
|
|
||||||
backtrace->setNextElement(line);
|
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -123,44 +114,71 @@ extern "C" {
|
|||||||
// however it is better to have an inexact stacktrace than not to have any.
|
// however it is better to have an inexact stacktrace than not to have any.
|
||||||
OBJ_GETTER0(GetCurrentStackTrace) {
|
OBJ_GETTER0(GetCurrentStackTrace) {
|
||||||
#if OMIT_BACKTRACE
|
#if OMIT_BACKTRACE
|
||||||
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT);
|
return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT);
|
||||||
ArrayHeader* array = result->array();
|
|
||||||
CreateStringFromCString("<UNIMPLEMENTED>", ArrayAddressOfElementAt(array, 0));
|
|
||||||
return result;
|
|
||||||
#else
|
#else
|
||||||
// Skips first 3 elements as irrelevant.
|
// Skips first 3 elements as irrelevant.
|
||||||
constexpr int kSkipFrames = 3;
|
constexpr int kSkipFrames = 3;
|
||||||
#if USE_GCC_UNWIND
|
#if USE_GCC_UNWIND
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
_Unwind_Backtrace(depthCountCallback, &depth);
|
_Unwind_Backtrace(depthCountCallback, &depth);
|
||||||
if (depth < kSkipFrames)
|
|
||||||
return AllocArrayInstance(theArrayTypeInfo, 0, OBJ_RESULT);
|
|
||||||
Backtrace result(depth, kSkipFrames);
|
Backtrace result(depth, kSkipFrames);
|
||||||
_Unwind_Backtrace(unwindCallback, &result);
|
if (result.obj()->array()->count_ > 0) {
|
||||||
|
_Unwind_Backtrace(unwindCallback, &result);
|
||||||
|
}
|
||||||
RETURN_OBJ(result.obj());
|
RETURN_OBJ(result.obj());
|
||||||
#else
|
#else
|
||||||
const int maxSize = 32;
|
const int maxSize = 32;
|
||||||
void* buffer[maxSize];
|
void* buffer[maxSize];
|
||||||
|
|
||||||
int size = backtrace(buffer, maxSize);
|
int size = backtrace(buffer, maxSize);
|
||||||
char** symbols = backtrace_symbols(buffer, size);
|
|
||||||
RuntimeCheck(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
|
|
||||||
if (size < kSkipFrames)
|
if (size < kSkipFrames)
|
||||||
return AllocArrayInstance(theArrayTypeInfo, 0, OBJ_RESULT);
|
return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT);
|
||||||
AutoFree autoFree(symbols);
|
|
||||||
ObjHolder resultHolder;
|
ObjHolder resultHolder;
|
||||||
ObjHeader* result = AllocArrayInstance(
|
ObjHeader* result = AllocArrayInstance(theNativePtrArrayTypeInfo, size - kSkipFrames, resultHolder.slot());
|
||||||
theArrayTypeInfo, size - kSkipFrames, resultHolder.slot());
|
|
||||||
ArrayHeader* array = result->array();
|
|
||||||
for (int index = kSkipFrames; index < size; ++index) {
|
for (int index = kSkipFrames; index < size; ++index) {
|
||||||
CreateStringFromCString(
|
Kotlin_NativePtrArray_set(result, index - kSkipFrames, buffer[index]);
|
||||||
symbols[index], ArrayAddressOfElementAt(array, index - kSkipFrames));
|
|
||||||
}
|
}
|
||||||
RETURN_OBJ(result);
|
RETURN_OBJ(result);
|
||||||
#endif
|
#endif
|
||||||
#endif // !OMIT_BACKTRACE
|
#endif // !OMIT_BACKTRACE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) {
|
||||||
|
#if OMIT_BACKTRACE
|
||||||
|
ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT);
|
||||||
|
CreateStringFromCString("<UNIMPLEMENTED>", ArrayAddressOfElementAt(result->array(), 0));
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
uint32_t size = stackTrace->array()->count_;
|
||||||
|
ObjHolder resultHolder;
|
||||||
|
ObjHeader* strings = AllocArrayInstance(theArrayTypeInfo, size, resultHolder.slot());
|
||||||
|
#if USE_GCC_UNWIND
|
||||||
|
for (int index = 0; index < size; ++index) {
|
||||||
|
KNativePtr address = Kotlin_NativePtrArray_get(stackTrace, index);
|
||||||
|
char symbol[512];
|
||||||
|
if (!AddressToSymbol((const void*) address, symbol, sizeof(symbol))) {
|
||||||
|
// Make empty string:
|
||||||
|
symbol[0] = '\0';
|
||||||
|
}
|
||||||
|
char line[512];
|
||||||
|
konan::snprintf(line, sizeof(line) - 1, "%s (%p)", symbol, (void*)(intptr_t)address);
|
||||||
|
CreateStringFromCString(line, ArrayAddressOfElementAt(strings->array(), index));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (size > 0) {
|
||||||
|
char **symbols = backtrace_symbols(PrimitiveArrayAddressOfElementAt<KNativePtr>(stackTrace->array(), 0), size);
|
||||||
|
RuntimeCheck(symbols != nullptr, "Not enough memory to retrieve the stacktrace");
|
||||||
|
AutoFree autoFree(symbols);
|
||||||
|
for (int index = 0; index < size; ++index) {
|
||||||
|
CreateStringFromCString(symbols[index], ArrayAddressOfElementAt(strings->array(), index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
RETURN_OBJ(strings);
|
||||||
|
#endif // !OMIT_BACKTRACE
|
||||||
|
}
|
||||||
|
|
||||||
void ThrowException(KRef exception) {
|
void ThrowException(KRef exception) {
|
||||||
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
|
RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo),
|
||||||
"Throwing something non-throwable");
|
"Throwing something non-throwable");
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ extern "C" {
|
|||||||
// Returns current stacktrace as Array<String>.
|
// Returns current stacktrace as Array<String>.
|
||||||
OBJ_GETTER0(GetCurrentStackTrace);
|
OBJ_GETTER0(GetCurrentStackTrace);
|
||||||
|
|
||||||
|
OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace);
|
||||||
|
|
||||||
// Throws arbitrary exception.
|
// Throws arbitrary exception.
|
||||||
void ThrowException(KRef exception);
|
void ThrowException(KRef exception);
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ OBJ_GETTER0(Kotlin_getCurrentStackTrace) {
|
|||||||
RETURN_RESULT_OF0(GetCurrentStackTrace);
|
RETURN_RESULT_OF0(GetCurrentStackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBJ_GETTER(Kotlin_getStackTraceStrings, KConstRef stackTrace) {
|
||||||
|
RETURN_RESULT_OF(GetStackTraceStrings, stackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: consider handling it with compiler magic instead.
|
// TODO: consider handling it with compiler magic instead.
|
||||||
OBJ_GETTER0(Kotlin_native_internal_undefined) {
|
OBJ_GETTER0(Kotlin_native_internal_undefined) {
|
||||||
RETURN_OBJ(nullptr);
|
RETURN_OBJ(nullptr);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define RUNTIME_NATIVES_H
|
#define RUNTIME_NATIVES_H
|
||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#include "Exceptions.h"
|
||||||
|
|
||||||
inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) {
|
inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) {
|
||||||
// Instance size is negative.
|
// Instance size is negative.
|
||||||
@@ -109,6 +110,13 @@ KInt Kotlin_IntArray_get(KConstRef thiz, KInt index);
|
|||||||
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value);
|
void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value);
|
||||||
KInt Kotlin_IntArray_getArrayLength(KConstRef thiz);
|
KInt Kotlin_IntArray_getArrayLength(KConstRef thiz);
|
||||||
|
|
||||||
|
KLong Kotlin_LongArray_get(KConstRef thiz, KInt index);
|
||||||
|
void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value);
|
||||||
|
|
||||||
|
KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index);
|
||||||
|
void Kotlin_NativePtrArray_set(KRef thiz, KInt index, KNativePtr value);
|
||||||
|
KInt Kotlin_NativePtrArray_getArrayLength(KConstRef thiz);
|
||||||
|
|
||||||
// io/Console.kt
|
// io/Console.kt
|
||||||
void Kotlin_io_Console_print(KString message);
|
void Kotlin_io_Console_print(KString message);
|
||||||
void Kotlin_io_Console_println(KString message);
|
void Kotlin_io_Console_println(KString message);
|
||||||
@@ -132,6 +140,8 @@ OBJ_GETTER(Kotlin_String_subSequence, KString thiz, KInt startIndex, KInt endInd
|
|||||||
|
|
||||||
OBJ_GETTER0(Kotlin_getCurrentStackTrace);
|
OBJ_GETTER0(Kotlin_getCurrentStackTrace);
|
||||||
|
|
||||||
|
OBJ_GETTER(Kotlin_getStackTraceStrings, KConstRef stackTrace);
|
||||||
|
|
||||||
OBJ_GETTER0(Kotlin_native_internal_undefined);
|
OBJ_GETTER0(Kotlin_native_internal_undefined);
|
||||||
|
|
||||||
void Kotlin_native_internal_GC_suspend(KRef);
|
void Kotlin_native_internal_GC_suspend(KRef);
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ extern const TypeInfo* theThrowableTypeInfo;
|
|||||||
extern const TypeInfo* theUnitTypeInfo;
|
extern const TypeInfo* theUnitTypeInfo;
|
||||||
extern const TypeInfo* theForeignObjCObjectTypeInfo;
|
extern const TypeInfo* theForeignObjCObjectTypeInfo;
|
||||||
extern const TypeInfo* theObjCObjectWrapperTypeInfo;
|
extern const TypeInfo* theObjCObjectWrapperTypeInfo;
|
||||||
|
extern const TypeInfo* theNativePtrArrayTypeInfo;
|
||||||
|
|
||||||
KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE;
|
KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE;
|
||||||
void CheckCast(const ObjHeader* obj, const TypeInfo* type_info);
|
void CheckCast(const ObjHeader* obj, const TypeInfo* type_info);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package kotlin
|
package kotlin
|
||||||
|
|
||||||
import kotlin.native.internal.ExportTypeInfo
|
import kotlin.native.internal.ExportTypeInfo
|
||||||
|
import kotlin.native.internal.NativePtrArray
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base class for all errors and exceptions. Only instances of this class can be thrown or caught.
|
* The base class for all errors and exceptions. Only instances of this class can be thrown or caught.
|
||||||
@@ -22,11 +23,18 @@ public open class Throwable(open val message: String?, open val cause: Throwable
|
|||||||
|
|
||||||
constructor() : this(null, null)
|
constructor() : this(null, null)
|
||||||
|
|
||||||
private val stacktrace: Array<String> = getCurrentStackTrace()
|
private val stackTrace = getCurrentStackTrace()
|
||||||
|
|
||||||
|
private val stackTraceStrings: Array<String> by lazy {
|
||||||
|
getStackTraceStrings(stackTrace)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStackTrace(): Array<String> = stackTraceStrings
|
||||||
|
|
||||||
fun printStackTrace() {
|
fun printStackTrace() {
|
||||||
println(this.toString())
|
println(this.toString())
|
||||||
for (element in stacktrace) {
|
|
||||||
|
for (element in stackTraceStrings) {
|
||||||
println(" at " + element)
|
println(" at " + element)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,4 +56,7 @@ public open class Throwable(open val message: String?, open val cause: Throwable
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SymbolName("Kotlin_getCurrentStackTrace")
|
@SymbolName("Kotlin_getCurrentStackTrace")
|
||||||
private external fun getCurrentStackTrace(): Array<String>
|
private external fun getCurrentStackTrace(): NativePtrArray
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_getStackTraceStrings")
|
||||||
|
private external fun getStackTraceStrings(stackTrace: NativePtrArray): Array<String>
|
||||||
@@ -36,3 +36,16 @@ internal inline class NonNullNativePtr(val value: NotNullPointerValue) { // TODO
|
|||||||
|
|
||||||
override fun equals(other: Any?) = false
|
override fun equals(other: Any?) = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExportTypeInfo("theNativePtrArrayTypeInfo")
|
||||||
|
internal class NativePtrArray {
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_NativePtrArray_get")
|
||||||
|
external public operator fun get(index: Int): NativePtr
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_NativePtrArray_set")
|
||||||
|
external public operator fun set(index: Int, value: NativePtr): Unit
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_NativePtrArray_getArrayLength")
|
||||||
|
external private fun getArrayLength(): Int
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user