[K/JS, K/Wasm] Optimize inline-class fields access
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InlineClassDeclarationLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InlineClassDeclarationLowering.kt index d7df101..7ca7937 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InlineClassDeclarationLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InlineClassDeclarationLowering.kt
@@ -31,6 +31,12 @@ private fun isClassInlineLike(irClass: IrClass): Boolean = context.inlineClassesUtils.isClassInlineLike(irClass) + private val IrSimpleFunction.isInlineClassFieldAccessor: Boolean + get() = correspondingPropertySymbol?.owner?.backingField != null + + private val IrSimpleFunction.shouldBeReplacedWithStaticMethod: Boolean + get() = !isStaticMethodOfClass && isReal && !isInlineClassFieldAccessor + val inlineClassDeclarationLowering = object : DeclarationTransformer { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { @@ -59,8 +65,7 @@ private fun transformMethodFlat(function: IrSimpleFunction): List<IrDeclaration>? { // TODO: Support fake-overridden methods without boxing - if (function.isStaticMethodOfClass || !function.isReal) - return null + if (!function.shouldBeReplacedWithStaticMethod) return null val staticMethod = getOrCreateStaticMethod(function) @@ -309,7 +314,15 @@ val typeParameters = extractTypeParameters(function.parentAsClass) + function.typeParameters for ((index, typeParameter) in typeParameters.withIndex()) { - putTypeArgument(index, IrSimpleTypeImpl(typeParameter.symbol, SimpleTypeNullability.NOT_SPECIFIED, emptyList(), emptyList())) + putTypeArgument( + index, + IrSimpleTypeImpl( + typeParameter.symbol, + SimpleTypeNullability.NOT_SPECIFIED, + emptyList(), + emptyList() + ) + ) } } ) @@ -332,6 +345,7 @@ override fun visitConstructorCall(expression: IrConstructorCall): IrExpression { expression.transformChildrenVoid(this) val function = expression.symbol.owner + if (!isClassInlineLike(function.parentAsClass)) { return expression } @@ -342,11 +356,8 @@ override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid(this) val function: IrSimpleFunction = expression.symbol.owner - if (function.parent !is IrClass || - function.isStaticMethodOfClass || - !isClassInlineLike(function.parentAsClass) || - !function.isReal - ) { + + if (function.parent !is IrClass || !isClassInlineLike(function.parentAsClass) || !function.shouldBeReplacedWithStaticMethod) { return expression } @@ -370,6 +381,26 @@ } } + + val inlineClassUsageOptimizationLowering = object : BodyLoweringPass { + override fun lower(irBody: IrBody, container: IrDeclaration) { + irBody.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + val function: IrSimpleFunction = expression.symbol.owner + val parentClass = function.parentClassOrNull + + val backingField = function.correspondingPropertySymbol?.owner?.backingField + ?.takeIf { parentClass != null && context.inlineClassesUtils.isClassInlineLike(parentClass) } + ?: return expression + + return context.createIrBuilder(expression.symbol).irGetField(expression.dispatchReceiver, backingField) + } + }) + } + } + private fun IrFunction.toInlineClassImplementationName(): Name { val newName = parentAsClass.name.asString() + "__" + name.asString() + INLINE_CLASS_IMPL_SUFFIX return when {
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt index 0a5727e..fb03347 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsLoweringPhases.kt
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLambdasLowering import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.backend.common.phaser.* -import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.ir.backend.js.lower.* import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering import org.jetbrains.kotlin.ir.backend.js.lower.cleanup.CleanupLowering @@ -22,7 +21,6 @@ import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendArityStoreLowering import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering import org.jetbrains.kotlin.ir.backend.js.lower.inline.* -import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsGenerationGranularity import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration import org.jetbrains.kotlin.platform.js.JsPlatforms @@ -646,6 +644,13 @@ description = "Insert box/unbox intrinsics" ) +private val inlineClassFieldUsageLoweringPhase = makeIrModulePhase( + { InlineClassLowering(it).inlineClassUsageOptimizationLowering }, + name = "InlineClassFieldUsageLowering", + description = "[Optimization] Handle inline class field usages", + prerequisite = setOf(autoboxingTransformerPhase) +) + private val blockDecomposerLoweringPhase = makeIrModulePhase( ::JsBlockDecomposerLowering, name = "BlockDecomposerLowering", @@ -863,6 +868,7 @@ inlineClassDeclarationLoweringPhase, inlineClassUsageLoweringPhase, autoboxingTransformerPhase, + inlineClassFieldUsageLoweringPhase, objectDeclarationLoweringPhase, blockDecomposerLoweringPhase, invokeStaticInitializersPhase,
diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 6c9f5f7..6770fb9 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt
@@ -450,6 +450,13 @@ description = "Insert box/unbox intrinsics" ) +private val inlineClassFieldUsageLoweringPhase = makeIrModulePhase( + { InlineClassLowering(it).inlineClassUsageOptimizationLowering }, + name = "InlineClassFieldUsageLowering", + description = "[Optimization] Handle inline class field usages", + prerequisite = setOf(autoboxingTransformerPhase) +) + private val staticMembersLoweringPhase = makeIrModulePhase( ::StaticMembersLowering, name = "StaticMembersLowering", @@ -711,6 +718,8 @@ autoboxingTransformerPhase, + inlineClassFieldUsageLoweringPhase, + objectUsageLoweringPhase, purifyObjectInstanceGettersLoweringPhase, fieldInitializersLoweringPhase,