[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 gcUnsafeCall = FqName("kotlin.native.internal.GCUnsafeCall")
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.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<IrField> by lazy {
val superClass = irClass.getSuperClassNotAny() // TODO: what if Any has fields?
val fields: List<FieldInfo> 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<IrField> {
fun getDeclaredFields(): List<FieldInfo> {
val declarations: List<IrDeclaration> = 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<IrSimpleFunction>
@@ -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)) {
@@ -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
@@ -924,7 +924,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun computeFields(declaration: IrClass): Array<ConstValue> {
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))
}
}
@@ -76,7 +76,7 @@ internal class StaticFieldLlvmDeclarations(val storageAddressAccess: AddressAcce
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) }
// 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
)
)
@@ -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) })
@@ -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<ConstValue>()
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())
}