JVM IR: optimize IrIntrinsicMethods.getIntrinsic

Create a nested hash map with names as keys that are easier to compute
than the whole `Key`. It helps to substantially reduce the number of
computed FqName instances, since intrinsics are queried on generation of
each call.

Also put intrinsic query a bit lower in SyntheticAccessorLowering, after
operations which are easier to compute.
This commit is contained in:
Alexander Udalov
2023-08-22 12:07:41 +02:00
committed by Space Team
parent 498d2c0bd7
commit 70f48db226
2 changed files with 59 additions and 32 deletions
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmSymbols
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
@@ -44,7 +41,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
private val kClassFqn = StandardNames.FqNames.kClass.toSafe() private val kClassFqn = StandardNames.FqNames.kClass.toSafe()
private val stringFqn = StandardNames.FqNames.string.toSafe() private val stringFqn = StandardNames.FqNames.string.toSafe()
private val intrinsicsMap = ( private val intrinsics = (
listOf( listOf(
Key(kotlinJvmFqn, FqName("T"), "<get-javaClass>", emptyList()) to JavaClassProperty, Key(kotlinJvmFqn, FqName("T"), "<get-javaClass>", emptyList()) to JavaClassProperty,
Key(kotlinJvmFqn, kClassFqn, "<get-javaObjectType>", emptyList()) to GetJavaObjectType, Key(kotlinJvmFqn, kClassFqn, "<get-javaObjectType>", emptyList()) to GetJavaObjectType,
@@ -122,7 +119,18 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
primitiveComparisonIntrinsics(irBuiltIns.greaterOrEqualFunByOperandType, KtTokens.GTEQ) + primitiveComparisonIntrinsics(irBuiltIns.greaterOrEqualFunByOperandType, KtTokens.GTEQ) +
intrinsicsThatShouldHaveBeenLowered() intrinsicsThatShouldHaveBeenLowered()
).toMap() )
private val intrinsicsMap = hashMapOf<String, MutableMap<FqName?, MutableMap<Key, IntrinsicMethod>>>()
init {
@Suppress("ReplacePutWithAssignment")
for ((key, intrinsic) in intrinsics) {
intrinsicsMap.getOrPut(key.name) { hashMapOf() }
.getOrPut(key.receiverParameterTypeName) { hashMapOf() }
.put(key, intrinsic)
}
}
private fun intrinsicsThatShouldHaveBeenLowered() = private fun intrinsicsThatShouldHaveBeenLowered() =
(symbols.primitiveTypesToPrimitiveArrays.map { (_, primitiveClassSymbol) -> (symbols.primitiveTypesToPrimitiveArrays.map { (_, primitiveClassSymbol) ->
@@ -139,7 +147,15 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
private val PrimitiveType.symbol private val PrimitiveType.symbol
get() = irBuiltIns.primitiveTypeToIrType[this]!!.classOrNull!! get() = irBuiltIns.primitiveTypeToIrType[this]!!.classOrNull!!
fun getIntrinsic(symbol: IrFunctionSymbol): IntrinsicMethod? = intrinsicsMap[symbol.toKey()] fun getIntrinsic(symbol: IrFunctionSymbol): IntrinsicMethod? {
val function = symbol.owner
val name = function.name.asString()
val byName = intrinsicsMap[name] ?: return null
val receiverFqName = function.computeExtensionReceiverFqName()
val byReceiver = byName[receiverFqName] ?: return null
val ownerFqName = function.computeOwnerFqName() ?: return null
return byReceiver[Key(ownerFqName, receiverFqName, name, function.computeValueParameterFqNames())]
}
private fun unaryFunForPrimitives(name: String, intrinsic: IntrinsicMethod): List<Pair<Key, IntrinsicMethod>> = private fun unaryFunForPrimitives(name: String, intrinsic: IntrinsicMethod): List<Pair<Key, IntrinsicMethod>> =
PrimitiveType.entries.map { type -> PrimitiveType.entries.map { type ->
@@ -155,7 +171,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
private fun binaryFunForPrimitives( private fun binaryFunForPrimitives(
name: String, name: String,
intrinsic: IntrinsicMethod, intrinsic: IntrinsicMethod,
parameter: IrClassifierSymbol parameter: IrClassifierSymbol,
): List<Pair<Key, IntrinsicMethod>> = ): List<Pair<Key, IntrinsicMethod>> =
PrimitiveType.entries.map { type -> PrimitiveType.entries.map { type ->
createKeyMapping(intrinsic, type.symbol, name, parameter) createKeyMapping(intrinsic, type.symbol, name, parameter)
@@ -186,7 +202,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
private fun primitiveComparisonIntrinsics( private fun primitiveComparisonIntrinsics(
typeToIrFun: Map<IrClassifierSymbol, IrSimpleFunctionSymbol>, typeToIrFun: Map<IrClassifierSymbol, IrSimpleFunctionSymbol>,
operator: KtSingleValueToken operator: KtSingleValueToken,
): List<Pair<Key, PrimitiveComparison>> = ): List<Pair<Key, PrimitiveComparison>> =
PrimitiveType.entries.mapNotNull { primitiveType -> PrimitiveType.entries.mapNotNull { primitiveType ->
val irPrimitiveClassifier = irBuiltIns.primitiveTypeToIrType[primitiveType]!!.classifierOrFail val irPrimitiveClassifier = irBuiltIns.primitiveTypeToIrType[primitiveType]!!.classifierOrFail
@@ -198,31 +214,39 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
companion object { companion object {
private val INC = Increment(1) private val INC = Increment(1)
private val DEC = Increment(-1) private val DEC = Increment(-1)
private val EXPLICIT_EQUALS = ExplicitEquals() private val EXPLICIT_EQUALS = ExplicitEquals()
private fun IrFunctionSymbol.toKey(): Key? { private fun IrFunctionSymbol.toKey(): Key? = owner.toKey()
val parent = owner.parent
val ownerFqName = when { private fun IrFunction.toKey(): Key? {
parent is IrClass && parent.isFileClass ->
(parent.parent as IrPackageFragment).packageFqName
parent is IrClass -> parent.fqNameWhenAvailable ?: return null
parent is IrPackageFragment -> parent.packageFqName
else -> return null
}
return Key( return Key(
ownerFqName, computeOwnerFqName() ?: return null,
getParameterFqName(owner.extensionReceiverParameter), computeExtensionReceiverFqName(),
owner.name.asString(), name.asString(),
owner.valueParameters.map(::getParameterFqName) computeValueParameterFqNames()
) )
} }
private fun getParameterFqName(parameter: IrValueParameter?): FqName? = private fun IrFunction.computeOwnerFqName(): FqName? {
getParameterFqName(parameter?.type?.classifierOrNull) val ownerFqName = when (val parent = parent) {
is IrClass -> {
if (parent.isFileClass) (parent.parent as IrPackageFragment).packageFqName
else parent.fqNameWhenAvailable
}
is IrPackageFragment -> parent.packageFqName
else -> null
}
return ownerFqName
}
private fun getParameterFqName(parameter: IrClassifierSymbol?): FqName? = private fun IrFunction.computeExtensionReceiverFqName(): FqName? =
computeParameterFqName(extensionReceiverParameter)
private fun computeParameterFqName(parameter: IrValueParameter?): FqName? =
computeParameterFqName(parameter?.type?.classifierOrNull)
private fun computeParameterFqName(parameter: IrClassifierSymbol?): FqName? =
parameter?.owner?.let { parameter?.owner?.let {
when (it) { when (it) {
is IrClass -> it.fqNameWhenAvailable is IrClass -> it.fqNameWhenAvailable
@@ -231,13 +255,16 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
} }
} }
private fun IrFunction.computeValueParameterFqNames(): List<FqName?> =
valueParameters.map(::computeParameterFqName)
private fun createKeyMapping( private fun createKeyMapping(
intrinsic: IntrinsicMethod, intrinsic: IntrinsicMethod,
klass: IrClassSymbol, klass: IrClassSymbol,
name: String, name: String,
vararg args: IrClassifierSymbol vararg args: IrClassifierSymbol,
): Pair<Key, IntrinsicMethod> = ): Pair<Key, IntrinsicMethod> =
Key(klass.owner.fqNameWhenAvailable!!, null, name, args.map { getParameterFqName(it) }) to Key(klass.owner.fqNameWhenAvailable!!, null, name, args.map { computeParameterFqName(it) }) to
intrinsic intrinsic
} }
} }
@@ -52,10 +52,6 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : FileL
/// This function needs to single out those cases where Java accessibility rules differ from Kotlin's. /// This function needs to single out those cases where Java accessibility rules differ from Kotlin's.
val declarationRaw = owner as IrDeclarationWithVisibility val declarationRaw = owner as IrDeclarationWithVisibility
// If this expression won't actually result in a JVM instruction call, access modifiers don't matter.
if (declarationRaw is IrFunction && (declarationRaw.isInline || context.getIntrinsic(declarationRaw.symbol) != null))
return true
// Enum entry constructors are generated as package-private and are accessed only from corresponding enum class // Enum entry constructors are generated as package-private and are accessed only from corresponding enum class
if (declarationRaw is IrConstructor && declarationRaw.constructedClass.isEnumEntry) return true if (declarationRaw is IrConstructor && declarationRaw.constructedClass.isEnumEntry) return true
@@ -72,6 +68,10 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : FileL
// (the inliner will generate it at the call site if necessary). // (the inliner will generate it at the call site if necessary).
if (declarationRaw is IrField && declarationRaw.isAssertionsDisabledField(context)) return true if (declarationRaw is IrField && declarationRaw.isAssertionsDisabledField(context)) return true
// If this expression won't actually result in a JVM instruction call, access modifiers don't matter.
if (declarationRaw is IrFunction && (declarationRaw.isInline || context.getIntrinsic(declarationRaw.symbol) != null))
return true
val declaration = when (declarationRaw) { val declaration = when (declarationRaw) {
is IrSimpleFunction -> declarationRaw.resolveFakeOverride(allowAbstract = true)!! is IrSimpleFunction -> declarationRaw.resolveFakeOverride(allowAbstract = true)!!
is IrField -> declarationRaw.resolveFakeOverride() is IrField -> declarationRaw.resolveFakeOverride()