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:
committed by
Space Team
parent
498d2c0bd7
commit
70f48db226
+55
-28
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user