[K/N][codegen] Reworked fields building

This commit is contained in:
Igor Chevdar
2021-08-04 23:17:57 +05:00
parent 56cc40f639
commit 3eb7d32b21
8 changed files with 45 additions and 32 deletions
@@ -34,4 +34,5 @@ object KonanFqNames {
val hasFreezeHook = FqName("kotlin.native.internal.HasFreezeHook") val hasFreezeHook = FqName("kotlin.native.internal.HasFreezeHook")
val gcUnsafeCall = FqName("kotlin.native.internal.GCUnsafeCall") val gcUnsafeCall = FqName("kotlin.native.internal.GCUnsafeCall")
val eagerInitialization = FqName("kotlin.native.EagerInitialization") val eagerInitialization = FqName("kotlin.native.EagerInitialization")
val noReorderFields = FqName("kotlin.native.internal.NoReorderFields")
} }
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.simpleFunctions
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.computeFunctionName 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.llvm.localHash
import org.jetbrains.kotlin.backend.konan.lower.InnerClassLowering import org.jetbrains.kotlin.backend.konan.lower.InnerClassLowering
import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget 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.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrClassReference 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.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.FqName
internal class OverriddenFunctionInfo( internal class OverriddenFunctionInfo(
val function: IrSimpleFunction, val function: IrSimpleFunction,
@@ -392,15 +393,30 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
return context.getLayoutBuilder(superFunction.parentAsClass).itablePlace(superFunction) 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. * All fields of the class instance.
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix. * The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
*/ */
val fields: List<IrField> by lazy { val fields: List<FieldInfo> by lazy {
val superClass = irClass.getSuperClassNotAny() // TODO: what if Any has fields? val superClass = irClass.getSuperClassNotAny()
val superFields = if (superClass != null) context.getLayoutBuilder(superClass).fields else emptyList() 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 { val associatedObjects by lazy {
@@ -441,10 +457,15 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
lateinit var hierarchyInfo: ClassGlobalHierarchyInfo 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. * Fields declared in the class.
*/ */
private fun getDeclaredFields(): List<IrField> { fun getDeclaredFields(): List<FieldInfo> {
val declarations: List<IrDeclaration> = if (irClass.isInner && !isLowered) { val declarations: List<IrDeclaration> = if (irClass.isInner && !isLowered) {
// Note: copying to avoid mutation of the original class. // Note: copying to avoid mutation of the original class.
irClass.declarations.toMutableList() irClass.declarations.toMutableList()
@@ -452,19 +473,13 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
} else { } else {
irClass.declarations irClass.declarations
} }
return declarations.mapNotNull {
val fields = declarations.mapNotNull {
when (it) { when (it) {
is IrField -> it.takeIf { it.isReal } is IrField -> it.takeIf { it.isReal }?.toFieldInfo()
is IrProperty -> it.takeIf { it.isReal }?.backingField is IrProperty -> it.takeIf { it.isReal }?.backingField?.toFieldInfo()
else -> null 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<IrSimpleFunction> private val IrClass.overridableOrOverridingMethods: List<IrSimpleFunction>
@@ -43,7 +43,7 @@ internal fun IrClass.hasConstStateAndNoSideEffects(context: Context): Boolean {
if (!context.shouldOptimize()) return false if (!context.shouldOptimize()) return false
if (this.hasAnnotation(KonanFqNames.canBePrecreated)) return true if (this.hasAnnotation(KonanFqNames.canBePrecreated)) return true
val fields = context.getLayoutBuilder(this).fields 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) } this.constructors.all { it.isAutogeneratedSimpleConstructor(context) }
} }
@@ -367,7 +367,7 @@ internal class StackLocalsManagerImpl(
} else { } else {
val type = context.llvmDeclarations.forClass(stackLocal.irClass).bodyType val type = context.llvmDeclarations.forClass(stackLocal.irClass).bodyType
for (field in context.getLayoutBuilder(stackLocal.irClass).fields) { for (field in context.getLayoutBuilder(stackLocal.irClass).fields) {
val fieldIndex = context.llvmDeclarations.forField(field).index val fieldIndex = field.index
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!! val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
if (isObjectType(fieldType)) { if (isObjectType(fieldType)) {
@@ -254,7 +254,7 @@ internal class InitializersGenerationState {
&& moduleGlobalInitializers.isEmpty() && moduleThreadLocalInitializers.isEmpty() && 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 { private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
if (LLVMGetNamedFunction(llvmModule, name) != null) { if (LLVMGetNamedFunction(llvmModule, name) != null) {
@@ -462,7 +462,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
private val target = context.config.target private val target = context.config.target
val runtimeFile = context.config.distribution.runtime(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 val targetTriple = runtime.target
@@ -924,7 +924,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun computeFields(declaration: IrClass): Array<ConstValue> { private fun computeFields(declaration: IrClass): Array<ConstValue> {
val fields = context.getLayoutBuilder(declaration).fields val fields = context.getLayoutBuilder(declaration).fields
return Array(fields.size) { index -> 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)) constValue(evaluateConst(initializer))
} }
} }
@@ -76,7 +76,7 @@ internal class StaticFieldLlvmDeclarations(val storageAddressAccess: AddressAcce
internal class UniqueLlvmDeclarations(val pointer: ConstPointer) internal class UniqueLlvmDeclarations(val pointer: ConstPointer)
private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef { private fun ContextUtils.createClassBodyType(name: String, fields: List<ClassLayoutBuilder.FieldInfo>): LLVMTypeRef {
val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) } val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) }
// TODO: consider adding synthetic ObjHeader field to Any. // 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 val classDeclarations = (containingClass.metadata as? CodegenClassMetadata)?.llvm
?: error(containingClass.descriptor.toString()) ?: error(containingClass.descriptor.toString())
val allFields = context.getLayoutBuilder(containingClass).fields 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 = CodegenInstanceFieldMetadata(
declaration.metadata?.name, declaration.metadata?.name,
containingClass.konanLibrary, containingClass.konanLibrary,
FieldLlvmDeclarations( FieldLlvmDeclarations(
allFields.indexOf(declaration) + 1, // First field is ObjHeader. fieldInfo.index,
classDeclarations.bodyType classDeclarations.bodyType
) )
) )
@@ -426,12 +426,12 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr), NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr),
debugOperationsSize, debugOperations) debugOperationsSize, debugOperations)
} else { } else {
data class FieldRecord(val offset: Int, val type: Int, val name: String) class FieldRecord(val offset: Int, val type: Int, val name: String)
val fields = getStructElements(bodyType).drop(1).mapIndexed { index, type -> val fields = context.getLayoutBuilder(irClass).fields.map {
FieldRecord( FieldRecord(
LLVMOffsetOfElement(llvmTargetData, bodyType, index + 1).toInt(), LLVMOffsetOfElement(llvmTargetData, bodyType, it.index).toInt(),
mapRuntimeType(type), mapRuntimeType(LLVMStructGetTypeAtIndex(bodyType, it.index)!!),
context.getLayoutBuilder(irClass).fields[index].name.asString()) it.name)
} }
val offsetsPtr = staticData.placeGlobalConstArray("kextoff:$className", int32Type, val offsetsPtr = staticData.placeGlobalConstArray("kextoff:$className", int32Type,
fields.map { Int32(it.offset) }) fields.map { Int32(it.offset) })
@@ -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() // Now sort these values according to the order of fields returned by getFields()
// to match the sorting order of the real ArrayList(). // to match the sorting order of the real ArrayList().
val sorted = mutableListOf<ConstValue>() val sorted = context.getLayoutBuilder(arrayListClass).fields.map { arrayListFields[it.name]!! }
context.getLayoutBuilder(arrayListClass).fields.forEach {
require (it.parent == arrayListClass)
sorted.add(arrayListFields[it.name.asString()]!!)
}
return createConstKotlinObject(arrayListClass, *sorted.toTypedArray()) return createConstKotlinObject(arrayListClass, *sorted.toTypedArray())
} }