JVM IR: link via descriptors instead of signatures by default
Doing so speeds up psi2ir ~2 times, and thus improves total compiler performance by about 6-8%. Unless JVM IR is in the mode where linking via signatures is the only way (-Xserialize-ir, -Xklib), signatures are actually not needed at all, SymbolTable can use the frontend representation (descriptors for FE1.0, and hopefully FIR elements for K2) as hash table keys. The only catch is that since other backends still need to work with signatures, all the common IR utilities, such as irTypePredicates.kt, need to work correctly for IR elements both with signatures and without. Also, introduce a fallback compiler flag -Xlink-via-signatures, in case something goes wrong, to be able to troubleshoot and workaround any issues. #KT-48233
This commit is contained in:
@@ -481,22 +481,26 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
||||
).substitute(type as IrType)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? {
|
||||
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? =
|
||||
getNameForClassUnderKotlinPackage()?.let(PrimitiveType::getByShortName)
|
||||
|
||||
override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? =
|
||||
getNameForClassUnderKotlinPackage()?.let(PrimitiveType::getByShortArrayName)
|
||||
|
||||
private fun TypeConstructorMarker.getNameForClassUnderKotlinPackage(): String? {
|
||||
if (this !is IrClassSymbol) return null
|
||||
|
||||
val signature = signature?.asPublic()
|
||||
if (signature == null || signature.packageFqName != "kotlin") return null
|
||||
|
||||
return PrimitiveType.getByShortName(signature.declarationFqName)
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.getPrimitiveArrayType(): PrimitiveType? {
|
||||
if (this !is IrClassSymbol) return null
|
||||
|
||||
val signature = signature?.asPublic()
|
||||
if (signature == null || signature.packageFqName != "kotlin") return null
|
||||
|
||||
return PrimitiveType.getByShortArrayName(signature.declarationFqName)
|
||||
return if (signature != null) {
|
||||
if (signature.packageFqName == StandardNames.BUILT_INS_PACKAGE_NAME.asString())
|
||||
signature.declarationFqName
|
||||
else null
|
||||
} else {
|
||||
val parent = owner.parent
|
||||
if (parent is IrPackageFragment && parent.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME)
|
||||
owner.name.asString()
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
override fun TypeConstructorMarker.isUnderKotlinPackage(): Boolean {
|
||||
|
||||
@@ -9,12 +9,14 @@ import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.hasEqualFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
object IdSignatureValues {
|
||||
@@ -55,9 +57,14 @@ fun getPublicSignature(packageFqName: FqName, name: String) =
|
||||
private fun IrType.isClassType(signature: IdSignature.CommonSignature, hasQuestionMark: Boolean? = null): Boolean {
|
||||
if (this !is IrSimpleType) return false
|
||||
if (hasQuestionMark != null && this.hasQuestionMark != hasQuestionMark) return false
|
||||
return signature == classifier.signature
|
||||
return signature == classifier.signature ||
|
||||
classifier.owner.let { it is IrClass && it.hasFqNameEqualToSignature(signature) }
|
||||
}
|
||||
|
||||
private fun IrClass.hasFqNameEqualToSignature(signature: IdSignature.CommonSignature): Boolean =
|
||||
name.asString() == signature.shortName &&
|
||||
hasEqualFqName(FqName("${signature.packageFqName}.${signature.declarationFqName}"))
|
||||
|
||||
fun IrClassifierSymbol.isClassWithFqName(fqName: FqNameUnsafe): Boolean =
|
||||
this is IrClassSymbol && classFqNameEquals(this, fqName)
|
||||
|
||||
@@ -71,6 +78,17 @@ private val idSignatureToPrimitiveType: Map<IdSignature.CommonSignature, Primiti
|
||||
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, it.typeName.asString())
|
||||
}
|
||||
|
||||
private val shortNameToPrimitiveType: Map<Name, PrimitiveType> =
|
||||
PrimitiveType.values().associateBy(PrimitiveType::typeName)
|
||||
|
||||
private val idSignatureToUnsignedType: Map<IdSignature.CommonSignature, UnsignedType> =
|
||||
UnsignedType.values().associateBy {
|
||||
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, it.typeName.asString())
|
||||
}
|
||||
|
||||
private val shortNameToUnsignedType: Map<Name, UnsignedType> =
|
||||
UnsignedType.values().associateBy(UnsignedType::typeName)
|
||||
|
||||
val primitiveArrayTypesSignatures: Map<PrimitiveType, IdSignature.CommonSignature> =
|
||||
PrimitiveType.values().associateWith {
|
||||
getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "${it.typeName.asString()}Array")
|
||||
@@ -97,23 +115,24 @@ fun IrType.isPrimitiveType(hasQuestionMark: Boolean = false): Boolean =
|
||||
fun IrType.isNullablePrimitiveType(): Boolean = isPrimitiveType(true)
|
||||
|
||||
fun IrType.getPrimitiveType(): PrimitiveType? =
|
||||
if (this is IrSimpleType && classifier is IrClassSymbol)
|
||||
idSignatureToPrimitiveType[classifier.signature]
|
||||
else null
|
||||
getPrimitiveOrUnsignedType(idSignatureToPrimitiveType, shortNameToPrimitiveType)
|
||||
|
||||
fun IrType.isUnsignedType(hasQuestionMark: Boolean = false): Boolean =
|
||||
this is IrSimpleType && hasQuestionMark == this.hasQuestionMark && getUnsignedType() != null
|
||||
|
||||
fun IrType.getUnsignedType(): UnsignedType? =
|
||||
if (this is IrSimpleType && classifier is IrClassSymbol)
|
||||
when (classifier.signature) {
|
||||
IdSignatureValues.uByte -> UnsignedType.UBYTE
|
||||
IdSignatureValues.uShort -> UnsignedType.USHORT
|
||||
IdSignatureValues.uInt -> UnsignedType.UINT
|
||||
IdSignatureValues.uLong -> UnsignedType.ULONG
|
||||
else -> null
|
||||
}
|
||||
else null
|
||||
getPrimitiveOrUnsignedType(idSignatureToUnsignedType, shortNameToUnsignedType)
|
||||
|
||||
fun <T : Enum<T>> IrType.getPrimitiveOrUnsignedType(byIdSignature: Map<IdSignature.CommonSignature, T>, byShortName: Map<Name, T>): T? {
|
||||
if (this !is IrSimpleType) return null
|
||||
val symbol = classifier as? IrClassSymbol ?: return null
|
||||
if (symbol.signature != null) return byIdSignature[symbol.signature]
|
||||
|
||||
val klass = symbol.owner
|
||||
val parent = klass.parent
|
||||
if (parent !is IrPackageFragment || parent.fqName != StandardNames.BUILT_INS_PACKAGE_FQ_NAME) return null
|
||||
return byShortName[klass.name]
|
||||
}
|
||||
|
||||
fun IrType.isMarkedNullable() = (this as? IrSimpleType)?.hasQuestionMark ?: false
|
||||
|
||||
@@ -151,8 +170,6 @@ fun IrType.isLongArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignat
|
||||
fun IrType.isFloatArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.FLOAT]!!)
|
||||
fun IrType.isDoubleArray(): Boolean = isNotNullClassType(primitiveArrayTypesSignatures[PrimitiveType.DOUBLE]!!)
|
||||
|
||||
// TODO: remove this method using FqNames.
|
||||
// Need to refactor declarationBuilders.kt: visibilty is known, need to add info about package in IrFactory.buildClass (similar to name).
|
||||
fun IrType.isClassType(fqName: FqNameUnsafe, hasQuestionMark: Boolean): Boolean {
|
||||
if (this !is IrSimpleType) return false
|
||||
if (this.hasQuestionMark != hasQuestionMark) return false
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrScriptImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBasedClassDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -472,7 +473,17 @@ open class SymbolTable(
|
||||
}
|
||||
|
||||
override fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol =
|
||||
classSymbolTable.referenced(descriptor) { signature -> createClassSymbol(descriptor, signature) }
|
||||
@Suppress("Reformat")
|
||||
// This is needed for cases like kt46069.kt, where psi2ir creates descriptor-less IR elements for adapted function references.
|
||||
// In JVM IR, symbols are linked via descriptors by default, so for an adapted function reference, an IrBasedClassDescriptor
|
||||
// is created for any classifier used in the function parameter/return types. Any attempt to translate such type to IrType goes
|
||||
// to this method, which puts the descriptor into unboundClasses, which causes an assertion failure later because we won't bind
|
||||
// such symbol anywhere.
|
||||
// TODO: maybe there's a better solution.
|
||||
if (descriptor is IrBasedClassDescriptor)
|
||||
descriptor.owner.symbol
|
||||
else
|
||||
classSymbolTable.referenced(descriptor) { signature -> createClassSymbol(descriptor, signature) }
|
||||
|
||||
fun referenceClass(
|
||||
sig: IdSignature,
|
||||
|
||||
Reference in New Issue
Block a user