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