diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt index e99843a3e60..9c186c70256 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt @@ -97,7 +97,8 @@ internal val arrayTypes = setOf( "kotlin.FloatArray", "kotlin.DoubleArray", "kotlin.BooleanArray", - "kotlin.native.ImmutableBlob" + "kotlin.native.ImmutableBlob", + "kotlin.native.internal.NativePtrArray" ) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index 6a86a9dbb2d..aa702f6d6c8 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -109,7 +109,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { "kotlin.DoubleArray" to LLVMDoubleType()!!, "kotlin.BooleanArray" to LLVMInt8Type()!!, "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. diff --git a/runtime/src/main/cpp/Arrays.cpp b/runtime/src/main/cpp/Arrays.cpp index e244b7d20f1..cc2a956ea69 100644 --- a/runtime/src/main/cpp/Arrays.cpp +++ b/runtime/src/main/cpp/Arrays.cpp @@ -48,6 +48,26 @@ inline void copyImpl(KConstRef thiz, KInt fromIndex, count * sizeof(T)); } + +template +inline void PrimitiveArraySet(KRef thiz, KInt index, T value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + mutabilityCheck(thiz); + *PrimitiveArrayAddressOfElementAt(array, index) = value; +} + +template +inline T PrimitiveArrayGet(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *PrimitiveArrayAddressOfElementAt(array, index); +} + } // namespace extern "C" { @@ -278,20 +298,11 @@ void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) { } KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_CharArray_set(KRef thiz, KInt index, KChar value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } 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) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_ShortArray_set(KRef thiz, KInt index, KShort value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) { @@ -337,20 +339,11 @@ KInt Kotlin_ShortArray_getArrayLength(KConstRef thiz) { } KInt Kotlin_IntArray_get(KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_IntArray_set(KRef thiz, KInt index, KInt value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } 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) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_LongArray_set(KRef thiz, KInt index, KLong value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) { @@ -433,20 +416,11 @@ KInt Kotlin_LongArray_getArrayLength(KConstRef thiz) { } KFloat Kotlin_FloatArray_get(KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_FloatArray_set(KRef thiz, KInt index, KFloat value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) { @@ -455,20 +429,11 @@ KInt Kotlin_FloatArray_getArrayLength(KConstRef thiz) { } KDouble Kotlin_DoubleArray_get(KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_DoubleArray_set(KRef thiz, KInt index, KDouble value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) { @@ -477,20 +442,11 @@ KInt Kotlin_DoubleArray_getArrayLength(KConstRef thiz) { } KBoolean Kotlin_BooleanArray_get(KConstRef thiz, KInt index) { - const ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - return *PrimitiveArrayAddressOfElementAt(array, index); + return PrimitiveArrayGet(thiz, index); } void Kotlin_BooleanArray_set(KRef thiz, KInt index, KBoolean value) { - ArrayHeader* array = thiz->array(); - if (static_cast(index) >= array->count_) { - ThrowArrayIndexOutOfBoundsException(); - } - mutabilityCheck(thiz); - *PrimitiveArrayAddressOfElementAt(array, index) = value; + PrimitiveArraySet(thiz, index, value); } KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) { @@ -498,6 +454,19 @@ KInt Kotlin_BooleanArray_getArrayLength(KConstRef thiz) { return array->count_; } +KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index) { + return PrimitiveArrayGet(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) { const ArrayHeader* array = thiz->array(); if (start < 0 || count < 0 || start > array->count_ - count) { diff --git a/runtime/src/main/cpp/Exceptions.cpp b/runtime/src/main/cpp/Exceptions.cpp index 8677335f42d..30b12653bf3 100644 --- a/runtime/src/main/cpp/Exceptions.cpp +++ b/runtime/src/main/cpp/Exceptions.cpp @@ -60,17 +60,17 @@ class AutoFree { #if USE_GCC_UNWIND struct Backtrace { Backtrace(int count, int skip) : index(0), skipCount(skip) { - auto result = AllocArrayInstance( - theArrayTypeInfo, count - skipCount, arrayHolder.slot()); + uint32_t size = count - skipCount; + if (size < 0) { + size = 0; + } + auto result = AllocArrayInstance(theNativePtrArrayTypeInfo, size, arrayHolder.slot()); // TODO: throw cached OOME? RuntimeCheck(result != nullptr, "Cannot create backtrace array"); } - void setNextElement(const char* element) { - auto result = CreateStringFromCString( - element, ArrayAddressOfElementAt(obj()->array(), index++)); - // TODO: throw cached OOME? - RuntimeCheck(result != nullptr, "Cannot create backtrace array element"); + void setNextElement(_Unwind_Ptr element) { + Kotlin_NativePtrArray_set(obj(), index++, (KNativePtr) element); } ObjHeader* obj() { return arrayHolder.obj(); } @@ -100,17 +100,8 @@ _Unwind_Reason_Code unwindCallback( #else _Unwind_Ptr address = _Unwind_GetIP(context); #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; } #endif @@ -123,44 +114,71 @@ extern "C" { // however it is better to have an inexact stacktrace than not to have any. OBJ_GETTER0(GetCurrentStackTrace) { #if OMIT_BACKTRACE - ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT); - ArrayHeader* array = result->array(); - CreateStringFromCString("", ArrayAddressOfElementAt(array, 0)); - return result; + return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT); #else // Skips first 3 elements as irrelevant. constexpr int kSkipFrames = 3; #if USE_GCC_UNWIND int depth = 0; _Unwind_Backtrace(depthCountCallback, &depth); - if (depth < kSkipFrames) - return AllocArrayInstance(theArrayTypeInfo, 0, OBJ_RESULT); Backtrace result(depth, kSkipFrames); - _Unwind_Backtrace(unwindCallback, &result); + if (result.obj()->array()->count_ > 0) { + _Unwind_Backtrace(unwindCallback, &result); + } RETURN_OBJ(result.obj()); #else const int maxSize = 32; void* 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) - return AllocArrayInstance(theArrayTypeInfo, 0, OBJ_RESULT); - AutoFree autoFree(symbols); + return AllocArrayInstance(theNativePtrArrayTypeInfo, 0, OBJ_RESULT); + ObjHolder resultHolder; - ObjHeader* result = AllocArrayInstance( - theArrayTypeInfo, size - kSkipFrames, resultHolder.slot()); - ArrayHeader* array = result->array(); + ObjHeader* result = AllocArrayInstance(theNativePtrArrayTypeInfo, size - kSkipFrames, resultHolder.slot()); for (int index = kSkipFrames; index < size; ++index) { - CreateStringFromCString( - symbols[index], ArrayAddressOfElementAt(array, index - kSkipFrames)); + Kotlin_NativePtrArray_set(result, index - kSkipFrames, buffer[index]); } RETURN_OBJ(result); #endif #endif // !OMIT_BACKTRACE } +OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace) { +#if OMIT_BACKTRACE + ObjHeader* result = AllocArrayInstance(theArrayTypeInfo, 1, OBJ_RESULT); + CreateStringFromCString("", 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(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) { RuntimeAssert(exception != nullptr && IsInstance(exception, theThrowableTypeInfo), "Throwing something non-throwable"); diff --git a/runtime/src/main/cpp/Exceptions.h b/runtime/src/main/cpp/Exceptions.h index 71509982139..0ecfb0f3d0f 100644 --- a/runtime/src/main/cpp/Exceptions.h +++ b/runtime/src/main/cpp/Exceptions.h @@ -26,6 +26,8 @@ extern "C" { // Returns current stacktrace as Array. OBJ_GETTER0(GetCurrentStackTrace); +OBJ_GETTER(GetStackTraceStrings, KConstRef stackTrace); + // Throws arbitrary exception. void ThrowException(KRef exception); diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index 8b2ab0f5a18..3ff054bc938 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -43,6 +43,10 @@ OBJ_GETTER0(Kotlin_getCurrentStackTrace) { RETURN_RESULT_OF0(GetCurrentStackTrace); } +OBJ_GETTER(Kotlin_getStackTraceStrings, KConstRef stackTrace) { + RETURN_RESULT_OF(GetStackTraceStrings, stackTrace); +} + // TODO: consider handling it with compiler magic instead. OBJ_GETTER0(Kotlin_native_internal_undefined) { RETURN_OBJ(nullptr); diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index 59a4a09b615..f6e30427fc6 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -18,6 +18,7 @@ #define RUNTIME_NATIVES_H #include "Types.h" +#include "Exceptions.h" inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) { // 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); 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 void Kotlin_io_Console_print(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_GETTER(Kotlin_getStackTraceStrings, KConstRef stackTrace); + OBJ_GETTER0(Kotlin_native_internal_undefined); void Kotlin_native_internal_GC_suspend(KRef); diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index 1989ad8f216..9512f898395 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -91,6 +91,7 @@ extern const TypeInfo* theThrowableTypeInfo; extern const TypeInfo* theUnitTypeInfo; extern const TypeInfo* theForeignObjCObjectTypeInfo; extern const TypeInfo* theObjCObjectWrapperTypeInfo; +extern const TypeInfo* theNativePtrArrayTypeInfo; KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PURE; void CheckCast(const ObjHeader* obj, const TypeInfo* type_info); diff --git a/runtime/src/main/kotlin/kotlin/Throwable.kt b/runtime/src/main/kotlin/kotlin/Throwable.kt index 13e41462b30..340bbcb5a84 100644 --- a/runtime/src/main/kotlin/kotlin/Throwable.kt +++ b/runtime/src/main/kotlin/kotlin/Throwable.kt @@ -6,6 +6,7 @@ package kotlin 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. @@ -22,11 +23,18 @@ public open class Throwable(open val message: String?, open val cause: Throwable constructor() : this(null, null) - private val stacktrace: Array = getCurrentStackTrace() + private val stackTrace = getCurrentStackTrace() + + private val stackTraceStrings: Array by lazy { + getStackTraceStrings(stackTrace) + } + + fun getStackTrace(): Array = stackTraceStrings fun printStackTrace() { println(this.toString()) - for (element in stacktrace) { + + for (element in stackTraceStrings) { println(" at " + element) } @@ -48,4 +56,7 @@ public open class Throwable(open val message: String?, open val cause: Throwable } @SymbolName("Kotlin_getCurrentStackTrace") -private external fun getCurrentStackTrace(): Array \ No newline at end of file +private external fun getCurrentStackTrace(): NativePtrArray + +@SymbolName("Kotlin_getStackTraceStrings") +private external fun getStackTraceStrings(stackTrace: NativePtrArray): Array \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt b/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt index d81accc7d6c..72234661e67 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt @@ -36,3 +36,16 @@ internal inline class NonNullNativePtr(val value: NotNullPointerValue) { // TODO 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 +}