[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,