From c6ac807034f9ef8cf61b69e53b4dea7eb76ae754 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Mon, 3 Dec 2018 12:39:47 +0300 Subject: [PATCH] Get rid of uneeded parts of RTTI. (#2435) --- .../backend/konan/llvm/RTTIGenerator.kt | 48 +++++-------------- .../kotlin/backend/konan/llvm/Runtime.kt | 1 - runtime/src/main/cpp/ObjCExport.mm | 4 -- runtime/src/main/cpp/TypeInfo.cpp | 28 ----------- runtime/src/main/cpp/TypeInfo.h | 27 +++-------- runtime/src/main/cpp/Types.cpp | 2 +- 6 files changed, 20 insertions(+), 90 deletions(-) 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 d2437e7f35d..617f5555ee0 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 @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.isAnnotationClass import org.jetbrains.kotlin.ir.util.isInterface +import org.jetbrains.kotlin.konan.KonanAbiVersion import org.jetbrains.kotlin.name.FqName internal class RTTIGenerator(override val context: Context) : ContextUtils { @@ -59,18 +60,17 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { result = result or TF_ACYCLIC } } + if (classDescriptor.isInterface) + result = result or TF_INTERFACE return result } - private inner class FieldTableRecord(val nameSignature: LocalHash, fieldOffset: Int) : - Struct(runtime.fieldTableRecordType, nameSignature, Int32(fieldOffset)) - inner class MethodTableRecord(val nameSignature: LocalHash, methodEntryPoint: ConstPointer?) : Struct(runtime.methodTableRecordType, nameSignature, methodEntryPoint) private inner class TypeInfo( selfPtr: ConstPointer, - name: ConstValue, + extendedInfo: ConstPointer, size: Int, superType: ConstValue, objOffsets: ConstValue, @@ -79,12 +79,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { interfacesCount: Int, methods: ConstValue, methodsCount: Int, - fields: ConstValue, - fieldsCount: Int, packageName: String?, relativeName: String?, flags: Int, - extendedInfo: ConstPointer, writableTypeInfo: ConstPointer?) : Struct( @@ -92,7 +89,10 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { selfPtr, - name, + extendedInfo, + + Int32(KonanAbiVersion.CURRENT.version), + Int32(size), superType, @@ -106,16 +106,11 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { methods, Int32(methodsCount), - fields, - Int32(fieldsCount), - kotlinStringLiteral(packageName), kotlinStringLiteral(relativeName), Int32(flags), - extendedInfo, - *listOfNotNull(writableTypeInfo).toTypedArray() ) @@ -180,8 +175,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { val bodyType = llvmDeclarations.bodyType - val name = className.globalHash - val size = getInstanceSize(bodyType, className) val superTypeOrAny = classDesc.getSuperClassNotAny() ?: context.ir.symbols.any.owner @@ -192,7 +185,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { val interfacesPtr = staticData.placeGlobalConstArray("kintf:$className", pointerType(runtime.typeInfoType), interfaces) - // TODO: reuse offsets obtained for 'fields' below val objOffsets = getStructElements(bodyType).mapIndexedNotNull { index, type -> if (isObjectType(type)) { LLVMOffsetOfElement(llvmTargetData, bodyType, index) @@ -210,16 +202,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { objOffsets.size } - val fields = llvmDeclarations.fields.mapIndexed { index, field -> - // Note: using FQ name because a class may have multiple fields with the same name due to property overriding - val nameSignature = field.fqNameSafe.localHash // FIXME: add signature - val fieldOffset = LLVMOffsetOfElement(llvmTargetData, bodyType, index) - FieldTableRecord(nameSignature, fieldOffset.toInt()) - }.sortedBy { it.nameSignature.value } - - val fieldsPtr = staticData.placeGlobalConstArray("kfields:$className", - runtime.fieldTableRecordType, fields) - val methods = if (classDesc.isAbstract()) { emptyList() } else { @@ -233,17 +215,15 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { val typeInfoGlobal = llvmDeclarations.typeInfoGlobal val typeInfo = TypeInfo( classDesc.typeInfoPtr, - name, + makeExtendedInfo(classDesc), size, superType, objOffsetsPtr, objOffsetsCount, interfacesPtr, interfaces.size, methodsPtr, methods.size, - fieldsPtr, if (classDesc.isInterface) -1 else fields.size, reflectionInfo.packageName, reflectionInfo.relativeName, flagsFromClass(classDesc), - makeExtendedInfo(classDesc), llvmDeclarations.writableTypeInfoGlobal?.pointer ) @@ -335,8 +315,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { ): ConstPointer { assert(descriptor.isInterface) - val name = "".globalHash - val size = 0 val superClass = context.ir.symbols.any.owner @@ -349,8 +327,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { assert(superClass.declarations.all { it !is IrProperty && it !is IrField }) val objOffsetsPtr = NullPointer(int32Type) val objOffsetsCount = 0 - val fieldsPtr = NullPointer(runtime.fieldTableRecordType) - val fieldsCount = 0 val methods = (methodTableRecords(superClass) + methodImpls.map { (method, impl) -> assert(method.containingDeclaration == descriptor) @@ -377,17 +353,15 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { val result = typeInfoWithVtableGlobal.pointer.getElementPtr(0) val typeInfoWithVtable = Struct(TypeInfo( selfPtr = result, - name = name, + extendedInfo = NullPointer(runtime.extendedTypeInfoType), size = size, superType = superClass.typeInfoPtr, objOffsets = objOffsetsPtr, objOffsetsCount = objOffsetsCount, interfaces = interfacesPtr, interfacesCount = interfaces.size, methods = methodsPtr, methodsCount = methods.size, - fields = fieldsPtr, fieldsCount = fieldsCount, packageName = reflectionInfo.packageName, relativeName = reflectionInfo.relativeName, flags = flagsFromClass(descriptor) or (if (immutable) TF_IMMUTABLE else 0), - extendedInfo = NullPointer(runtime.extendedTypeInfoType), writableTypeInfo = writableTypeInfo ), vtable) @@ -417,5 +391,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { } } +// Keep in sync with Konan_TypeFlags in TypeInfo.h. private const val TF_IMMUTABLE = 1 private const val TF_ACYCLIC = 2 +private const val TF_INTERFACE = 4 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt index 90370779811..762aade9896 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt @@ -22,7 +22,6 @@ class Runtime(bitcodeFile: String) { val typeInfoType = getStructType("TypeInfo") val extendedTypeInfoType = getStructType("ExtendedTypeInfo") val writableTypeInfoType = getStructTypeOrNull("WritableTypeInfo") - val fieldTableRecordType = getStructType("FieldTableRecord") val methodTableRecordType = getStructType("MethodTableRecord") val globalHashType = getStructType("GlobalHash") diff --git a/runtime/src/main/cpp/ObjCExport.mm b/runtime/src/main/cpp/ObjCExport.mm index 90a6d319d36..9f85804acc2 100644 --- a/runtime/src/main/cpp/ObjCExport.mm +++ b/runtime/src/main/cpp/ObjCExport.mm @@ -671,7 +671,6 @@ static const TypeInfo* createTypeInfo( result->flags_ = 0; - MakeGlobalHash(nullptr, 0, &result->name_); result->instanceSize_ = superType->instanceSize_; result->superType_ = superType; result->objOffsets_ = superType->objOffsets_; @@ -705,9 +704,6 @@ static const TypeInfo* createTypeInfo( result->openMethods_ = openMethods_; result->openMethodsCount_ = methodTable.size(); - result->fields_ = nullptr; - result->fieldsCount_ = 0; - result->packageName_ = nullptr; result->relativeName_ = nullptr; // TODO: add some info. result->writableInfo_ = (WritableTypeInfo*)konanAllocMemory(sizeof(WritableTypeInfo)); diff --git a/runtime/src/main/cpp/TypeInfo.cpp b/runtime/src/main/cpp/TypeInfo.cpp index d1f52d1aca6..60262ea6072 100644 --- a/runtime/src/main/cpp/TypeInfo.cpp +++ b/runtime/src/main/cpp/TypeInfo.cpp @@ -24,24 +24,6 @@ extern "C" { #if USE_BINARY_SEARCH -int LookupFieldOffset(const TypeInfo* info, FieldNameHash nameSignature) { - int bottom = 0; - int top = info->fieldsCount_ - 1; - - while (bottom <= top) { - int middle = (bottom + top) / 2; - if (info->fields_[middle].nameSignature_ < nameSignature) - bottom = middle + 1; - else if (info->fields_[middle].nameSignature_ == nameSignature) - return info->fields_[middle].fieldOffset_; - else - top = middle - 1; - } - - RuntimeAssert(false, "Unknown field"); - return -1; -} - void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) { int bottom = 0; int top = info->openMethodsCount_ - 1; @@ -62,16 +44,6 @@ void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) { #else -int LookupFieldOffset(const TypeInfo* info, FieldNameHash nameSignature) { - for (int i = 0; i < info->fieldsCount_; ++i) { - if (info->fields_[i].nameSignature_ == nameSignature) { - return info->fields_[i].fieldOffset_; - } - } - RuntimeAssert(false, "Unknown field"); - return -1; -} - void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) { for (int i = 0; i < info->openMethodsCount_; ++i) { if (info->openMethods_[i].nameSignature_ == nameSignature) { diff --git a/runtime/src/main/cpp/TypeInfo.h b/runtime/src/main/cpp/TypeInfo.h index bd2e51832d7..5b1873ebc56 100644 --- a/runtime/src/main/cpp/TypeInfo.h +++ b/runtime/src/main/cpp/TypeInfo.h @@ -36,12 +36,6 @@ struct MethodTableRecord { void* methodEntryPoint_; }; -// An element of sorted by hash in-place array representing field offsets. -struct FieldTableRecord { - FieldNameHash nameSignature_; - int fieldOffset_; -}; - // Type for runtime representation of Konan object. // Keep in sync with runtimeTypeMap in RTTIGenerator. enum Konan_RuntimeType { @@ -59,7 +53,8 @@ enum Konan_RuntimeType { enum Konan_TypeFlags { TF_IMMUTABLE = 1 << 0, - TF_ACYCLIC = 1 << 1 + TF_ACYCLIC = 1 << 1, + TF_INTERFACE = 1 << 2 }; enum Konan_MetaFlags { @@ -84,8 +79,10 @@ struct ExtendedTypeInfo { struct TypeInfo { // Reference to self, to allow simple obtaining TypeInfo via meta-object. const TypeInfo* typeInfo_; - // Hash of class name. - ClassNameHash name_; + // Extended RTTI, to retain cross-version debuggability, since ABI version 5 shall always be at the second position. + const ExtendedTypeInfo* extendedInfo_; + // ABI version. + uint32_t abiVersion_; // Negative value marks array class/string, and it is negated element size. int32_t instanceSize_; // Must be pointer to Any for array classes, and null for Any. @@ -100,9 +97,6 @@ struct TypeInfo { // Null for abstract classes and interfaces. const MethodTableRecord* openMethods_; uint32_t openMethodsCount_; - const FieldTableRecord* fields_; - // Is negative to mark an interface. - int32_t fieldsCount_; // String for the fully qualified dot-separated name of the package containing class, // or `null` if the class is local or anonymous. @@ -116,9 +110,6 @@ struct TypeInfo { // Various flags. int32_t flags_; - // Extended RTTI. - const ExtendedTypeInfo* extendedInfo_; - #if KONAN_TYPE_INFO_HAS_WRITABLE_PART WritableTypeInfo* writableInfo_; #endif @@ -139,16 +130,12 @@ struct TypeInfo { #ifdef __cplusplus extern "C" { #endif -// Find offset of given hash in table. +// Find open method by its hash. Other methods are resolved in compile-time. // Note, that we use attribute const, which assumes function doesn't // dereference global memory, while this function does. However, it seems // to be safe, as actual result of this computation depends only on 'type_info' // and 'hash' numeric values and doesn't really depends on global memory state // (as TypeInfo is compile time constant and type info pointers are stable). -int LookupFieldOffset(const TypeInfo* type_info, FieldNameHash hash) RUNTIME_CONST; - -// Find open method by its hash. Other methods are resolved in compile-time. -// See comment in LookupFieldOffset(). void* LookupOpenMethod(const TypeInfo* info, MethodNameHash nameSignature) RUNTIME_CONST; #ifdef __cplusplus diff --git a/runtime/src/main/cpp/Types.cpp b/runtime/src/main/cpp/Types.cpp index b5d84d94826..884bd5c44b0 100644 --- a/runtime/src/main/cpp/Types.cpp +++ b/runtime/src/main/cpp/Types.cpp @@ -24,7 +24,7 @@ KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) { RuntimeAssert(obj != nullptr, "must not be null"); const TypeInfo* obj_type_info = obj->type_info(); // If it is an interface - check in list of implemented interfaces. - if (type_info->fieldsCount_ < 0) { + if ((type_info->flags_ & TF_INTERFACE) != 0) { for (int i = 0; i < obj_type_info->implementedInterfacesCount_; ++i) { if (obj_type_info->implementedInterfaces_[i] == type_info) { return 1;