Additional RTTI for debugging. (#1568)
This commit is contained in:
+15
-31
@@ -351,47 +351,31 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
printBitCode()
|
printBitCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldVerifyDescriptors(): Boolean {
|
fun shouldVerifyDescriptors() = config.configuration.getBoolean(KonanConfigKeys.VERIFY_DESCRIPTORS)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.VERIFY_DESCRIPTORS)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldVerifyIr(): Boolean {
|
fun shouldVerifyIr() = config.configuration.getBoolean(KonanConfigKeys.VERIFY_IR)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.VERIFY_IR)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldVerifyBitCode(): Boolean {
|
fun shouldVerifyBitCode() = config.configuration.getBoolean(KonanConfigKeys.VERIFY_BITCODE)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.VERIFY_BITCODE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldPrintDescriptors(): Boolean {
|
fun shouldPrintDescriptors() = config.configuration.getBoolean(KonanConfigKeys.PRINT_DESCRIPTORS)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.PRINT_DESCRIPTORS)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldPrintIr(): Boolean {
|
fun shouldPrintIr() = config.configuration.getBoolean(KonanConfigKeys.PRINT_IR)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.PRINT_IR)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldPrintIrWithDescriptors(): Boolean {
|
fun shouldPrintIrWithDescriptors()=
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.PRINT_IR_WITH_DESCRIPTORS)
|
config.configuration.getBoolean(KonanConfigKeys.PRINT_IR_WITH_DESCRIPTORS)
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldPrintBitCode(): Boolean {
|
fun shouldPrintBitCode() = config.configuration.getBoolean(KonanConfigKeys.PRINT_BITCODE)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.PRINT_BITCODE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldPrintLocations(): Boolean {
|
fun shouldPrintLocations() = config.configuration.getBoolean(KonanConfigKeys.PRINT_LOCATIONS)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.PRINT_LOCATIONS)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldProfilePhases(): Boolean {
|
fun shouldProfilePhases() = config.configuration.getBoolean(KonanConfigKeys.TIME_PHASES)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.TIME_PHASES)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldContainDebugInfo(): Boolean {
|
fun shouldContainDebugInfo() = config.configuration.getBoolean(KonanConfigKeys.DEBUG)
|
||||||
return config.configuration.getBoolean(KonanConfigKeys.DEBUG)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldGenerateTestRunner(): Boolean = config.configuration.getBoolean(KonanConfigKeys.GENERATE_TEST_RUNNER)
|
fun shouldOptimize() = config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION)
|
||||||
|
|
||||||
|
fun shouldGenerateTestRunner() =
|
||||||
|
config.configuration.getBoolean(KonanConfigKeys.GENERATE_TEST_RUNNER)
|
||||||
|
|
||||||
override fun log(message: () -> String) {
|
override fun log(message: () -> String) {
|
||||||
if (phase?.verbose ?: false) {
|
if (phase?.verbose ?: false) {
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ internal class LinkStage(val context: Context) {
|
|||||||
private val platform = context.config.platform
|
private val platform = context.config.platform
|
||||||
private val linker = platform.linker
|
private val linker = platform.linker
|
||||||
|
|
||||||
private val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
|
private val optimize = context.shouldOptimize()
|
||||||
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
|
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
|
||||||
private val linkerOutput = when (context.config.produce) {
|
private val linkerOutput = when (context.config.produce) {
|
||||||
CompilerOutputKind.DYNAMIC, CompilerOutputKind.FRAMEWORK -> LinkerOutputKind.DYNAMIC_LIBRARY
|
CompilerOutputKind.DYNAMIC, CompilerOutputKind.FRAMEWORK -> LinkerOutputKind.DYNAMIC_LIBRARY
|
||||||
|
|||||||
+2
-1
@@ -416,7 +416,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
LLVMAddFunction(context.llvmModule, symbolName, llvmFunctionType)!!
|
LLVMAddFunction(context.llvmModule, symbolName, llvmFunctionType)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION)) {
|
// TODO: do we still need it?
|
||||||
|
if (!context.shouldOptimize()) {
|
||||||
LLVMAddTargetDependentFunctionAttr(llvmFunction, "no-frame-pointer-elim", "true")
|
LLVMAddTargetDependentFunctionAttr(llvmFunction, "no-frame-pointer-elim", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+71
-14
@@ -50,6 +50,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
fieldsCount: Int,
|
fieldsCount: Int,
|
||||||
packageName: String?,
|
packageName: String?,
|
||||||
relativeName: String?,
|
relativeName: String?,
|
||||||
|
extendedInfo: ConstPointer,
|
||||||
writableTypeInfo: ConstPointer?) :
|
writableTypeInfo: ConstPointer?) :
|
||||||
|
|
||||||
Struct(
|
Struct(
|
||||||
@@ -77,6 +78,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
kotlinStringLiteral(packageName),
|
kotlinStringLiteral(packageName),
|
||||||
kotlinStringLiteral(relativeName),
|
kotlinStringLiteral(relativeName),
|
||||||
|
|
||||||
|
extendedInfo,
|
||||||
|
|
||||||
*listOfNotNull(writableTypeInfo).toTypedArray()
|
*listOfNotNull(writableTypeInfo).toTypedArray()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,22 +100,36 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val arrayClasses = mapOf(
|
private val arrayClasses = mapOf(
|
||||||
"kotlin.Array" to -LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt(),
|
"kotlin.Array" to kObjHeaderPtr,
|
||||||
"kotlin.ByteArray" to -1,
|
"kotlin.ByteArray" to LLVMInt8Type()!!,
|
||||||
"kotlin.CharArray" to -2,
|
"kotlin.CharArray" to LLVMInt16Type()!!,
|
||||||
"kotlin.ShortArray" to -2,
|
"kotlin.ShortArray" to LLVMInt16Type()!!,
|
||||||
"kotlin.IntArray" to -4,
|
"kotlin.IntArray" to LLVMInt32Type()!!,
|
||||||
"kotlin.LongArray" to -8,
|
"kotlin.LongArray" to LLVMInt64Type()!!,
|
||||||
"kotlin.FloatArray" to -4,
|
"kotlin.FloatArray" to LLVMFloatType()!!,
|
||||||
"kotlin.DoubleArray" to -8,
|
"kotlin.DoubleArray" to LLVMDoubleType()!!,
|
||||||
"kotlin.BooleanArray" to -1,
|
"kotlin.BooleanArray" to LLVMInt8Type()!!,
|
||||||
"kotlin.String" to -2,
|
"kotlin.String" to LLVMInt16Type()!!,
|
||||||
"konan.ImmutableBinaryBlob" to -1
|
"konan.ImmutableBinaryBlob" to LLVMInt8Type()!!
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keep in sync with Konan_RuntimeType.
|
||||||
|
private val runtimeTypeMap = mapOf(
|
||||||
|
kObjHeaderPtr to 1,
|
||||||
|
LLVMInt8Type()!! to 2,
|
||||||
|
LLVMInt16Type()!! to 3,
|
||||||
|
LLVMInt32Type()!! to 4,
|
||||||
|
LLVMInt64Type()!! to 5,
|
||||||
|
LLVMFloatType()!! to 6,
|
||||||
|
LLVMDoubleType()!! to 7,
|
||||||
|
kInt8Ptr to 8,
|
||||||
|
LLVMInt1Type()!! to 9
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getInstanceSize(classType: LLVMTypeRef?, className: FqName) : Int {
|
private fun getInstanceSize(classType: LLVMTypeRef?, className: FqName) : Int {
|
||||||
val arraySize = arrayClasses.get(className.asString());
|
val elementType = arrayClasses.get(className.asString())
|
||||||
if (arraySize != null) return arraySize;
|
// Check if it is an array.
|
||||||
|
if (elementType != null) return -LLVMABISizeOfType(llvmTargetData, elementType).toInt()
|
||||||
return LLVMStoreSizeOfType(llvmTargetData, classType).toInt()
|
return LLVMStoreSizeOfType(llvmTargetData, classType).toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,6 +197,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
fieldsPtr, if (classDesc.isInterface) -1 else fields.size,
|
fieldsPtr, if (classDesc.isInterface) -1 else fields.size,
|
||||||
reflectionInfo.packageName,
|
reflectionInfo.packageName,
|
||||||
reflectionInfo.relativeName,
|
reflectionInfo.relativeName,
|
||||||
|
makeExtendedInfo(classDesc),
|
||||||
llvmDeclarations.writableTypeInfoGlobal?.pointer
|
llvmDeclarations.writableTypeInfoGlobal?.pointer
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -225,7 +243,45 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
}.sortedBy { it.nameSignature.value }
|
}.sortedBy { it.nameSignature.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: extract more code common with generate()
|
private fun mapRuntimeType(type: LLVMTypeRef): Int =
|
||||||
|
runtimeTypeMap[type] ?: throw Error("Unmapped type: ${llvmtype2string(type)}")
|
||||||
|
|
||||||
|
private fun makeExtendedInfo(descriptor: ClassDescriptor): ConstPointer {
|
||||||
|
// TODO: shall we actually do that?
|
||||||
|
if (context.shouldOptimize())
|
||||||
|
return NullPointer(runtime.extendedTypeInfoType)
|
||||||
|
|
||||||
|
val className = descriptor.fqNameSafe.toString()
|
||||||
|
val llvmDeclarations = context.llvmDeclarations.forClass(descriptor)
|
||||||
|
val bodyType = llvmDeclarations.bodyType
|
||||||
|
val elementType = arrayClasses[className]
|
||||||
|
val value = if (elementType != null) {
|
||||||
|
// An array type.
|
||||||
|
val runtimeElementType = mapRuntimeType(elementType)
|
||||||
|
Struct(runtime.extendedTypeInfoType,
|
||||||
|
Int32(-runtimeElementType),
|
||||||
|
NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr))
|
||||||
|
} else {
|
||||||
|
data class FieldRecord(val offset: Int, val type: Int, val name: String)
|
||||||
|
val fields = getStructElements(bodyType).mapIndexedNotNull { index, type ->
|
||||||
|
FieldRecord(
|
||||||
|
LLVMOffsetOfElement(llvmTargetData, bodyType, index).toInt(),
|
||||||
|
mapRuntimeType(type),
|
||||||
|
llvmDeclarations.fields[index].name.asString())
|
||||||
|
}
|
||||||
|
val offsetsPtr = staticData.placeGlobalConstArray("kextoff:$className", int32Type,
|
||||||
|
fields.map { Int32(it.offset) })
|
||||||
|
val typesPtr = staticData.placeGlobalConstArray("kexttype:$className", int8Type,
|
||||||
|
fields.map { Int8(it.type.toByte()) })
|
||||||
|
val namesPtr = staticData.placeGlobalConstArray("kextname:$className", kInt8Ptr,
|
||||||
|
fields.map { staticData.placeCStringLiteral(it.name) })
|
||||||
|
Struct(runtime.extendedTypeInfoType, Int32(fields.size), offsetsPtr, typesPtr, namesPtr)
|
||||||
|
}
|
||||||
|
val result = staticData.placeGlobal("", value)
|
||||||
|
return result.pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: extract more code common with generate().
|
||||||
fun generateSyntheticInterfaceImpl(
|
fun generateSyntheticInterfaceImpl(
|
||||||
descriptor: ClassDescriptor,
|
descriptor: ClassDescriptor,
|
||||||
methodImpls: Map<FunctionDescriptor, ConstPointer>
|
methodImpls: Map<FunctionDescriptor, ConstPointer>
|
||||||
@@ -283,6 +339,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
|||||||
fields = fieldsPtr, fieldsCount = fieldsCount,
|
fields = fieldsPtr, fieldsCount = fieldsCount,
|
||||||
packageName = reflectionInfo.packageName,
|
packageName = reflectionInfo.packageName,
|
||||||
relativeName = reflectionInfo.relativeName,
|
relativeName = reflectionInfo.relativeName,
|
||||||
|
extendedInfo = NullPointer(runtime.extendedTypeInfoType),
|
||||||
writableTypeInfo = writableTypeInfo
|
writableTypeInfo = writableTypeInfo
|
||||||
), vtable)
|
), vtable)
|
||||||
|
|
||||||
|
|||||||
+1
@@ -34,6 +34,7 @@ class Runtime(bitcodeFile: String) {
|
|||||||
?: throw Error("struct.$name is not found in the Runtime module.")
|
?: throw Error("struct.$name is not found in the Runtime module.")
|
||||||
|
|
||||||
val typeInfoType = getStructType("TypeInfo")
|
val typeInfoType = getStructType("TypeInfo")
|
||||||
|
val extendedTypeInfoType = getStructType("ExtendedTypeInfo")
|
||||||
val writableTypeInfoType = getStructTypeOrNull("WritableTypeInfo")
|
val writableTypeInfoType = getStructTypeOrNull("WritableTypeInfo")
|
||||||
val fieldTableRecordType = getStructType("FieldTableRecord")
|
val fieldTableRecordType = getStructType("FieldTableRecord")
|
||||||
val methodTableRecordType = getStructType("MethodTableRecord")
|
val methodTableRecordType = getStructType("MethodTableRecord")
|
||||||
|
|||||||
+1
-1
@@ -911,7 +911,7 @@ internal object Devirtualization {
|
|||||||
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
|
devirtualizedCallSites: Map<IrCall, DevirtualizedCallSite>) {
|
||||||
val nativePtrType = context.builtIns.nativePtr.defaultType
|
val nativePtrType = context.builtIns.nativePtr.defaultType
|
||||||
val nativePtrEqualityOperatorSymbol = context.ir.symbols.areEqualByValue.single { it.descriptor.valueParameters[0].type == nativePtrType }
|
val nativePtrEqualityOperatorSymbol = context.ir.symbols.areEqualByValue.single { it.descriptor.valueParameters[0].type == nativePtrType }
|
||||||
val optimize = context.config.configuration.get(KonanConfigKeys.OPTIMIZATION) ?: false
|
val optimize = context.shouldOptimize()
|
||||||
|
|
||||||
irModule.transformChildrenVoid(object: IrElementTransformerVoidWithContext() {
|
irModule.transformChildrenVoid(object: IrElementTransformerVoidWithContext() {
|
||||||
override fun visitCall(expression: IrCall): IrExpression {
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
|||||||
@@ -32,6 +32,19 @@ namespace {
|
|||||||
|
|
||||||
char debugBuffer[4096];
|
char debugBuffer[4096];
|
||||||
|
|
||||||
|
constexpr int runtimeTypeSize[] = {
|
||||||
|
-1, // INVALID
|
||||||
|
sizeof(ObjHeader*), // OBJECT
|
||||||
|
1, // INT8
|
||||||
|
2, // INT16
|
||||||
|
4, // INT32
|
||||||
|
8, // INT64
|
||||||
|
4, // FLOAT32
|
||||||
|
8, // FLOAT64
|
||||||
|
sizeof(void*), // NATIVE_PTR
|
||||||
|
1 // BOOLEAN
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -63,39 +76,88 @@ RUNTIME_USED KInt Konan_DebugPrint(KRef obj) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index) {
|
RUNTIME_USED int Konan_DebugIsArray(KRef obj) {
|
||||||
if (obj == nullptr || index < 0) return Konan_RuntimeType::INVALID;
|
return obj == nullptr || IsArray(obj) ? 1 : 0;
|
||||||
auto typeInfo = obj->type_info();
|
}
|
||||||
if (typeInfo->instanceSize_ < 0) {
|
|
||||||
// Arrays.
|
|
||||||
if (index >= obj->array()->count_) return Konan_RuntimeType::INVALID;
|
|
||||||
if (typeInfo == theArrayTypeInfo) {
|
|
||||||
return Konan_RuntimeType::OBJECT;
|
|
||||||
}
|
|
||||||
// TODO: support other array types.
|
|
||||||
return Konan_RuntimeType::INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: support primitive type fields as well!
|
RUNTIME_USED int Konan_DebugGetFieldCount(KRef obj) {
|
||||||
if (index >= typeInfo->objOffsetsCount_) return Konan_RuntimeType::INVALID;
|
if (obj == nullptr)
|
||||||
return Konan_RuntimeType::OBJECT;
|
return 0;
|
||||||
|
|
||||||
|
auto typeInfo = obj->type_info();
|
||||||
|
auto extendedTypeInfo = typeInfo->extendedInfo_;
|
||||||
|
|
||||||
|
if (extendedTypeInfo == nullptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (IsArray(obj))
|
||||||
|
return obj->array()->count_;
|
||||||
|
|
||||||
|
return extendedTypeInfo->fieldsCount_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index) {
|
||||||
|
if (obj == nullptr || index < 0)
|
||||||
|
return Konan_RuntimeType::RT_INVALID;
|
||||||
|
|
||||||
|
auto typeInfo = obj->type_info();
|
||||||
|
auto extendedTypeInfo = typeInfo->extendedInfo_;
|
||||||
|
|
||||||
|
if (extendedTypeInfo == nullptr)
|
||||||
|
return Konan_RuntimeType::RT_INVALID;
|
||||||
|
|
||||||
|
if (extendedTypeInfo->fieldsCount_ < 0)
|
||||||
|
return -typeInfo->fieldsCount_;
|
||||||
|
|
||||||
|
if (index >= extendedTypeInfo->fieldsCount_)
|
||||||
|
return Konan_RuntimeType::RT_INVALID;
|
||||||
|
|
||||||
|
return extendedTypeInfo->fieldTypes_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
|
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
|
||||||
if (obj == nullptr || index < 0) return nullptr;
|
if (obj == nullptr || index < 0)
|
||||||
auto typeInfo = obj->type_info();
|
|
||||||
if (typeInfo->instanceSize_ < 0) {
|
|
||||||
// Arrays.
|
|
||||||
if (index >= obj->array()->count_) return nullptr;
|
|
||||||
if (typeInfo == theArrayTypeInfo) {
|
|
||||||
return ArrayAddressOfElementAt(obj->array(), index);
|
|
||||||
}
|
|
||||||
// TODO: support other array types.
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
// TODO: support primitive type fields as well!
|
auto typeInfo = obj->type_info();
|
||||||
if (index >= typeInfo->objOffsetsCount_) return nullptr;
|
auto extendedTypeInfo = typeInfo->extendedInfo_;
|
||||||
return reinterpret_cast<uint8_t*>(obj + 1) + typeInfo->objOffsets_[index];
|
|
||||||
|
if (extendedTypeInfo == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (extendedTypeInfo->fieldsCount_ < 0) {
|
||||||
|
if (index >= obj->array()->count_)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return reinterpret_cast<uint8_t*>(obj + 1) + index * runtimeTypeSize[-typeInfo->fieldsCount_];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= extendedTypeInfo->fieldsCount_)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return reinterpret_cast<uint8_t*>(obj + 1) + extendedTypeInfo->fieldOffsets_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
if (obj == nullptr || index < 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto typeInfo = obj->type_info();
|
||||||
|
auto extendedTypeInfo = typeInfo->extendedInfo_;
|
||||||
|
|
||||||
|
if (extendedTypeInfo == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// For arrays, field name makes not much sense.
|
||||||
|
if (extendedTypeInfo->fieldsCount_ < 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (index >= extendedTypeInfo->fieldsCount_)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return extendedTypeInfo->fieldNames_[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -24,18 +24,6 @@
|
|||||||
|
|
||||||
#ifndef KONAN_NO_DEBUG_API
|
#ifndef KONAN_NO_DEBUG_API
|
||||||
|
|
||||||
// Type for runtime representation of Konan object.
|
|
||||||
enum Konan_RuntimeType {
|
|
||||||
INVALID = 0,
|
|
||||||
OBJECT = 1,
|
|
||||||
INT8 = 2,
|
|
||||||
INT16 = 3,
|
|
||||||
INT32 = 4,
|
|
||||||
INT64 = 5,
|
|
||||||
FLOAT32 = 6,
|
|
||||||
FLOAT64 = 7
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -46,25 +34,32 @@ char* Konan_DebugBuffer();
|
|||||||
|
|
||||||
// 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
|
||||||
int Konan_DebugBufferSize();
|
int32_t Konan_DebugBufferSize();
|
||||||
|
|
||||||
// Put string representation of an object to the provided buffer.
|
// Put string representation of an object to the provided buffer.
|
||||||
RUNTIME_USED
|
RUNTIME_USED
|
||||||
int Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int bufferSize);
|
int32_t Konan_DebugObjectToUtf8Array(KRef obj, char* buffer, int bufferSize);
|
||||||
|
|
||||||
// Print to console string representation of an object.
|
// Print to console string representation of an object.
|
||||||
RUNTIME_USED
|
RUNTIME_USED
|
||||||
int 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.
|
||||||
|
RUNTIME_USED int Konan_DebugIsArray(KRef obj);
|
||||||
|
|
||||||
|
// Returns number of fields in an objects, or elements in an array.
|
||||||
|
RUNTIME_USED int 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.
|
||||||
// TODO: currently, only object fields are supported, will be fixed soon.
|
|
||||||
RUNTIME_USED int Konan_DebugGetFieldType(KRef obj, int index);
|
RUNTIME_USED int Konan_DebugGetFieldType(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.
|
||||||
// TODO: currently, only object fields are supported, will be fixed soon.
|
|
||||||
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index);
|
RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -42,6 +42,34 @@ struct FieldTableRecord {
|
|||||||
int fieldOffset_;
|
int fieldOffset_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Type for runtime representation of Konan object.
|
||||||
|
// Keep in sync with runtimeTypeMap in RTTIGenerator.
|
||||||
|
enum Konan_RuntimeType {
|
||||||
|
RT_INVALID = 0,
|
||||||
|
RT_OBJECT = 1,
|
||||||
|
RT_INT8 = 2,
|
||||||
|
RT_INT16 = 3,
|
||||||
|
RT_INT32 = 4,
|
||||||
|
RT_INT64 = 5,
|
||||||
|
RT_FLOAT32 = 6,
|
||||||
|
RT_FLOAT64 = 7,
|
||||||
|
RT_NATIVE_PTR = 8,
|
||||||
|
RT_BOOLEAN = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extended information about a type.
|
||||||
|
struct ExtendedTypeInfo {
|
||||||
|
// Number of fields (negated Konan_RuntimeType for array types).
|
||||||
|
int32_t fieldsCount_;
|
||||||
|
// Offsets of all fields.
|
||||||
|
const int32_t* fieldOffsets_;
|
||||||
|
// Types of all fields.
|
||||||
|
const uint8_t* fieldTypes_;
|
||||||
|
// Names of all fields.
|
||||||
|
const char** fieldNames_;
|
||||||
|
// TODO: do we want any other info here?
|
||||||
|
};
|
||||||
|
|
||||||
// This struct represents runtime type information and by itself is the compile time
|
// This struct represents runtime type information and by itself is the compile time
|
||||||
// constant.
|
// constant.
|
||||||
struct TypeInfo {
|
struct TypeInfo {
|
||||||
@@ -74,6 +102,9 @@ struct TypeInfo {
|
|||||||
// or `null` if the class is anonymous.
|
// or `null` if the class is anonymous.
|
||||||
ObjHeader* relativeName_;
|
ObjHeader* relativeName_;
|
||||||
|
|
||||||
|
// Extended RTTI.
|
||||||
|
const ExtendedTypeInfo* extendedInfo_;
|
||||||
|
|
||||||
#if KONAN_TYPE_INFO_HAS_WRITABLE_PART
|
#if KONAN_TYPE_INFO_HAS_WRITABLE_PART
|
||||||
WritableTypeInfo* writableInfo_;
|
WritableTypeInfo* writableInfo_;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user