[Wasm] Fix inliner issues (KT-56584)

* Fix objects in inline functions and lambdas:
  * Add common lowerings used in K/JS and K/Native
* Fix inline lambda call detection logic in presence of additional casts


Merge-request: KT-MR-8791
Merged-by: Svyatoslav Kuzmich <svyatoslav.kuzmich@jetbrains.com>
This commit is contained in:
Svyatoslav Kuzmich
2023-02-13 13:14:43 +00:00
committed by Space Team
parent 1b5210b870
commit 26c1098a4f
21 changed files with 64 additions and 34 deletions
@@ -258,7 +258,7 @@ class FunctionInlining(
if (!isLambdaCall(expression)) if (!isLambdaCall(expression))
return super.visitCall(expression) return super.visitCall(expression)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue val dispatchReceiver = expression.dispatchReceiver?.unwrapAdditionalImplicitCastsIfNeeded() as IrGetValue
val functionArgument = substituteMap[dispatchReceiver.symbol.owner] ?: return super.visitCall(expression) val functionArgument = substituteMap[dispatchReceiver.symbol.owner] ?: return super.visitCall(expression)
if ((dispatchReceiver.symbol.owner as? IrValueParameter)?.isNoinline == true) if ((dispatchReceiver.symbol.owner as? IrValueParameter)?.isNoinline == true)
return super.visitCall(expression) return super.visitCall(expression)
@@ -414,6 +414,16 @@ class FunctionInlining(
else else
IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.IMPLICIT_CAST, type, this) IrTypeOperatorCallImpl(startOffset, endOffset, type, IrTypeOperator.IMPLICIT_CAST, type, this)
// With `insertAdditionalImplicitCasts` flag we sometimes insert
// casts to inline lambda parameters before calling `invoke` on them.
// Unwrapping these casts helps us satisfy inline lambda call detection logic.
private fun IrExpression.unwrapAdditionalImplicitCastsIfNeeded(): IrExpression {
if (insertAdditionalImplicitCasts && this is IrTypeOperatorCall && this.operator == IrTypeOperator.IMPLICIT_CAST) {
return this.argument.unwrapAdditionalImplicitCastsIfNeeded()
}
return this
}
private fun isLambdaCall(irCall: IrCall): Boolean { private fun isLambdaCall(irCall: IrCall): Boolean {
val callee = irCall.symbol.owner val callee = irCall.symbol.owner
val dispatchReceiver = callee.dispatchReceiverParameter ?: return false val dispatchReceiver = callee.dispatchReceiverParameter ?: return false
@@ -421,7 +431,7 @@ class FunctionInlining(
return (dispatchReceiver.type.isFunction() || dispatchReceiver.type.isSuspendFunction()) return (dispatchReceiver.type.isFunction() || dispatchReceiver.type.isSuspendFunction())
&& callee.name == OperatorNameConventions.INVOKE && callee.name == OperatorNameConventions.INVOKE
&& irCall.dispatchReceiver is IrGetValue && irCall.dispatchReceiver?.unwrapAdditionalImplicitCastsIfNeeded() is IrGetValue
} }
private inner class ParameterToArgument( private inner class ParameterToArgument(
@@ -10,6 +10,9 @@ import org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesExtractionFromInlineFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineLambdasLowering
import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.backend.common.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.backend.common.lower.optimizations.PropertyAccessorInlineLowering import org.jetbrains.kotlin.backend.common.lower.optimizations.PropertyAccessorInlineLowering
import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.common.phaser.*
@@ -110,6 +113,36 @@ private val lateinitUsageLoweringPhase = makeWasmModulePhase(
description = "Insert checks for lateinit field references" description = "Insert checks for lateinit field references"
) )
private val sharedVariablesLoweringPhase = makeWasmModulePhase(
::SharedVariablesLowering,
name = "SharedVariablesLowering",
description = "Box captured mutable variables",
prerequisite = setOf(
lateinitDeclarationLoweringPhase,
lateinitUsageLoweringPhase
)
)
private val localClassesInInlineLambdasPhase = makeWasmModulePhase(
::LocalClassesInInlineLambdasLowering,
name = "LocalClassesInInlineLambdasPhase",
description = "Extract local classes from inline lambdas",
)
private val localClassesInInlineFunctionsPhase = makeWasmModulePhase(
::LocalClassesInInlineFunctionsLowering,
name = "LocalClassesInInlineFunctionsPhase",
description = "Extract local classes from inline functions",
)
private val localClassesExtractionFromInlineFunctionsPhase = makeWasmModulePhase(
{ context -> LocalClassesExtractionFromInlineFunctionsLowering(context) },
name = "localClassesExtractionFromInlineFunctionsPhase",
description = "Move local classes from inline functions into nearest declaration container",
prerequisite = setOf(localClassesInInlineFunctionsPhase)
)
private val wrapInlineDeclarationsWithReifiedTypeParametersPhase = makeWasmModulePhase( private val wrapInlineDeclarationsWithReifiedTypeParametersPhase = makeWasmModulePhase(
::WrapInlineDeclarationsWithReifiedTypeParametersLowering, ::WrapInlineDeclarationsWithReifiedTypeParametersLowering,
name = "WrapInlineDeclarationsWithReifiedTypeParametersPhase", name = "WrapInlineDeclarationsWithReifiedTypeParametersPhase",
@@ -118,14 +151,20 @@ private val wrapInlineDeclarationsWithReifiedTypeParametersPhase = makeWasmModul
private val functionInliningPhase = makeCustomWasmModulePhase( private val functionInliningPhase = makeCustomWasmModulePhase(
{ context, module -> { context, module ->
FunctionInlining(context, null, true).inline(module) FunctionInlining(
context = context,
innerClassesSupport = context.innerClassesSupport,
insertAdditionalImplicitCasts = true,
).inline(module)
module.patchDeclarationParents() module.patchDeclarationParents()
}, },
name = "FunctionInliningPhase", name = "FunctionInliningPhase",
description = "Perform function inlining", description = "Perform function inlining",
prerequisite = setOf( prerequisite = setOf(
expectDeclarationsRemovingPhase, expectDeclarationsRemovingPhase,
wrapInlineDeclarationsWithReifiedTypeParametersPhase wrapInlineDeclarationsWithReifiedTypeParametersPhase,
localClassesInInlineLambdasPhase,
localClassesInInlineFunctionsPhase,
) )
) )
@@ -238,12 +277,6 @@ private val enumEntryRemovalLoweringPhase = makeWasmModulePhase(
) )
private val sharedVariablesLoweringPhase = makeWasmModulePhase(
::SharedVariablesLowering,
name = "SharedVariablesLowering",
description = "Box captured mutable variables"
)
private val propertyReferenceLowering = makeWasmModulePhase( private val propertyReferenceLowering = makeWasmModulePhase(
::WasmPropertyReferenceLowering, ::WasmPropertyReferenceLowering,
name = "WasmPropertyReferenceLowering", name = "WasmPropertyReferenceLowering",
@@ -563,6 +596,14 @@ val wasmPhases = SameTypeNamedCompilerPhase(
excludeDeclarationsFromCodegenPhase then excludeDeclarationsFromCodegenPhase then
expectDeclarationsRemovingPhase then expectDeclarationsRemovingPhase then
lateinitNullableFieldsPhase then
lateinitDeclarationLoweringPhase then
lateinitUsageLoweringPhase then
sharedVariablesLoweringPhase then
localClassesInInlineLambdasPhase then
localClassesInInlineFunctionsPhase then
localClassesExtractionFromInlineFunctionsPhase then
// TODO: Need some helpers from stdlib // TODO: Need some helpers from stdlib
// arrayConstructorPhase then // arrayConstructorPhase then
wrapInlineDeclarationsWithReifiedTypeParametersPhase then wrapInlineDeclarationsWithReifiedTypeParametersPhase then
@@ -570,9 +611,6 @@ val wasmPhases = SameTypeNamedCompilerPhase(
functionInliningPhase then functionInliningPhase then
removeInlineDeclarationsWithReifiedTypeParametersLoweringPhase then removeInlineDeclarationsWithReifiedTypeParametersLoweringPhase then
lateinitNullableFieldsPhase then
lateinitDeclarationLoweringPhase then
lateinitUsageLoweringPhase then
tailrecLoweringPhase then tailrecLoweringPhase then
enumClassConstructorLoweringPhase then enumClassConstructorLoweringPhase then
@@ -583,7 +621,6 @@ val wasmPhases = SameTypeNamedCompilerPhase(
enumEntryCreateGetInstancesFunsLoweringPhase then enumEntryCreateGetInstancesFunsLoweringPhase then
enumSyntheticFunsLoweringPhase then enumSyntheticFunsLoweringPhase then
sharedVariablesLoweringPhase then
propertyReferenceLowering then propertyReferenceLowering then
callableReferencePhase then callableReferencePhase then
singleAbstractMethodPhase then singleAbstractMethodPhase then
-2
View File
@@ -1,6 +1,4 @@
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: UNKNOWN
// WITH_STDLIB // WITH_STDLIB
interface Runnable { interface Runnable {
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// MODULE: lib // MODULE: lib
// FILE: lib.kt // FILE: lib.kt
interface I { interface I {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// KT-33992 // KT-33992
class P<T>(val a: T, val b: T) class P<T>(val a: T, val b: T)
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// FILE: utils.kt // FILE: utils.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// FILE: 1.kt // FILE: 1.kt
@@ -1,5 +1,5 @@
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// IGNORE_BACKEND: JVM, WASM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR
import kotlin.IllegalStateException import kotlin.IllegalStateException
@@ -1,5 +1,5 @@
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// IGNORE_BACKEND: JVM, WASM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR
import kotlin.IllegalStateException import kotlin.IllegalStateException
@@ -1,5 +1,5 @@
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// IGNORE_BACKEND: JVM, WASM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR
import kotlin.IllegalStateException import kotlin.IllegalStateException
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_OLD_AGAINST_IR
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// FILE: 1.kt // FILE: 1.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// FILE: 1.kt // FILE: 1.kt
class E(val x: String) { class E(val x: String) {
inner class Inner { inner class Inner {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// FILE: 1.kt // FILE: 1.kt
class O(val a: String) { class O(val a: String) {
inner class I1(val b: String) { inner class I1(val b: String) {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// FILE: 1.kt // FILE: 1.kt
class E(val x: String) { class E(val x: String) {
fun bar() = x fun bar() = x
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// FILE: 1.kt // FILE: 1.kt
class E<T>(val x: T) { class E<T>(val x: T) {
inner class Inner { inner class Inner {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_IR_AGAINST_OLD // IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_IR_AGAINST_OLD
// FILE: a.kt // FILE: a.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: WASM
// NO_CHECK_LAMBDA_INLINING // NO_CHECK_LAMBDA_INLINING
// FILE: 1.kt // FILE: 1.kt