diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt index e4dc26a4a28..14becdc7ac9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt @@ -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() }, + { _, accumulator, element -> + accumulator.also { it[element.classId.shortClassName] = element } + }) } } @@ -105,10 +118,12 @@ internal abstract class InlineClassesSupport { protected abstract fun makeNullable(type: Type): Type protected abstract fun erase(type: Type): Class protected abstract fun computeFullErasure(type: Type): Sequence - 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 { 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 { } 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 { @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 { 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 { 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 { BinaryType.Reference(computeFullErasure(type), true) } -private val implicitInlineClasses = - (KonanPrimitiveType.values().map { it.fqName } + - KonanFqNames.nativePtr + - InteropFqNames.cPointer).toSet() - internal object KotlinTypeInlineClassesSupport : InlineClassesSupport() { override fun isNullable(type: KotlinType): Boolean = type.isNullable() @@ -233,7 +253,6 @@ internal object KotlinTypeInlineClassesSupport : InlineClassesSupport() { @@ -267,12 +294,11 @@ private object IrTypeInlineClassesSupport : InlineClassesSupport().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 } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt index f7a935eecfe..e7af77b2aca 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt @@ -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 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt index 6f0b6495bec..fd523beae5f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt @@ -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().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 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt index ca097b3ac47..d0b5ca280d8 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/NewIrUtils.kt @@ -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 } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index 9d8f144df31..5a88091a6aa 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -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. diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt index 1615a008fc6..052543a1b73 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/StaticObjects.kt @@ -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() + val sorted = mutableListOf() 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( diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt index 57d7dbb9e7a..aa4a94577a4 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/Autoboxing.kt @@ -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) }