[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:
committed by
Space Team
parent
89d5592622
commit
962265531e
+9
-9
@@ -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() }
|
||||
) {
|
||||
|
||||
+14
-12
@@ -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
|
||||
}
|
||||
|
||||
+41
-33
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+24
-5
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user