Rework debugging interface to allow coexisting for multiple frameworks. (#3818)
This commit is contained in:
+5
-1
@@ -61,7 +61,11 @@ internal val disposeLLVMPhase = namedUnitPhase(
|
|||||||
internal val RTTIPhase = makeKonanModuleOpPhase(
|
internal val RTTIPhase = makeKonanModuleOpPhase(
|
||||||
name = "RTTI",
|
name = "RTTI",
|
||||||
description = "RTTI generation",
|
description = "RTTI generation",
|
||||||
op = { context, irModule -> irModule.acceptVoid(RTTIGeneratorVisitor(context)) }
|
op = { context, irModule ->
|
||||||
|
val visitor = RTTIGeneratorVisitor(context)
|
||||||
|
irModule.acceptVoid(visitor)
|
||||||
|
visitor.dispose()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val generateDebugInfoHeaderPhase = makeKonanModuleOpPhase(
|
internal val generateDebugInfoHeaderPhase = makeKonanModuleOpPhase(
|
||||||
|
|||||||
+3
@@ -105,6 +105,9 @@ internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
generator.dispose()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
|
|||||||
+35
-2
@@ -395,6 +395,30 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
private fun mapRuntimeType(type: LLVMTypeRef): Int =
|
private fun mapRuntimeType(type: LLVMTypeRef): Int =
|
||||||
runtimeTypeMap[type] ?: throw Error("Unmapped type: ${llvmtype2string(type)}")
|
runtimeTypeMap[type] ?: throw Error("Unmapped type: ${llvmtype2string(type)}")
|
||||||
|
|
||||||
|
private val debugRuntimeOrNull: LLVMModuleRef? by lazy {
|
||||||
|
context.config.runtimeNativeLibraries.singleOrNull { it.endsWith("debug.bc")}?.let {
|
||||||
|
parseBitcodeFile(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val debugOperations: ConstValue by lazy {
|
||||||
|
if (debugRuntimeOrNull != null) {
|
||||||
|
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
|
||||||
|
val local = LLVMAddGlobal(context.llvmModule, LLVMGetElementType(LLVMTypeOf(external)),"Konan_debugOperationsList")!!
|
||||||
|
constPointer(LLVMConstBitCast(local, kInt8PtrPtr)!!)
|
||||||
|
} else {
|
||||||
|
Zero(kInt8PtrPtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val debugOperationsSize: ConstValue by lazy {
|
||||||
|
if (debugRuntimeOrNull != null) {
|
||||||
|
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
|
||||||
|
Int32(LLVMGetArrayLength(LLVMGetElementType(LLVMTypeOf(external))))
|
||||||
|
} else
|
||||||
|
Int32(0)
|
||||||
|
}
|
||||||
|
|
||||||
private fun makeExtendedInfo(irClass: IrClass): ConstPointer {
|
private fun makeExtendedInfo(irClass: IrClass): ConstPointer {
|
||||||
// TODO: shall we actually do that?
|
// TODO: shall we actually do that?
|
||||||
if (context.shouldOptimize())
|
if (context.shouldOptimize())
|
||||||
@@ -404,12 +428,14 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
|
val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
|
||||||
val bodyType = llvmDeclarations.bodyType
|
val bodyType = llvmDeclarations.bodyType
|
||||||
val elementType = arrayClasses[className]
|
val elementType = arrayClasses[className]
|
||||||
|
|
||||||
val value = if (elementType != null) {
|
val value = if (elementType != null) {
|
||||||
// An array type.
|
// An array type.
|
||||||
val runtimeElementType = mapRuntimeType(elementType)
|
val runtimeElementType = mapRuntimeType(elementType)
|
||||||
Struct(runtime.extendedTypeInfoType,
|
Struct(runtime.extendedTypeInfoType,
|
||||||
Int32(-runtimeElementType),
|
Int32(-runtimeElementType),
|
||||||
NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr))
|
NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr),
|
||||||
|
debugOperationsSize, debugOperations)
|
||||||
} else {
|
} else {
|
||||||
data class FieldRecord(val offset: Int, val type: Int, val name: String)
|
data class FieldRecord(val offset: Int, val type: Int, val name: String)
|
||||||
val fields = getStructElements(bodyType).drop(1).mapIndexed { index, type ->
|
val fields = getStructElements(bodyType).drop(1).mapIndexed { index, type ->
|
||||||
@@ -424,7 +450,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
fields.map { Int8(it.type.toByte()) })
|
fields.map { Int8(it.type.toByte()) })
|
||||||
val namesPtr = staticData.placeGlobalConstArray("kextname:$className", kInt8Ptr,
|
val namesPtr = staticData.placeGlobalConstArray("kextname:$className", kInt8Ptr,
|
||||||
fields.map { staticData.placeCStringLiteral(it.name) })
|
fields.map { staticData.placeCStringLiteral(it.name) })
|
||||||
Struct(runtime.extendedTypeInfoType, Int32(fields.size), offsetsPtr, typesPtr, namesPtr)
|
|
||||||
|
Struct(runtime.extendedTypeInfoType, Int32(fields.size), offsetsPtr, typesPtr, namesPtr,
|
||||||
|
debugOperationsSize, debugOperations)
|
||||||
|
|
||||||
}
|
}
|
||||||
val result = staticData.placeGlobal("", value)
|
val result = staticData.placeGlobal("", value)
|
||||||
result.setConstant(true)
|
result.setConstant(true)
|
||||||
@@ -566,6 +595,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
.joinToString(".") { it.name.asString() }
|
.joinToString(".") { it.name.asString() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
debugRuntimeOrNull?.let { LLVMDisposeModule(it) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep in sync with Konan_TypeFlags in TypeInfo.h.
|
// Keep in sync with Konan_TypeFlags in TypeInfo.h.
|
||||||
|
|||||||
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates const array-typed global with given name and value.
|
* Creates const array-typed global with given name and value.
|
||||||
* Returns pointer to the first element of the array.
|
* Returns pointer to the first element of the array.
|
||||||
|
|||||||
+5
@@ -51,6 +51,10 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun dispose() {
|
||||||
|
rttiGenerator.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: currently bridges don't have any custom `landingpad`s,
|
// TODO: currently bridges don't have any custom `landingpad`s,
|
||||||
// so it is correct to use [callAtFunctionScope] here.
|
// so it is correct to use [callAtFunctionScope] here.
|
||||||
// However, exception handling probably should be refactored
|
// However, exception handling probably should be refactored
|
||||||
@@ -103,6 +107,7 @@ internal class ObjCExportBlockCodeGenerator(codegen: CodeGenerator) : ObjCExport
|
|||||||
fun generate() {
|
fun generate() {
|
||||||
emitFunctionConverters()
|
emitFunctionConverters()
|
||||||
emitBlockToKotlinFunctionConverters()
|
emitBlockToKotlinFunctionConverters()
|
||||||
|
dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -102,6 +102,7 @@ internal class ObjCExport(val context: Context, symbolTable: SymbolTable) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
objCCodeGenerator.emitRtti()
|
objCCodeGenerator.emitRtti()
|
||||||
|
objCCodeGenerator.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun produceFrameworkSpecific(headerLines: List<String>) {
|
private fun produceFrameworkSpecific(headerLines: List<String>) {
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ constexpr int runtimeTypeSize[] = {
|
|||||||
4, // FLOAT32
|
4, // FLOAT32
|
||||||
8, // FLOAT64
|
8, // FLOAT64
|
||||||
sizeof(void*), // NATIVE_PTR
|
sizeof(void*), // NATIVE_PTR
|
||||||
1 // BOOLEAN
|
1, // BOOLEAN
|
||||||
|
16 // VECTOR128
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr int runtimeTypeAlignment[] = {
|
constexpr int runtimeTypeAlignment[] = {
|
||||||
@@ -56,24 +57,59 @@ constexpr int runtimeTypeAlignment[] = {
|
|||||||
alignof(float), // FLOAT32
|
alignof(float), // FLOAT32
|
||||||
alignof(double), // FLOAT64
|
alignof(double), // FLOAT64
|
||||||
alignof(void*), // NATIVE_PTR
|
alignof(void*), // NATIVE_PTR
|
||||||
1 // BOOLEAN
|
1, // BOOLEAN
|
||||||
|
16 // VECTOR128
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
// Never ever change numbering in this enum, as it will break debugging of older binaries.
|
||||||
|
enum Konan_DebugOperation {
|
||||||
|
DO_DebugBuffer = 1,
|
||||||
|
DO_DebugBufferSize = 2,
|
||||||
|
DO_DebugBufferWithObject = 3,
|
||||||
|
DO_DebugBufferSizeWithObject = 4,
|
||||||
|
DO_DebugObjectToUtf8Array = 5,
|
||||||
|
DO_DebugPrint = 6,
|
||||||
|
DO_DebugIsArray = 7,
|
||||||
|
DO_DebugGetFieldCount = 8,
|
||||||
|
DO_DebugGetFieldType = 9,
|
||||||
|
DO_DebugGetFieldAddress = 10,
|
||||||
|
DO_DebugGetFieldName = 11,
|
||||||
|
DO_DebugGetTypeName = 12,
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" {
|
template <typename F>
|
||||||
|
F getImpl(KRef obj, Konan_DebugOperation operation) {
|
||||||
|
if (obj == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
auto* typeInfo = obj->type_info();
|
||||||
|
auto* extendedTypeInfo = typeInfo->extendedInfo_;
|
||||||
|
|
||||||
|
if (extendedTypeInfo == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
if (static_cast<int32_t>(operation) >= extendedTypeInfo->debugOperationsCount_)
|
||||||
|
return nullptr;
|
||||||
|
return reinterpret_cast<F>(extendedTypeInfo->debugOperations_[operation]);
|
||||||
|
}
|
||||||
|
|
||||||
// Buffer that can be used by debugger for inspections.
|
// Buffer that can be used by debugger for inspections.
|
||||||
RUNTIME_USED char* Konan_DebugBuffer() {
|
char* Konan_DebugBufferImpl() {
|
||||||
return debugBuffer;
|
return debugBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED int Konan_DebugBufferSize() {
|
int Konan_DebugBufferSizeImpl() {
|
||||||
|
return sizeof(debugBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* Konan_DebugBufferWithObjectImpl(KRef obj) {
|
||||||
|
return debugBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Konan_DebugBufferSizeWithObjectImpl(KRef obj) {
|
||||||
return sizeof(debugBuffer);
|
return sizeof(debugBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auxilary function which can be called by developer/debugger to inspect an object.
|
// Auxilary function which can be called by developer/debugger to inspect an object.
|
||||||
RUNTIME_USED KInt Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, KInt bufferSize) {
|
int32_t Konan_DebugObjectToUtf8ArrayImpl(KRef obj, char* buffer, int32_t bufferSize) {
|
||||||
ObjHolder stringHolder;
|
ObjHolder stringHolder;
|
||||||
auto data = KonanObjectToUtf8Array(obj, stringHolder.slot())->array();
|
auto data = KonanObjectToUtf8Array(obj, stringHolder.slot())->array();
|
||||||
if (data == nullptr) return 0;
|
if (data == nullptr) return 0;
|
||||||
@@ -83,23 +119,23 @@ RUNTIME_USED KInt Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, KInt buff
|
|||||||
return toCopy + 1;
|
return toCopy + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED KInt Konan_DebugPrint(KRef obj) {
|
int32_t Konan_DebugPrintImpl(KRef obj) {
|
||||||
KInt size = Konan_DebugObjectToUtf8Array(obj, Konan_DebugBuffer(), Konan_DebugBufferSize());
|
int32_t size = Konan_DebugObjectToUtf8Array(obj, Konan_DebugBuffer(), Konan_DebugBufferSize());
|
||||||
if (size > 1)
|
if (size > 1)
|
||||||
konan::consoleWriteUtf8(Konan_DebugBuffer(), size - 1);
|
konan::consoleWriteUtf8(Konan_DebugBuffer(), size - 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED int Konan_DebugIsArray(KRef obj) {
|
int32_t Konan_DebugIsArrayImpl(KRef obj) {
|
||||||
return obj == nullptr || IsArray(obj) ? 1 : 0;
|
return obj == nullptr || IsArray(obj) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED int Konan_DebugGetFieldCount(KRef obj) {
|
int32_t Konan_DebugGetFieldCountImpl(KRef obj) {
|
||||||
if (obj == nullptr)
|
if (obj == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto typeInfo = obj->type_info();
|
auto* typeInfo = obj->type_info();
|
||||||
auto extendedTypeInfo = typeInfo->extendedInfo_;
|
auto* extendedTypeInfo = typeInfo->extendedInfo_;
|
||||||
|
|
||||||
if (extendedTypeInfo == nullptr)
|
if (extendedTypeInfo == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -110,8 +146,7 @@ RUNTIME_USED int Konan_DebugGetFieldCount(KRef obj) {
|
|||||||
return extendedTypeInfo->fieldsCount_;
|
return extendedTypeInfo->fieldsCount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Konan_DebugGetFieldTypeImpl(KRef obj, int32_t index) {
|
||||||
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index) {
|
|
||||||
if (obj == nullptr || index < 0)
|
if (obj == nullptr || index < 0)
|
||||||
return Konan_RuntimeType::RT_INVALID;
|
return Konan_RuntimeType::RT_INVALID;
|
||||||
|
|
||||||
@@ -130,7 +165,7 @@ RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index) {
|
|||||||
return extendedTypeInfo->fieldTypes_[index];
|
return extendedTypeInfo->fieldTypes_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
|
void* Konan_DebugGetFieldAddressImpl(KRef obj, int32_t index) {
|
||||||
if (obj == nullptr || index < 0)
|
if (obj == nullptr || index < 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@@ -157,7 +192,7 @@ RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute address of field or an array element at the index, or null, if incorrect.
|
// Compute address of field or an array element at the index, or null, if incorrect.
|
||||||
RUNTIME_USED const char* Konan_DebugGetFieldName(KRef obj, int index) {
|
const char* Konan_DebugGetFieldNameImpl(KRef obj, int32_t index) {
|
||||||
if (obj == nullptr || index < 0)
|
if (obj == nullptr || index < 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@@ -177,7 +212,7 @@ RUNTIME_USED const char* Konan_DebugGetFieldName(KRef obj, int index) {
|
|||||||
return extendedTypeInfo->fieldNames_[index];
|
return extendedTypeInfo->fieldNames_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED const char* Konan_DebugGetTypeName(KRef obj) {
|
const char* Konan_DebugGetTypeNameImpl(KRef obj) {
|
||||||
if (obj == nullptr)
|
if (obj == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@@ -188,6 +223,96 @@ RUNTIME_USED const char* Konan_DebugGetTypeName(KRef obj) {
|
|||||||
return CreateCStringFromString(type_info->relativeName_);
|
return CreateCStringFromString(type_info->relativeName_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK char* Konan_DebugBuffer() {
|
||||||
|
return Konan_DebugBufferImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugBufferSize() {
|
||||||
|
return Konan_DebugBufferSizeImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK char* Konan_DebugBufferWithObject(KRef obj) {
|
||||||
|
auto* impl = getImpl<char* (*)(KRef)>(obj, DO_DebugBufferWithObject);
|
||||||
|
if (impl == nullptr) return nullptr;
|
||||||
|
return impl(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugBufferSizeWithObject(KRef obj) {
|
||||||
|
auto* impl = getImpl<int32_t (*)(KRef)>(obj, DO_DebugBufferSizeWithObject);
|
||||||
|
if (impl == nullptr) return 0;
|
||||||
|
return impl(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auxilary function which can be called by developer/debugger to inspect an object.
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int32_t bufferSize) {
|
||||||
|
auto* impl = getImpl<int32_t (*)(KRef, char*, int32_t)>(obj, DO_DebugObjectToUtf8Array);
|
||||||
|
if (impl == nullptr) return 0;
|
||||||
|
return impl(obj, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugPrint(KRef obj) {
|
||||||
|
auto* impl = getImpl<int32_t (*)(KRef)>(obj, DO_DebugPrint);
|
||||||
|
if (impl == nullptr) return 0;
|
||||||
|
return impl(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugIsArray(KRef obj) {
|
||||||
|
auto* impl = getImpl<int32_t (*)(KRef)>(obj, DO_DebugIsArray);
|
||||||
|
if (impl == nullptr) return 0;
|
||||||
|
return impl(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugGetFieldCount(KRef obj) {
|
||||||
|
auto* impl = getImpl<int32_t (*)(KRef)>(obj, DO_DebugGetFieldCount);
|
||||||
|
if (impl == nullptr) return 0;
|
||||||
|
return impl(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK int32_t Konan_DebugGetFieldType(KRef obj, int32_t index) {
|
||||||
|
auto* impl = getImpl<int32_t (*)(KRef, int32_t)>(obj, DO_DebugGetFieldType);
|
||||||
|
if (impl == nullptr) return 0;
|
||||||
|
return impl(obj, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK void* Konan_DebugGetFieldAddress(KRef obj, int32_t index) {
|
||||||
|
auto* impl = getImpl<void* (*)(KRef, int32_t)>(obj, DO_DebugGetFieldAddress);
|
||||||
|
if (impl == nullptr) return nullptr;
|
||||||
|
return impl(obj, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute address of field or an array element at the index, or null, if incorrect.
|
||||||
|
RUNTIME_USED RUNTIME_WEAK const char* Konan_DebugGetFieldName(KRef obj, int32_t index) {
|
||||||
|
auto* impl = getImpl<const char* (*)(KRef, int32_t)>(obj, DO_DebugGetFieldName);
|
||||||
|
if (impl == nullptr) return nullptr;
|
||||||
|
return impl(obj, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_USED RUNTIME_WEAK const char* Konan_DebugGetTypeName(KRef obj) {
|
||||||
|
auto* impl = getImpl<const char* (*)(KRef)>(obj, DO_DebugGetTypeName);
|
||||||
|
if (impl == nullptr) return nullptr;
|
||||||
|
return impl(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* Konan_debugOperationsList[] = {
|
||||||
|
nullptr,
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugBufferImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugBufferSizeImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugBufferWithObjectImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugBufferSizeWithObjectImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugObjectToUtf8ArrayImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugPrintImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugIsArrayImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugGetFieldCountImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugGetFieldTypeImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugGetFieldAddressImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugGetFieldNameImpl),
|
||||||
|
reinterpret_cast<const void*>(&Konan_DebugGetTypeNameImpl)
|
||||||
|
};
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
#endif // !KONAN_NO_DEBUG_API
|
#endif // !KONAN_NO_DEBUG_API
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define RUNTIME_CONST __attribute__((const))
|
#define RUNTIME_CONST __attribute__((const))
|
||||||
#define RUNTIME_PURE __attribute__((pure))
|
#define RUNTIME_PURE __attribute__((pure))
|
||||||
#define RUNTIME_USED __attribute__((used))
|
#define RUNTIME_USED __attribute__((used))
|
||||||
|
#define RUNTIME_WEAK __attribute__((weak))
|
||||||
|
|
||||||
#define ALWAYS_INLINE __attribute__((always_inline))
|
#define ALWAYS_INLINE __attribute__((always_inline))
|
||||||
#define NO_INLINE __attribute__((noinline))
|
#define NO_INLINE __attribute__((noinline))
|
||||||
|
|||||||
@@ -28,40 +28,65 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// PLEASE READ: please do not alter signatures of the existing functions, and when adding
|
||||||
|
// the new function please do not forget to add new functions into the debug operations list.
|
||||||
|
|
||||||
// Get memory buffer where debugger can put data in Konan app process.
|
// Get memory buffer where debugger can put data in Konan app process.
|
||||||
RUNTIME_USED
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
char* Konan_DebugBuffer();
|
char* Konan_DebugBuffer();
|
||||||
|
|
||||||
|
// Same, but runtime-specific.
|
||||||
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
char* Konan_DebugBufferWithObject(KRef obj);
|
||||||
|
|
||||||
// Get size of memory buffer where debugger can put data in Konan app process.
|
// Get size of memory buffer where debugger can put data in Konan app process.
|
||||||
RUNTIME_USED
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
int32_t Konan_DebugBufferSize();
|
int32_t Konan_DebugBufferSize();
|
||||||
|
|
||||||
|
// Same, but runtime-specific.
|
||||||
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
int32_t Konan_DebugBufferSizeWithObject(KRef obj);
|
||||||
|
|
||||||
// Put string representation of an object to the provided buffer.
|
// Put string representation of an object to the provided buffer.
|
||||||
RUNTIME_USED
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
int32_t Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int bufferSize);
|
int32_t Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int32_t bufferSize);
|
||||||
|
|
||||||
// Print to console string representation of an object.
|
// Print to console string representation of an object.
|
||||||
RUNTIME_USED
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
int32_t Konan_DebugPrint(KRef obj);
|
int32_t Konan_DebugPrint(KRef obj);
|
||||||
|
|
||||||
// Returns 1 if obj refers to an array, string or binary blob and 0 otherwise.
|
// Returns 1 if obj refers to an array, string or binary blob and 0 otherwise.
|
||||||
RUNTIME_USED int Konan_DebugIsArray(KRef obj);
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
int32_t Konan_DebugIsArray(KRef obj);
|
||||||
|
|
||||||
// Returns number of fields in an objects, or elements in an array.
|
// Returns number of fields in an objects, or elements in an array.
|
||||||
RUNTIME_USED int Konan_DebugGetFieldCount(KRef obj);
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
int32_t Konan_DebugGetFieldCount(KRef obj);
|
||||||
|
|
||||||
// Compute type of field or an array element at the index, or 0, if incorrect,
|
// Compute type of field or an array element at the index, or 0, if incorrect,
|
||||||
// see Konan_RuntimeType.
|
// see Konan_RuntimeType.
|
||||||
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index);
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
int32_t Konan_DebugGetFieldType(KRef obj, int32_t index);
|
||||||
|
|
||||||
// Compute address of field or an array element at the index, or null, if incorrect.
|
// Compute address of field or an array element at the index, or null, if incorrect.
|
||||||
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index);
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
void* Konan_DebugGetFieldAddress(KRef obj, int32_t index);
|
||||||
|
|
||||||
// Compute address of field or an array element at the index, or null, if incorrect.
|
// Compute address of field or an array element at the index, or null, if incorrect.
|
||||||
RUNTIME_USED const char* Konan_DebugGetFieldName(KRef obj, int index);
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
const char* Konan_DebugGetFieldName(KRef obj, int32_t index);
|
||||||
|
|
||||||
// Returns name of type.
|
// Returns name of type.
|
||||||
RUNTIME_USED const char* Konan_DebugGetTypeName(KRef obj);
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
const char* Konan_DebugGetTypeName(KRef obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an object finds debugger interface operation suitable for manipulation with this object.
|
||||||
|
* Important for cases where multiple K/N runtimes coexist in the same address space and debugger
|
||||||
|
* doesn't know which debug operation to use on particular instance.
|
||||||
|
*/
|
||||||
|
RUNTIME_USED RUNTIME_WEAK
|
||||||
|
void* Konan_DebugGetOperation(KRef obj, /* Konan_DebugOperation */ int32_t operation);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
// This function replaces `__cxa_demangle` defined in GNU libstdc++
|
// This function replaces `__cxa_demangle` defined in GNU libstdc++
|
||||||
// by adding `--defsym` flag in `konan.properties`.
|
// by adding `--defsym` flag in `konan.properties`.
|
||||||
// This allows to avoid linking `__cxa_demangle` and its dependencies, thus reducing binary size.
|
// This allows to avoid linking `__cxa_demangle` and its dependencies, thus reducing binary size.
|
||||||
RUNTIME_USED extern "C" char* Konan_cxa_demangle(
|
RUNTIME_USED RUNTIME_WEAK extern "C" char* Konan_cxa_demangle(
|
||||||
const char* __mangled_name, char* __output_buffer,
|
const char* __mangled_name, char* __output_buffer,
|
||||||
size_t* __length, int* __status
|
size_t* __length, int* __status
|
||||||
) {
|
) {
|
||||||
@@ -31,9 +31,10 @@ RUNTIME_USED extern "C" char* Konan_cxa_demangle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
void __throw_length_error(const char* __s __attribute__((unused))) {
|
void __throw_length_error(const char* __s __attribute__((unused))) {
|
||||||
RuntimeAssert(false, __s);
|
RuntimeAssert(false, __s);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
#endif // KONAN_LINUX || KONAN_WINDOWS
|
#endif // KONAN_LINUX || KONAN_WINDOWS
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ enum Konan_RuntimeType {
|
|||||||
RT_FLOAT32 = 6,
|
RT_FLOAT32 = 6,
|
||||||
RT_FLOAT64 = 7,
|
RT_FLOAT64 = 7,
|
||||||
RT_NATIVE_PTR = 8,
|
RT_NATIVE_PTR = 8,
|
||||||
RT_BOOLEAN = 9
|
RT_BOOLEAN = 9,
|
||||||
|
RT_VECTOR128 = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flags per type.
|
// Flags per type.
|
||||||
@@ -77,7 +78,10 @@ struct ExtendedTypeInfo {
|
|||||||
const uint8_t* fieldTypes_;
|
const uint8_t* fieldTypes_;
|
||||||
// Names of all fields.
|
// Names of all fields.
|
||||||
const char** fieldNames_;
|
const char** fieldNames_;
|
||||||
// TODO: do we want any other info here?
|
// Number of supported debug operations.
|
||||||
|
int32_t debugOperationsCount_;
|
||||||
|
// Table of supported debug operations functions.
|
||||||
|
void** debugOperations_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void const* VTableElement;
|
typedef void const* VTableElement;
|
||||||
|
|||||||
Reference in New Issue
Block a user