[IR] Weaken pressure on Local storage to fix performance issue

Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com>

#KT-1179
This commit is contained in:
Evgeniy.Zhelenskiy
2022-10-12 13:51:22 +02:00
committed by Space Team
parent 89d5592622
commit 962265531e
5 changed files with 89 additions and 60 deletions
@@ -356,7 +356,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
}
override fun handleSpecificNewClass(declaration: IrClass) {
val rootNode = replacements.getRootMfvcNode(declaration)!!
val rootNode = replacements.getRootMfvcNode(declaration)
rootNode.replaceFields()
declaration.declarations.removeIf { it is IrSimpleFunction && it.isMultiFieldValueClassFieldGetter && it.overriddenSymbols.isEmpty() }
declaration.declarations += rootNode.run { allUnboxMethods + listOf(boxMethod, specializedEqualsMethod) }
@@ -376,7 +376,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
override fun visitClass(declaration: IrClass): IrStatement = declaration
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
val oldPrimaryConstructor = replacements.getRootMfvcNode(constructor.constructedClass)!!.oldPrimaryConstructor
val oldPrimaryConstructor = replacements.getRootMfvcNode(constructor.constructedClass).oldPrimaryConstructor
thisVar.initializer = irCall(oldPrimaryConstructor).apply {
copyTypeAndValueArgumentsFrom(expression)
}
@@ -720,7 +720,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
function is IrConstructor && function.isPrimary && function.constructedClass.isMultiFieldValueClass &&
currentScope.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_MULTI_FIELD_VALUE_CLASS_MEMBER -> {
context.createIrBuilder(currentScope.symbol).irBlock {
val rootNode = replacements.getRootMfvcNode(function.constructedClass)!!
val rootNode = replacements.getRootMfvcNode(function.constructedClass)
val instance = rootNode.createInstanceFromValueDeclarationsAndBoxType(
this, function.constructedClassType as IrSimpleType, Name.identifier("constructor_tmp"), ::variablesSaver
)
@@ -769,9 +769,9 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val leftArgument = expression.getValueArgument(0)!!
val rightArgument = expression.getValueArgument(1)!!
val leftClass = leftArgument.type.erasedUpperBound
val leftNode = if (leftArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNode(leftClass) else null
val leftNode = if (leftArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNodeOrNull(leftClass) else null
val rightClass = rightArgument.type.erasedUpperBound
val rightNode = if (rightArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNode(rightClass) else null
val rightNode = if (rightArgument.type.needsMfvcFlattening()) replacements.getRootMfvcNodeOrNull(rightClass) else null
if (leftNode != null) {
if (rightNode != null) {
// both are unboxed
@@ -1013,7 +1013,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val initializer = declaration.initializer
if (declaration.type.needsMfvcFlattening()) {
val irClass = declaration.type.erasedUpperBound
val rootNode = replacements.getRootMfvcNode(irClass)!!
val rootNode = replacements.getRootMfvcNode(irClass)
return context.createIrBuilder(getCurrentScopeSymbol()).irBlock {
val instance = rootNode.createInstanceFromValueDeclarationsAndBoxType(
this, declaration.type as IrSimpleType, declaration.name, ::variablesSaver
@@ -1036,7 +1036,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
if (!expression.type.needsMfvcFlattening()) {
return listOf(expression.transform(this@JvmMultiFieldValueClassLowering, null))
}
val rootMfvcNode = replacements.getRootMfvcNode(expression.type.erasedUpperBound)!!
val rootMfvcNode = replacements.getRootMfvcNode(expression.type.erasedUpperBound)
val typeArguments = makeTypeArgumentsFromType(expression.type as IrSimpleType)
val variables = rootMfvcNode.leaves.map {
savableStandaloneVariable(
@@ -1060,7 +1060,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
* Takes not transformed expression and initialized given MfvcNodeInstance with transformed version of it
*/
fun IrBlockBuilder.flattenExpressionTo(expression: IrExpression, instance: MfvcNodeInstance) {
val rootNode = replacements.getRootMfvcNode(
val rootNode = replacements.getRootMfvcNodeOrNull(
if (expression is IrConstructorCall) expression.symbol.owner.constructedClass else expression.type.erasedUpperBound
)
val type = if (expression is IrConstructorCall) expression.symbol.owner.constructedClass.defaultType else expression.type
@@ -1198,7 +1198,7 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV
val statementsToRemove = mutableSetOf<IrStatement>()
for (statement in expression.statements.subListWithoutLast(if (resultIsUsed) 1 else 0)) {
val call = getFunctionCallOrNull(statement) ?: continue
val node = replacements.getRootMfvcNode(call.type.erasedUpperBound) ?: continue
val node = replacements.getRootMfvcNodeOrNull(call.type.erasedUpperBound) ?: continue
if (node.boxMethod == call.symbol.owner &&
List(call.valueArgumentsCount) { call.getValueArgument(it) }.all { it.isRepeatableGetter() }
) {
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.alwaysNull
import java.util.concurrent.ConcurrentHashMap
/**
@@ -31,8 +30,7 @@ class MemoizedInlineClassReplacements(
private val mangleReturnTypes: Boolean,
irFactory: IrFactory,
context: JvmBackendContext
) : MemoizedValueClassAbstractReplacements(irFactory, context) {
private val storageManager = LockBasedStorageManager("inline-class-replacements")
) : MemoizedValueClassAbstractReplacements(irFactory, context, LockBasedStorageManager("inline-class-replacements")) {
val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
@@ -40,7 +38,7 @@ class MemoizedInlineClassReplacements(
/**
* Get a replacement for a function or a constructor.
*/
override val getReplacementFunction: (IrFunction) -> IrSimpleFunction? =
override val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction? =
storageManager.createMemoizedFunctionWithNullableValues {
when {
// Don't mangle anonymous or synthetic functions, except for generated SAM wrapper methods
@@ -68,9 +66,11 @@ class MemoizedInlineClassReplacements(
it.isRemoveAtSpecialBuiltinStub() ->
null
it.isValueClassMemberFakeOverriddenFromJvmDefaultInterfaceMethod() ||
it.origin == IrDeclarationOrigin.IR_BUILTINS_STUB ->
createMethodReplacement(it)
else ->
createStaticReplacement(it)
}
@@ -85,6 +85,13 @@ class MemoizedInlineClassReplacements(
}
}
override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction) = !(
function.parent.let { (it is IrClass && it.isSingleFieldValueClass) } ||
function.dispatchReceiverParameter?.type?.isInlineClassType() == true ||
function.extensionReceiverParameter?.type?.isInlineClassType() == true ||
function.valueParameters.any { it.type.isInlineClassType() } || function.returnType.isInlineClassType()
)
/**
* Get the box function for an inline class. Concretely, this is a synthetic
* static function named "box-impl" which takes an unboxed value and returns
@@ -246,20 +253,15 @@ class MemoizedInlineClassReplacements(
origin = when {
function.origin == IrDeclarationOrigin.GENERATED_SINGLE_FIELD_VALUE_CLASS_MEMBER ->
JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD
function is IrConstructor && function.constructedClass.isSingleFieldValueClass ->
JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR
else ->
replacementOrigin
}
name = InlineClassAbi.mangledNameFor(function, mangleReturnTypes, useOldManglingScheme)
}
override val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor? = alwaysNull()
override val replaceOverriddenSymbols: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol> =
storageManager.createMemoizedFunction { irSimpleFunction ->
irSimpleFunction.overriddenSymbols.map {
computeOverrideReplacement(it.owner).symbol
}
}
override fun getReplacementForRegularClassConstructor(constructor: IrConstructor): IrConstructor? = null
}
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.builders.irExprBody
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
@@ -31,8 +30,7 @@ import java.util.concurrent.ConcurrentHashMap
class MemoizedMultiFieldValueClassReplacements(
irFactory: IrFactory,
context: JvmBackendContext
) : MemoizedValueClassAbstractReplacements(irFactory, context) {
private val storageManager = LockBasedStorageManager("multi-field-value-class-replacements")
) : MemoizedValueClassAbstractReplacements(irFactory, context, LockBasedStorageManager("multi-field-value-class-replacements")) {
val originalFunctionForStaticReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
val originalFunctionForMethodReplacement: MutableMap<IrFunction, IrFunction> = ConcurrentHashMap()
@@ -224,7 +222,7 @@ class MemoizedMultiFieldValueClassReplacements(
/**
* Get a function replacement for a function or a constructor.
*/
override val getReplacementFunction: (IrFunction) -> IrSimpleFunction? =
override val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction? =
storageManager.createMemoizedFunctionWithNullableValues { function ->
when {
(function.isLocal && function is IrSimpleFunction && function.overriddenSymbols.isEmpty()) ||
@@ -259,6 +257,13 @@ class MemoizedMultiFieldValueClassReplacements(
}
}
override fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean = !(
function.parent.let { it is IrClass && it.isMultiFieldValueClass } ||
function.dispatchReceiverParameter?.type?.needsMfvcFlattening() == true ||
function.extensionReceiverParameter?.type?.needsMfvcFlattening() == true ||
function.valueParameters.any { it.type.needsMfvcFlattening() }
)
private fun makeMultiFieldValueClassFieldGetterReplacement(function: IrFunction): IrSimpleFunction {
require(function is IrSimpleFunction && function.isMultiFieldValueClassFieldGetter) { "Illegal function:\n${function.dump()}" }
val replacement = getMfvcPropertyNode(function.correspondingPropertySymbol!!.owner)!!.unboxMethod
@@ -269,48 +274,51 @@ class MemoizedMultiFieldValueClassReplacements(
return replacement
}
override val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor? =
private val getReplacementForRegularClassConstructorImpl: (IrConstructor) -> IrConstructor? =
storageManager.createMemoizedFunctionWithNullableValues { constructor ->
when {
constructor.constructedClass.isMultiFieldValueClass -> null
constructor.isFromJava() -> null
constructor.fullValueParameterList.any { it.type.needsMfvcFlattening() } ->
createConstructorReplacement(constructor)
else -> null
constructor.isFromJava() -> null //is recursive so run once
else -> createConstructorReplacement(constructor)
}
}
override val replaceOverriddenSymbols: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol> =
storageManager.createMemoizedFunction { irSimpleFunction ->
irSimpleFunction.overriddenSymbols.map {
computeOverrideReplacement(it.owner).symbol
}
}
val getRootMfvcNode: (IrClass) -> RootMfvcNode? = storageManager.createMemoizedFunctionWithNullableValues {
if (it.defaultType.needsMfvcFlattening()) getRootNode(context, it) else null
override fun getReplacementForRegularClassConstructor(constructor: IrConstructor): IrConstructor? = when {
constructor.constructedClass.isMultiFieldValueClass -> null
constructor.valueParameters.none { it.type.needsMfvcFlattening() } -> null
else -> getReplacementForRegularClassConstructorImpl(constructor)
}
val getRegularClassMfvcPropertyNode: (IrProperty) -> IntermediateMfvcNode? =
storageManager.createMemoizedFunctionWithNullableValues { property: IrProperty ->
val parent = property.parent
when {
parent !is IrClass -> null
property.isFakeOverride -> null
property.getter.let { it != null && (it.contextReceiverParametersCount > 0 || it.extensionReceiverParameter != null) } -> null
useRootNode(parent, property) -> null
property.run { backingField?.type ?: getter?.returnType }?.needsMfvcFlattening() != true -> null
else -> createIntermediateNodeForMfvcPropertyOfRegularClass(parent, context, property)
}
val getRootMfvcNode: (IrClass) -> RootMfvcNode = storageManager.createMemoizedFunction {
require(it.defaultType.needsMfvcFlattening()) { it.defaultType.render() }
getRootNode(context, it)
}
fun getRootMfvcNodeOrNull(irClass: IrClass): RootMfvcNode? =
if (irClass.defaultType.needsMfvcFlattening()) getRootMfvcNode(irClass) else null
private val getRegularClassMfvcPropertyNodeImpl: (IrProperty) -> IntermediateMfvcNode =
storageManager.createMemoizedFunction { property: IrProperty ->
val parent = property.parentAsClass
createIntermediateNodeForMfvcPropertyOfRegularClass(parent, context, property)
}
fun getRegularClassMfvcPropertyNode(property: IrProperty): IntermediateMfvcNode? {
val parent = property.parent
return when {
property.run { backingField?.type ?: getter?.returnType }?.needsMfvcFlattening() != true -> null
parent !is IrClass -> null
property.isFakeOverride -> null
property.getter.let { it != null && (it.contextReceiverParametersCount > 0 || it.extensionReceiverParameter != null) } -> null
useRootNode(parent, property) -> null
else -> getRegularClassMfvcPropertyNodeImpl(property)
}
}
fun getMfvcPropertyNode(property: IrProperty): NameableMfvcNode? {
val parent = property.parent
return when {
parent !is IrClass -> null
useRootNode(parent, property) -> getRootMfvcNode(parent)!![property.name]
useRootNode(parent, property) -> getRootMfvcNode(parent)[property.name]
else -> getRegularClassMfvcPropertyNode(property)
}
}
@@ -16,15 +16,23 @@ import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.isInt
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import java.util.concurrent.ConcurrentHashMap
abstract class MemoizedValueClassAbstractReplacements(protected val irFactory: IrFactory, protected val context: JvmBackendContext) {
abstract class MemoizedValueClassAbstractReplacements(
protected val irFactory: IrFactory,
protected val context: JvmBackendContext,
protected val storageManager: LockBasedStorageManager
) {
private val propertyMap = ConcurrentHashMap<IrPropertySymbol, IrProperty>()
/**
* Get a replacement for a function or a constructor.
*/
abstract val getReplacementFunction: (IrFunction) -> IrSimpleFunction?
fun getReplacementFunction(function: IrFunction) =
if (quickCheckIfFunctionIsNotApplicable(function)) null else getReplacementFunctionImpl(function)
protected abstract val getReplacementFunctionImpl: (IrFunction) -> IrSimpleFunction?
protected fun IrFunction.isRemoveAtSpecialBuiltinStub() =
origin == IrDeclarationOrigin.IR_BUILTINS_STUB &&
@@ -106,12 +114,23 @@ abstract class MemoizedValueClassAbstractReplacements(protected val irFactory: I
body()
}
abstract val replaceOverriddenSymbols: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol>
private val replaceOverriddenSymbolsImpl: (IrSimpleFunction) -> List<IrSimpleFunctionSymbol> =
storageManager.createMemoizedFunction { irSimpleFunction ->
irSimpleFunction.overriddenSymbols.map {
computeOverrideReplacement(it.owner).symbol
}
}
abstract val getReplacementForRegularClassConstructor: (IrConstructor) -> IrConstructor?
fun replaceOverriddenSymbols(function: IrSimpleFunction): List<IrSimpleFunctionSymbol> =
if (function.overriddenSymbols.isEmpty()) listOf()
else replaceOverriddenSymbolsImpl(function)
protected fun computeOverrideReplacement(function: IrSimpleFunction): IrSimpleFunction =
abstract fun getReplacementForRegularClassConstructor(constructor: IrConstructor): IrConstructor?
private fun computeOverrideReplacement(function: IrSimpleFunction): IrSimpleFunction =
getReplacementFunction(function) ?: function.also {
function.overriddenSymbols = replaceOverriddenSymbols(function)
}
protected abstract fun quickCheckIfFunctionIsNotApplicable(function: IrFunction): Boolean
}
@@ -188,7 +188,7 @@ fun createIntermediateMfvcNode(
val representation = valueClass.multiFieldValueClassRepresentation!!
val replacements = context.multiFieldValueClassReplacements
val rootNode = replacements.getRootMfvcNode(valueClass)!!
val rootNode = replacements.getRootMfvcNode(valueClass)
val oldField = oldGetter?.correspondingPropertySymbol?.owner?.backingField