[K/Wasm] Refactor the fix for the non-capturing lambda singletons

This commit is contained in:
Artem Kobzar
2024-02-01 18:13:37 +00:00
committed by Space Team
parent 968ecadff2
commit 2fdc8b6c14
14 changed files with 26 additions and 66 deletions
@@ -26,7 +26,6 @@ class JsMapping : DefaultMapping() {
val secondaryConstructorToFactory = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrSimpleFunction>() val secondaryConstructorToFactory = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrSimpleFunction>()
val objectToGetInstanceFunction = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>() val objectToGetInstanceFunction = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>()
val objectToInstanceField = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>() val objectToInstanceField = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
val functionToInstanceField = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
val classToSyntheticPrimaryConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>() val classToSyntheticPrimaryConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
val privateMemberToCorrespondingStatic = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrFunction, IrSimpleFunction>() val privateMemberToCorrespondingStatic = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrFunction, IrSimpleFunction>()
@@ -475,12 +475,6 @@ private val wasmVarargExpressionLoweringPhase = makeIrModulePhase(
description = "Lower varargs" description = "Lower varargs"
) )
private val fieldInitializersLoweringPhase = makeIrModulePhase(
::FieldInitializersLowering,
name = "FieldInitializersLowering",
description = "Move field initializers to start function"
)
private val builtInsLoweringPhase0 = makeIrModulePhase( private val builtInsLoweringPhase0 = makeIrModulePhase(
::BuiltInsLowering, ::BuiltInsLowering,
name = "BuiltInsLowering0", name = "BuiltInsLowering0",
@@ -505,7 +499,7 @@ private val objectDeclarationLoweringPhase = makeIrModulePhase(
::ObjectDeclarationLowering, ::ObjectDeclarationLowering,
name = "ObjectDeclarationLowering", name = "ObjectDeclarationLowering",
description = "Create lazy object instance generator functions", description = "Create lazy object instance generator functions",
prerequisite = setOf(enumClassCreateInitializerLoweringPhase) prerequisite = setOf(enumClassCreateInitializerLoweringPhase, staticCallableReferenceLoweringPhase)
) )
private val objectUsageLoweringPhase = makeIrModulePhase( private val objectUsageLoweringPhase = makeIrModulePhase(
@@ -606,6 +600,13 @@ private val inlineObjectsWithPureInitializationLoweringPhase = makeIrModulePhase
prerequisite = setOf(purifyObjectInstanceGettersLoweringPhase) prerequisite = setOf(purifyObjectInstanceGettersLoweringPhase)
) )
private val fieldInitializersLoweringPhase = makeIrModulePhase(
::FieldInitializersLowering,
name = "FieldInitializersLowering",
description = "Move field initializers to start function",
prerequisite = setOf(purifyObjectInstanceGettersLoweringPhase)
)
val constEvaluationPhase = makeIrModulePhase( val constEvaluationPhase = makeIrModulePhase(
{ context -> { context ->
val configuration = IrInterpreterConfiguration( val configuration = IrInterpreterConfiguration(
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.wasm.dce
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.backend.wasm.ir2wasm.* import org.jetbrains.kotlin.backend.wasm.ir2wasm.*
import org.jetbrains.kotlin.backend.wasm.lower.isFunctionReferenceInstanceField
import org.jetbrains.kotlin.backend.wasm.utils.* import org.jetbrains.kotlin.backend.wasm.utils.*
import org.jetbrains.kotlin.ir.backend.js.dce.UsefulDeclarationProcessor import org.jetbrains.kotlin.ir.backend.js.dce.UsefulDeclarationProcessor
import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.backend.js.utils.*
@@ -49,7 +48,7 @@ internal class WasmUsefulDeclarationProcessor(
} }
override fun visitSetField(expression: IrSetField, data: IrDeclaration) { override fun visitSetField(expression: IrSetField, data: IrDeclaration) {
if (!expression.symbol.owner.run { isObjectInstanceField() || isFunctionReferenceInstanceField() }) { if (!expression.symbol.owner.isObjectInstanceField()) {
super.visitSetField(expression, data) super.visitSetField(expression, data)
} }
} }
@@ -57,7 +56,7 @@ internal class WasmUsefulDeclarationProcessor(
override fun visitGetField(expression: IrGetField, data: IrDeclaration) { override fun visitGetField(expression: IrGetField, data: IrDeclaration) {
val field = expression.symbol.owner val field = expression.symbol.owner
if (field.isObjectInstanceField() || field.isFunctionReferenceInstanceField()) { if (field.isObjectInstanceField()) {
field.type.classOrFail.owner.primaryConstructor?.enqueue(field, "object lazy initialization") field.type.classOrFail.owner.primaryConstructor?.enqueue(field, "object lazy initialization")
} }
@@ -6,14 +6,11 @@
package org.jetbrains.kotlin.backend.wasm.dce package org.jetbrains.kotlin.backend.wasm.dce
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.backend.wasm.lower.isFunctionReferenceInstanceField
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.utils.isObjectInstanceField import org.jetbrains.kotlin.ir.backend.js.utils.isObjectInstanceField
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrSetField import org.jetbrains.kotlin.ir.expressions.IrSetField
import org.jetbrains.kotlin.ir.types.classOrFail
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -57,7 +54,7 @@ class WasmUselessDeclarationsRemover(
private fun IrSimpleFunction.removeUnusedObjectsInitializers() { private fun IrSimpleFunction.removeUnusedObjectsInitializers() {
(body as? IrBlockBody)?.statements?.removeIf { (body as? IrBlockBody)?.statements?.removeIf {
it is IrSetField && it.symbol.owner.run { isObjectInstanceField() || isFunctionReferenceInstanceField() } && it.symbol.owner !in usefulDeclarations it is IrSetField && it.symbol.owner.isObjectInstanceField() && it.symbol.owner !in usefulDeclarations
} }
} }
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.utils.isObjectInstanceField
import org.jetbrains.kotlin.ir.builders.irSetField import org.jetbrains.kotlin.ir.builders.irSetField
import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -55,9 +56,11 @@ class FieldInitializersLowering(val context: WasmBackendContext) : FileLoweringP
} }
val initializerStatement = builder.at(initValue).irSetField(null, declaration, initValue) val initializerStatement = builder.at(initValue).irSetField(null, declaration, initValue)
val statements = startFunctionBody.statements
when (declaration.fqNameWhenAvailable) { when {
stringPoolFqName -> startFunctionBody.statements.add(0, initializerStatement) declaration.fqNameWhenAvailable == stringPoolFqName -> statements.add(0, initializerStatement)
declaration.isObjectInstanceField() -> statements.add(if (statements.size >= 1) 1 else 0, initializerStatement)
else -> startFunctionBody.statements.add(initializerStatement) else -> startFunctionBody.statements.add(initializerStatement)
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.getOrPut
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.backend.wasm.lower.WasmPropertyReferenceLowering.Companion.DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION import org.jetbrains.kotlin.backend.wasm.lower.WasmPropertyReferenceLowering.Companion.DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceLowering.Companion.FUNCTION_REFERENCE_IMPL import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceLowering.Companion.FUNCTION_REFERENCE_IMPL
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.constructedClass import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
@@ -31,20 +33,11 @@ import org.jetbrains.kotlin.name.Name
class WasmStaticCallableReferenceLowering(val context: WasmBackendContext) : FileLoweringPass { class WasmStaticCallableReferenceLowering(val context: WasmBackendContext) : FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
val irFields = mutableSetOf<IrField>()
val firstKProperty = irFile.declarations.indexOfFirst { it.origin == DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION }
irFile.transformChildrenVoid(object : IrElementTransformerVoid() { irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement { override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid() declaration.transformChildrenVoid()
if (declaration.isSyntheticSingleton) { if (declaration.isSyntheticSingleton) {
val functionReferenceField = declaration.getOrCreateInstanceField().apply { declaration.kind = ClassKind.OBJECT
parent = irFile
initializer = context.createIrBuilder(symbol).run {
irExprBody(irCall(declaration.primaryConstructor!!))
}
}
irFields.add(functionReferenceField)
} }
return declaration return declaration
} }
@@ -54,39 +47,10 @@ class WasmStaticCallableReferenceLowering(val context: WasmBackendContext) : Fil
if (!constructedClass.isSyntheticSingleton) if (!constructedClass.isSyntheticSingleton)
return super.visitConstructorCall(expression) return super.visitConstructorCall(expression)
val instanceField = constructedClass.getOrCreateInstanceField() return IrGetObjectValueImpl(expression.startOffset, expression.endOffset, expression.type, constructedClass.symbol)
return IrGetFieldImpl(expression.startOffset, expression.endOffset, instanceField.symbol, expression.type)
} }
}) })
// Should be placed before KProperty initializations
if (firstKProperty != -1) {
irFile.declarations.addAll(firstKProperty, irFields)
} else {
irFile.declarations.addAll(irFields)
}
} }
private fun IrClass.getOrCreateInstanceField(): IrField = context.mapping.functionToInstanceField.getOrPut(this) {
val klass = this
context.irFactory.buildField {
name = Name.identifier(klass.name.asString() + "_instance")
type = klass.defaultType.makeNullable()
isStatic = true
isFinal = true
origin = FUNCTION_REFERENCE_SINGLETON_FIELD
visibility = DescriptorVisibilities.PRIVATE
}.apply {
initializer = null
}
}
}
val FUNCTION_REFERENCE_SINGLETON_FIELD by IrDeclarationOriginImpl
fun IrField.isFunctionReferenceInstanceField(): Boolean {
return origin == FUNCTION_REFERENCE_SINGLETON_FIELD
} }
val IrClass.isSyntheticSingleton: Boolean val IrClass.isSyntheticSingleton: Boolean
+1 -1
View File
@@ -25,7 +25,7 @@ fun box() {
// EXPECTATIONS WASM // EXPECTATIONS WASM
// test.kt:1 $box // test.kt:1 $box
// test.kt:7 $box (9, 4) // test.kt:7 $box
// test.kt:4 $eval (27, 30) // test.kt:4 $eval (27, 30)
// test.kt:8 $box$lambda.invoke (9, 9, 9, 9) // test.kt:8 $box$lambda.invoke (9, 9, 9, 9)
// String.kt:141 $kotlin.stringLiteral (17, 28, 17) // String.kt:141 $kotlin.stringLiteral (17, 28, 17)
+1 -1
View File
@@ -248,7 +248,7 @@ fun box() {
// Number2String.kt:61 $kotlin.wasm.internal.utoa32 (28, 14) // Number2String.kt:61 $kotlin.wasm.internal.utoa32 (28, 14)
// Number2String.kt:63 $kotlin.wasm.internal.utoa32 (18, 23, 35, 4) // Number2String.kt:63 $kotlin.wasm.internal.utoa32 (18, 23, 35, 4)
// Number2String.kt:69 $kotlin.wasm.internal.utoaDecSimple (11, 23, 11, 11, 4) // Number2String.kt:69 $kotlin.wasm.internal.utoaDecSimple (11, 23, 11, 11, 4)
// Assertions.kt:14 $kotlin.assert (11, 18, 4, 11, 18, 4, 11, 18, 4, 11, 18, 4) // Assertions.kt:14 $kotlin.assert (11, 4, 11, 4, 11, 4, 11, 4)
// Assertions.kt:21 $kotlin.assert (9, 8, 9, 8, 9, 8, 9, 8) // Assertions.kt:21 $kotlin.assert (9, 8, 9, 8, 9, 8, 9, 8)
// Assertions.kt:25 $kotlin.assert (1, 1, 1, 1) // Assertions.kt:25 $kotlin.assert (1, 1, 1, 1)
// Assertions.kt:15 $kotlin.assert (1, 1, 1, 1) // Assertions.kt:15 $kotlin.assert (1, 1, 1, 1)
@@ -45,10 +45,10 @@ fun foo(f: () -> Unit) {
// EXPECTATIONS WASM // EXPECTATIONS WASM
// test.kt:1 $box // test.kt:1 $box
// test.kt:5 $box (8, 4) // test.kt:5 $box
// test.kt:15 $foo (4, 4) // test.kt:15 $foo (4, 4)
// test.kt:6 $box$lambda.invoke (20, 12, 21) // test.kt:6 $box$lambda.invoke (20, 12, 21)
// test.kt:16 $foo (1, 1) // test.kt:16 $foo (1, 1)
// test.kt:9 $box (10, 4) // test.kt:9 $box
// test.kt:10 $box$lambda.invoke (16, 8, 17) // test.kt:10 $box$lambda.invoke (16, 8, 17)
// test.kt:12 $box // test.kt:12 $box
-1
View File
@@ -27,7 +27,6 @@ inline fun foo() = {
// EXPECTATIONS WASM // EXPECTATIONS WASM
// test.kt:1 $box // test.kt:1 $box
// test.kt:6 $box (4, 4) // test.kt:6 $box (4, 4)
// test1.kt:10 $box
// test1.kt:11 $box // test1.kt:11 $box
// test.kt:8 $box$lambda.invoke // test.kt:8 $box$lambda.invoke
// test.kt:7 $box // test.kt:7 $box
-1
View File
@@ -30,7 +30,6 @@ inline fun foo() = {
// EXPECTATIONS WASM // EXPECTATIONS WASM
// test.kt:1 $box // test.kt:1 $box
// test.kt:6 $box // test.kt:6 $box
// test1.kt:11 $box
// test1.kt:12 $box // test1.kt:12 $box
// test.kt:7 $box // test.kt:7 $box
// test.kt:9 $box$lambda.invoke // test.kt:9 $box$lambda.invoke
-1
View File
@@ -52,7 +52,6 @@ fun baz(v:(() -> Unit)) {
// EXPECTATIONS WASM // EXPECTATIONS WASM
// test.kt:1 $box // test.kt:1 $box
// test.kt:6 $box (8, 4) // test.kt:6 $box (8, 4)
// test1.kt:12 $box (19, 19)
// test1.kt:13 $box (1, 1) // test1.kt:13 $box (1, 1)
// test3.kt:16 $baz (4, 4) // test3.kt:16 $baz (4, 4)
// test.kt:10 $box$lambda.invoke // test.kt:10 $box$lambda.invoke
+1 -1
View File
@@ -35,7 +35,7 @@ fun g() {}
// EXPECTATIONS WASM // EXPECTATIONS WASM
// test.kt:1 $box // test.kt:1 $box
// test.kt:4 $box (12, 4) // test.kt:4 $box (12, 4)
// test.kt:5 $box (6, 4) // test.kt:5 $box
// test.kt:9 $f // test.kt:9 $f
// test.kt:12 $g // test.kt:12 $g
// test.kt:10 $f // test.kt:10 $f
@@ -68,7 +68,7 @@ fun box() {
// Number2String.kt:61 $kotlin.wasm.internal.utoa32 (28, 14) // Number2String.kt:61 $kotlin.wasm.internal.utoa32 (28, 14)
// Number2String.kt:63 $kotlin.wasm.internal.utoa32 (18, 23, 35, 4) // Number2String.kt:63 $kotlin.wasm.internal.utoa32 (18, 23, 35, 4)
// Number2String.kt:69 $kotlin.wasm.internal.utoaDecSimple (11, 23, 11, 11, 4) // Number2String.kt:69 $kotlin.wasm.internal.utoaDecSimple (11, 23, 11, 11, 4)
// Assertions.kt:14 $kotlin.assert (11, 18, 4, 11, 18, 4, 11, 18, 4, 11, 18, 4, 11, 18, 4) // Assertions.kt:14 $kotlin.assert (11, 4, 11, 4, 11, 4, 11, 4, 11, 4)
// Assertions.kt:21 $kotlin.assert (9, 8, 9, 8, 9, 8, 9, 8, 9, 8) // Assertions.kt:21 $kotlin.assert (9, 8, 9, 8, 9, 8, 9, 8, 9, 8)
// Assertions.kt:25 $kotlin.assert (1, 1, 1, 1, 1) // Assertions.kt:25 $kotlin.assert (1, 1, 1, 1, 1)
// Assertions.kt:15 $kotlin.assert (1, 1, 1, 1, 1) // Assertions.kt:15 $kotlin.assert (1, 1, 1, 1, 1)