Started to eliminate expensive fqNames usages in IR (#4448)

This commit is contained in:
LepilkinaElena
2020-10-19 20:41:22 +03:00
committed by GitHub
parent 81043beb33
commit f6116477dd
7 changed files with 104 additions and 52 deletions
@@ -5,10 +5,13 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.ir.containsNull
import org.jetbrains.kotlin.backend.konan.ir.getSuperClassNotAny
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -18,9 +21,11 @@ import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.packageFqName
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.types.KotlinType
@@ -39,6 +44,8 @@ fun IrType.getInlinedClassNative(): IrClass? = IrTypeInlineClassesSupport.getInl
*/
fun IrType.isInlinedNative(): Boolean = IrTypeInlineClassesSupport.isInlined(this)
fun IrClass.isInlined(): Boolean = IrTypeInlineClassesSupport.isInlined(this)
fun IrClass.isNativePrimitiveType() = IrTypeInlineClassesSupport.isTopLevelClass(this) &&
KonanPrimitiveType.byFqNameParts[packageFqName]?.get(name) != null
fun KotlinType.getInlinedClass(): ClassDescriptor? = KotlinTypeInlineClassesSupport.getInlinedClass(this)
@@ -96,7 +103,13 @@ enum class KonanPrimitiveType(val classId: ClassId, val binaryType: BinaryType.P
val fqName: FqNameUnsafe get() = this.classId.asSingleFqName().toUnsafe()
companion object {
val byFqName = KonanPrimitiveType.values().associateBy { it.fqName }
val byFqNameParts = KonanPrimitiveType.values().groupingBy {
assert(!it.classId.isNestedClass)
it.classId.packageFqName
}.fold({ _, _ -> mutableMapOf<Name, KonanPrimitiveType>() },
{ _, accumulator, element ->
accumulator.also { it[element.classId.shortClassName] = element }
})
}
}
@@ -105,10 +118,12 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
protected abstract fun makeNullable(type: Type): Type
protected abstract fun erase(type: Type): Class
protected abstract fun computeFullErasure(type: Type): Sequence<Class>
protected abstract fun getFqName(clazz: Class): FqNameUnsafe
protected abstract fun hasInlineModifier(clazz: Class): Boolean
protected abstract fun getNativePointedSuperclass(clazz: Class): Class?
protected abstract fun getInlinedClassUnderlyingType(clazz: Class): Type
protected abstract fun getPackageFqName(clazz: Class): FqName?
protected abstract fun getName(clazz: Class): Name?
abstract fun isTopLevelClass(clazz: Class): Boolean
@JvmName("classIsInlined")
fun isInlined(clazz: Class): Boolean = getInlinedClass(clazz) != null
@@ -119,6 +134,16 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
fun getInlinedClass(type: Type): Class? =
getInlinedClass(erase(type), isNullable(type))
protected fun getKonanPrimitiveType(clazz: Class): KonanPrimitiveType? =
if (isTopLevelClass(clazz))
KonanPrimitiveType.byFqNameParts[getPackageFqName(clazz)]?.get(getName(clazz))
else null
protected fun isImplicitInlineClass(clazz: Class): Boolean =
isTopLevelClass(clazz) && (getKonanPrimitiveType(clazz) != null ||
getName(clazz) == KonanFqNames.nativePtr.shortName() && getPackageFqName(clazz) == KonanFqNames.internalPackageName ||
getName(clazz) == InteropFqNames.cPointer.shortName() && getPackageFqName(clazz) == InteropFqNames.cPointer.parent().toSafe())
private fun getInlinedClass(erased: Class, isNullable: Boolean): Class? {
val inlinedClass = getInlinedClass(erased) ?: return null
return if (!isNullable || representationIsNonNullReferenceOrPointer(inlinedClass)) {
@@ -129,7 +154,7 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
}
tailrec fun representationIsNonNullReferenceOrPointer(clazz: Class): Boolean {
val konanPrimitiveType = KonanPrimitiveType.byFqName[getFqName(clazz)]
val konanPrimitiveType = getKonanPrimitiveType(clazz)
if (konanPrimitiveType != null) {
return konanPrimitiveType == KonanPrimitiveType.NON_NULL_NATIVE_PTR
}
@@ -146,7 +171,7 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
@JvmName("classGetInlinedClass")
private fun getInlinedClass(clazz: Class): Class? =
if (hasInlineModifier(clazz) || getFqName(clazz) in implicitInlineClasses) {
if (hasInlineModifier(clazz) || isImplicitInlineClass(clazz)) {
clazz
} else {
getNativePointedSuperclass(clazz)
@@ -168,7 +193,7 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
val nullable = isNullable(currentType)
KonanPrimitiveType.byFqName[getFqName(inlinedClass)]?.let { primitiveType ->
getKonanPrimitiveType(inlinedClass)?.let { primitiveType ->
return ifPrimitive(primitiveType, nullable)
}
@@ -193,7 +218,7 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
val erased = erase(type)
val inlinedClass = getInlinedClass(erased, isNullable(type)) ?: return createReferenceBinaryType(type)
KonanPrimitiveType.byFqName[getFqName(inlinedClass)]?.let {
getKonanPrimitiveType(inlinedClass)?.let {
return it.binaryType
}
@@ -209,11 +234,6 @@ internal abstract class InlineClassesSupport<Class : Any, Type : Any> {
BinaryType.Reference(computeFullErasure(type), true)
}
private val implicitInlineClasses =
(KonanPrimitiveType.values().map { it.fqName } +
KonanFqNames.nativePtr +
InteropFqNames.cPointer).toSet()
internal object KotlinTypeInlineClassesSupport : InlineClassesSupport<ClassDescriptor, KotlinType>() {
override fun isNullable(type: KotlinType): Boolean = type.isNullable()
@@ -233,7 +253,6 @@ internal object KotlinTypeInlineClassesSupport : InlineClassesSupport<ClassDescr
else type.constructor.supertypes.asSequence().flatMap { computeFullErasure(it) }
}
override fun getFqName(clazz: ClassDescriptor): FqNameUnsafe = clazz.fqNameUnsafe
override fun hasInlineModifier(clazz: ClassDescriptor): Boolean = clazz.isInline
override fun getNativePointedSuperclass(clazz: ClassDescriptor): ClassDescriptor? = clazz.getAllSuperClassifiers()
@@ -241,6 +260,14 @@ internal object KotlinTypeInlineClassesSupport : InlineClassesSupport<ClassDescr
override fun getInlinedClassUnderlyingType(clazz: ClassDescriptor): KotlinType =
clazz.unsubstitutedPrimaryConstructor!!.valueParameters.single().type
override fun getPackageFqName(clazz: ClassDescriptor) =
clazz.findPackage().fqName
override fun getName(clazz: ClassDescriptor) =
clazz.name
override fun isTopLevelClass(clazz: ClassDescriptor): Boolean = clazz.containingDeclaration is PackageFragmentDescriptor
}
private object IrTypeInlineClassesSupport : InlineClassesSupport<IrClass, IrType>() {
@@ -267,12 +294,11 @@ private object IrTypeInlineClassesSupport : InlineClassesSupport<IrClass, IrType
}
}
override fun getFqName(clazz: IrClass): FqNameUnsafe = clazz.descriptor.fqNameUnsafe
override fun hasInlineModifier(clazz: IrClass): Boolean = clazz.descriptor.isInline
override fun getNativePointedSuperclass(clazz: IrClass): IrClass? {
var superClass: IrClass? = clazz
while (superClass != null && superClass.descriptor.fqNameUnsafe != InteropFqNames.nativePointed)
while (superClass != null && (!superClass.symbol.isPublicApi || InteropIdSignatures.nativePointed != superClass.symbol.signature))
superClass = superClass.getSuperClassNotAny()
return superClass
}
@@ -280,4 +306,12 @@ private object IrTypeInlineClassesSupport : InlineClassesSupport<IrClass, IrType
override fun getInlinedClassUnderlyingType(clazz: IrClass): IrType =
clazz.constructors.firstOrNull { it.isPrimary }?.valueParameters?.single()?.type
?: clazz.declarations.filterIsInstance<IrProperty>().single { it.backingField != null }.backingField!!.type
override fun getPackageFqName(clazz: IrClass) =
clazz.packageFqName
override fun getName(clazz: IrClass): Name? =
clazz.name
override fun isTopLevelClass(clazz: IrClass): Boolean = clazz.isTopLevel
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.types.getPublicSignature
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -26,6 +27,10 @@ object InteropFqNames {
val nativePointed = packageName.child(Name.identifier(nativePointedName)).toUnsafe()
}
object InteropIdSignatures {
val nativePointed = getPublicSignature(InteropFqNames.packageName, InteropFqNames.nativePointedName)
}
internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
val packageScope = builtIns.builtInsModule.getPackage(InteropFqNames.packageName).memberScope
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.getPublicSignature
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -34,14 +34,20 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal val interopPackageName = InteropFqNames.packageName
internal val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
internal val objCObjectIdSignature = getTopLevelPublicSignature(objCObjectFqName)
private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass"))
private val objCClassIdSignature = getTopLevelPublicSignature(objCClassFqName)
private val objCProtocolFqName = interopPackageName.child(Name.identifier("ObjCProtocol"))
private val objCProtocolIdSignature = getTopLevelPublicSignature(objCProtocolFqName)
internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass"))
private val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod"))
private val objCConstructorFqName = FqName("kotlinx.cinterop.ObjCConstructor")
private val objCFactoryFqName = interopPackageName.child(Name.identifier("ObjCFactory"))
private val objcnamesForwardDeclarationsPackageName = Name.identifier("objcnames")
private fun getTopLevelPublicSignature(fqName: FqName): IdSignature.PublicSignature =
getPublicSignature(fqName.parent(), fqName.shortName().asString())
fun ClassDescriptor.isObjCClass(): Boolean =
this.containingDeclaration.fqNameSafe != interopPackageName &&
this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } // TODO: this is not cheap. Cache me!
@@ -55,8 +61,8 @@ private fun IrClass.selfOrAnySuperClass(pred: (IrClass) -> Boolean): Boolean {
return superTypes.any { it.classOrNull!!.owner.selfOrAnySuperClass(pred) }
}
internal fun IrClass.isObjCClass() = this.parent.fqNameForIrSerialization != interopPackageName &&
selfOrAnySuperClass { it.fqNameForIrSerialization == objCObjectFqName }
internal fun IrClass.isObjCClass() = this.packageFqName != interopPackageName &&
selfOrAnySuperClass { it.symbol.isPublicApi && objCObjectIdSignature == it.symbol.signature }
fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
this.parentsWithSelf.filterIsInstance<ClassDescriptor>().any {
@@ -75,11 +81,11 @@ fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().a
}
fun IrClass.isObjCMetaClass(): Boolean = selfOrAnySuperClass {
it.fqNameForIrSerialization == objCClassFqName
it.symbol.isPublicApi && objCClassIdSignature == it.symbol.signature
}
fun IrClass.isObjCProtocolClass(): Boolean =
this.fqNameForIrSerialization == objCProtocolFqName
symbol.isPublicApi && objCProtocolIdSignature == symbol.signature
fun ClassDescriptor.isObjCProtocolClass(): Boolean =
this.fqNameSafe == objCProtocolFqName
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IdSignatureValues
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isMarkedNullable
import org.jetbrains.kotlin.ir.util.*
@@ -27,17 +28,21 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
val IrField.fqNameForIrSerialization: FqName get() = this.parent.fqNameForIrSerialization.child(this.name)
private fun IrClass.isClassTypeWithSignature(signature: IdSignature.PublicSignature): Boolean {
if (!symbol.isPublicApi) return false
return signature == symbol.signature
}
fun IrClass.isUnit() = this.fqNameForIrSerialization == StandardNames.FqNames.unit.toSafe()
fun IrClass.isUnit() = this.isClassTypeWithSignature(IdSignatureValues.unit)
fun IrClass.isKotlinArray() = this.fqNameForIrSerialization == StandardNames.FqNames.array.toSafe()
fun IrClass.isKotlinArray() = this.isClassTypeWithSignature(IdSignatureValues.array)
val IrClass.superClasses get() = this.superTypes.map { it.classifierOrFail as IrClassSymbol }
fun IrClass.getSuperClassNotAny() = this.superClasses.map { it.owner }.atMostOne { !it.isInterface && !it.isAny() }
fun IrClass.isAny() = this.fqNameForIrSerialization == StandardNames.FqNames.any.toSafe()
fun IrClass.isNothing() = this.fqNameForIrSerialization == StandardNames.FqNames.nothing.toSafe()
fun IrClass.isAny() = this.isClassTypeWithSignature(IdSignatureValues.any)
fun IrClass.isNothing() = this.isClassTypeWithSignature(IdSignatureValues.nothing)
fun IrClass.getSuperInterfaces() = this.superClasses.map { it.owner }.filter { it.isInterface }
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
@@ -162,18 +164,18 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
}
private val arrayClasses = mapOf(
"kotlin.Array" to kObjHeaderPtr,
"kotlin.ByteArray" to int8Type,
"kotlin.CharArray" to int16Type,
"kotlin.ShortArray" to int16Type,
"kotlin.IntArray" to int32Type,
"kotlin.LongArray" to int64Type,
"kotlin.FloatArray" to floatType,
"kotlin.DoubleArray" to doubleType,
"kotlin.BooleanArray" to int8Type,
"kotlin.String" to int16Type,
"kotlin.native.ImmutableBlob" to int8Type,
"kotlin.native.internal.NativePtrArray" to kInt8Ptr
IdSignatureValues.array to kObjHeaderPtr,
primitiveArrayTypesSignatures[PrimitiveType.BYTE] to int8Type,
primitiveArrayTypesSignatures[PrimitiveType.CHAR] to int16Type,
primitiveArrayTypesSignatures[PrimitiveType.SHORT] to int16Type,
primitiveArrayTypesSignatures[PrimitiveType.INT] to int32Type,
primitiveArrayTypesSignatures[PrimitiveType.LONG] to int64Type,
primitiveArrayTypesSignatures[PrimitiveType.FLOAT] to floatType,
primitiveArrayTypesSignatures[PrimitiveType.DOUBLE] to doubleType,
primitiveArrayTypesSignatures[PrimitiveType.BOOLEAN] to int8Type,
IdSignatureValues.string to int16Type,
getPublicSignature(KonanFqNames.packageName, "ImmutableBlob") to int8Type,
getPublicSignature(KonanFqNames.internalPackageName, "NativePtrArray") to kInt8Ptr
)
// Keep in sync with Konan_RuntimeType.
@@ -190,8 +192,11 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
vector128Type to 10
)
private fun getInstanceSize(classType: LLVMTypeRef?, className: FqName) : Int {
val elementType = arrayClasses.get(className.asString())
private fun getElementType(irClass: IrClass): LLVMTypeRef? =
if (irClass.symbol.isPublicApi) arrayClasses[irClass.symbol.signature as IdSignature.PublicSignature] else null
private fun getInstanceSize(classType: LLVMTypeRef?, irClass: IrClass) : Int {
val elementType = getElementType(irClass)
// Check if it is an array.
if (elementType != null) return -LLVMABISizeOfType(llvmTargetData, elementType).toInt()
return LLVMStoreSizeOfType(llvmTargetData, classType).toInt()
@@ -219,7 +224,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val bodyType = llvmDeclarations.bodyType
val instanceSize = getInstanceSize(bodyType, className)
val instanceSize = getInstanceSize(bodyType, irClass)
val superType = when {
irClass.isAny() -> NullPointer(runtime.typeInfoType)
@@ -452,7 +457,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val className = irClass.fqNameForIrSerialization.toString()
val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType
val elementType = arrayClasses[className]
val elementType = getElementType(irClass)
val value = if (elementType != null) {
// An array type.
@@ -7,10 +7,8 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.ir.fqNameForIrSerialization
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
private fun ConstPointer.add(index: Int): ConstPointer {
return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!)
@@ -86,22 +84,21 @@ internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstVal
internal fun StaticData.createConstArrayList(array: ConstPointer, length: Int): ConstPointer {
val arrayListClass = context.ir.symbols.arrayList.owner
val arrayListFqName = arrayListClass.fqNameForIrSerialization
val arrayListFields = mapOf(
"$arrayListFqName.array" to array,
"$arrayListFqName.offset" to Int32(0),
"$arrayListFqName.length" to Int32(length),
"$arrayListFqName.backing" to NullPointer(kObjHeader))
"array" to array,
"offset" to Int32(0),
"length" to Int32(length),
"backing" to NullPointer(kObjHeader))
// Now sort these values according to the order of fields returned by getFields()
// to match the sorting order of the real ArrayList().
val sorted = linkedMapOf<String, ConstValue>()
val sorted = mutableListOf<ConstValue>()
context.getLayoutBuilder(arrayListClass).fields.forEach {
val fqName = it.fqNameForIrSerialization.asString()
sorted.put(fqName, arrayListFields[fqName]!!)
require (it.parent == arrayListClass)
sorted.add(arrayListFields[it.name.asString()]!!)
}
return createConstKotlinObject(arrayListClass, *sorted.values.toTypedArray())
return createConstKotlinObject(arrayListClass, *sorted.toTypedArray())
}
internal fun StaticData.createUniqueInstance(
@@ -226,7 +226,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
if (declaration.isInlined()) {
if (declaration.isUsedAsBoxClass()) {
if (KonanPrimitiveType.byFqName[declaration.fqNameForIrSerialization.toUnsafe()] != null) {
if (declaration.isNativePrimitiveType()) {
buildBoxField(declaration)
}