From 3eb7d32b21dbfba83e24409686b22de3e4c7197a Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Wed, 4 Aug 2021 23:17:57 +0500 Subject: [PATCH] [K/N][codegen] Reworked fields building --- .../kotlin/backend/konan/KonanFqNames.kt | 1 + .../konan/descriptors/ClassLayoutBuilder.kt | 45 ++++++++++++------- .../backend/konan/llvm/CodeGenerator.kt | 4 +- .../kotlin/backend/konan/llvm/ContextUtils.kt | 4 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 2 +- .../backend/konan/llvm/LlvmDeclarations.kt | 5 ++- .../backend/konan/llvm/RTTIGenerator.kt | 10 ++--- .../backend/konan/llvm/StaticObjects.kt | 6 +-- 8 files changed, 45 insertions(+), 32 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt index 30cce0a1ce5..baf2dcd08d6 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanFqNames.kt @@ -34,4 +34,5 @@ object KonanFqNames { val hasFreezeHook = FqName("kotlin.native.internal.HasFreezeHook") val gcUnsafeCall = FqName("kotlin.native.internal.GCUnsafeCall") val eagerInitialization = FqName("kotlin.native.EagerInitialization") + val noReorderFields = FqName("kotlin.native.internal.NoReorderFields") } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt index cab0bfa2f41..f7657f82d03 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.simpleFunctions import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.llvm.computeFunctionName -import org.jetbrains.kotlin.backend.konan.llvm.llvmType +import org.jetbrains.kotlin.backend.konan.llvm.getLLVMType import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.lower.InnerClassLowering import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget @@ -18,11 +18,12 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrClassReference +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid -import org.jetbrains.kotlin.name.FqName internal class OverriddenFunctionInfo( val function: IrSimpleFunction, @@ -392,15 +393,30 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va return context.getLayoutBuilder(superFunction.parentAsClass).itablePlace(superFunction) } + class FieldInfo(val name: String, val type: IrType, val isConst: Boolean, val hasConstInitializer: Boolean, val irField: IrField?) { + var index = -1 + } + /** * All fields of the class instance. * The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix. */ - val fields: List by lazy { - val superClass = irClass.getSuperClassNotAny() // TODO: what if Any has fields? + val fields: List by lazy { + val superClass = irClass.getSuperClassNotAny() val superFields = if (superClass != null) context.getLayoutBuilder(superClass).fields else emptyList() - superFields + getDeclaredFields() + val declaredFields = getDeclaredFields() + val sortedDeclaredFields = if (irClass.hasAnnotation(KonanFqNames.noReorderFields)) + declaredFields + else + declaredFields.sortedByDescending { + with(context.llvm) { LLVMStoreSizeOfType(runtime.targetData, getLLVMType(it.type)) } + } + + val superFieldsCount = 1 /* First field is ObjHeader */ + superFields.size + sortedDeclaredFields.forEachIndexed { index, field -> field.index = superFieldsCount + index } + + superFields + sortedDeclaredFields } val associatedObjects by lazy { @@ -441,10 +457,15 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va lateinit var hierarchyInfo: ClassGlobalHierarchyInfo + private fun IrField.toFieldInfo() = + FieldInfo(name.asString(), type, + correspondingPropertySymbol?.owner?.isConst ?: false, + initializer?.expression is IrConst<*>, this) + /** * Fields declared in the class. */ - private fun getDeclaredFields(): List { + fun getDeclaredFields(): List { val declarations: List = if (irClass.isInner && !isLowered) { // Note: copying to avoid mutation of the original class. irClass.declarations.toMutableList() @@ -452,19 +473,13 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va } else { irClass.declarations } - - val fields = declarations.mapNotNull { + return declarations.mapNotNull { when (it) { - is IrField -> it.takeIf { it.isReal } - is IrProperty -> it.takeIf { it.isReal }?.backingField + is IrField -> it.takeIf { it.isReal }?.toFieldInfo() + is IrProperty -> it.takeIf { it.isReal }?.backingField?.toFieldInfo() else -> null } } - - if (irClass.hasAnnotation(FqName.fromSegments(listOf("kotlin", "native", "internal", "NoReorderFields")))) - return fields - - return fields.sortedByDescending{ LLVMStoreSizeOfType(context.llvm.runtime.targetData, it.type.llvmType(context)) } } private val IrClass.overridableOrOverridingMethods: List diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 3427b062cab..1e03d59409c 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -43,7 +43,7 @@ internal fun IrClass.hasConstStateAndNoSideEffects(context: Context): Boolean { if (!context.shouldOptimize()) return false if (this.hasAnnotation(KonanFqNames.canBePrecreated)) return true val fields = context.getLayoutBuilder(this).fields - return fields.all { (it.correspondingPropertySymbol?.owner?.isConst ?: false) && (it.initializer?.expression is IrConst<*>) } && + return fields.all { it.isConst && it.hasConstInitializer } && this.constructors.all { it.isAutogeneratedSimpleConstructor(context) } } @@ -367,7 +367,7 @@ internal class StackLocalsManagerImpl( } else { val type = context.llvmDeclarations.forClass(stackLocal.irClass).bodyType for (field in context.getLayoutBuilder(stackLocal.irClass).fields) { - val fieldIndex = context.llvmDeclarations.forField(field).index + val fieldIndex = field.index val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!! if (isObjectType(fieldType)) { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 7bcacc06d41..622c2a89451 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -254,7 +254,7 @@ internal class InitializersGenerationState { && moduleGlobalInitializers.isEmpty() && moduleThreadLocalInitializers.isEmpty() } -internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { +internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : RuntimeAware { private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef { if (LLVMGetNamedFunction(llvmModule, name) != null) { @@ -462,7 +462,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { private val target = context.config.target val runtimeFile = context.config.distribution.runtime(target) - val runtime = Runtime(runtimeFile) // TODO: dispose + override val runtime = Runtime(runtimeFile) // TODO: dispose val targetTriple = runtime.target diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 30c1ea54476..8d0b66b91d5 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -924,7 +924,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { val fields = context.getLayoutBuilder(declaration).fields return Array(fields.size) { index -> - val initializer = fields[index].initializer!!.expression as IrConst<*> + val initializer = fields[index].irField!!.initializer!!.expression as IrConst<*> constValue(evaluateConst(initializer)) } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt index ec22e6b40f1..79b656c05ac 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt @@ -76,7 +76,7 @@ internal class StaticFieldLlvmDeclarations(val storageAddressAccess: AddressAcce internal class UniqueLlvmDeclarations(val pointer: ConstPointer) -private fun ContextUtils.createClassBodyType(name: String, fields: List): LLVMTypeRef { +private fun ContextUtils.createClassBodyType(name: String, fields: List): LLVMTypeRef { val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) } // TODO: consider adding synthetic ObjHeader field to Any. @@ -307,11 +307,12 @@ private class DeclarationsGeneratorVisitor(override val context: Context) : val classDeclarations = (containingClass.metadata as? CodegenClassMetadata)?.llvm ?: error(containingClass.descriptor.toString()) val allFields = context.getLayoutBuilder(containingClass).fields + val fieldInfo = allFields.firstOrNull { it.irField == declaration } ?: error("Field ${declaration.render()} is not found") declaration.metadata = CodegenInstanceFieldMetadata( declaration.metadata?.name, containingClass.konanLibrary, FieldLlvmDeclarations( - allFields.indexOf(declaration) + 1, // First field is ObjHeader. + fieldInfo.index, classDeclarations.bodyType ) ) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index 47d0c8df05f..5fa77413746 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -426,12 +426,12 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr), debugOperationsSize, debugOperations) } else { - data class FieldRecord(val offset: Int, val type: Int, val name: String) - val fields = getStructElements(bodyType).drop(1).mapIndexed { index, type -> + class FieldRecord(val offset: Int, val type: Int, val name: String) + val fields = context.getLayoutBuilder(irClass).fields.map { FieldRecord( - LLVMOffsetOfElement(llvmTargetData, bodyType, index + 1).toInt(), - mapRuntimeType(type), - context.getLayoutBuilder(irClass).fields[index].name.asString()) + LLVMOffsetOfElement(llvmTargetData, bodyType, it.index).toInt(), + mapRuntimeType(LLVMStructGetTypeAtIndex(bodyType, it.index)!!), + it.name) } val offsetsPtr = staticData.placeGlobalConstArray("kextoff:$className", int32Type, fields.map { Int32(it.offset) }) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt index 052543a1b73..28a956c29d8 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt @@ -92,11 +92,7 @@ internal fun StaticData.createConstArrayList(array: ConstPointer, length: Int): // Now sort these values according to the order of fields returned by getFields() // to match the sorting order of the real ArrayList(). - val sorted = mutableListOf() - context.getLayoutBuilder(arrayListClass).fields.forEach { - require (it.parent == arrayListClass) - sorted.add(arrayListFields[it.name.asString()]!!) - } + val sorted = context.getLayoutBuilder(arrayListClass).fields.map { arrayListFields[it.name]!! } return createConstKotlinObject(arrayListClass, *sorted.toTypedArray()) }