[K/Wasm] Convert non-capturing lambdas into singletons ^KT-64803 Fixed

This commit is contained in:
Artem Kobzar
2024-01-29 12:52:18 +00:00
committed by Space Team
parent e03f8b503f
commit 1fe77705b0
37 changed files with 245 additions and 20 deletions
@@ -286,7 +286,6 @@ private val singleAbstractMethodPhase = makeIrModulePhase(
description = "Replace SAM conversions with instances of interface-implementing classes"
)
private val localDelegatedPropertiesLoweringPhase = makeIrModulePhase<WasmBackendContext>(
{ LocalDelegatedPropertiesLowering() },
name = "LocalDelegatedPropertiesLowering",
@@ -307,6 +306,13 @@ private val localClassExtractionPhase = makeIrModulePhase(
prerequisite = setOf(localDeclarationsLoweringPhase)
)
private val staticCallableReferenceLoweringPhase = makeIrModulePhase(
::WasmStaticCallableReferenceLowering,
name = "WasmStaticCallableReferenceLowering",
description = "Turn static callable references into singletons",
prerequisite = setOf(callableReferencePhase, localClassExtractionPhase)
)
private val innerClassesLoweringPhase = makeIrModulePhase<WasmBackendContext>(
{ context -> InnerClassesLowering(context, context.innerClassesSupport) },
name = "InnerClassesLowering",
@@ -653,6 +659,7 @@ val loweringList = listOf(
localDelegatedPropertiesLoweringPhase,
localDeclarationsLoweringPhase,
localClassExtractionPhase,
staticCallableReferenceLoweringPhase,
innerClassesLoweringPhase,
innerClassesMemberBodyLoweringPhase,
innerClassConstructorCallsLoweringPhase,
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.dce
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
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.ir.backend.js.dce.UsefulDeclarationProcessor
import org.jetbrains.kotlin.ir.backend.js.utils.*
@@ -48,7 +49,7 @@ internal class WasmUsefulDeclarationProcessor(
}
override fun visitSetField(expression: IrSetField, data: IrDeclaration) {
if (!expression.symbol.owner.isObjectInstanceField()) {
if (!expression.symbol.owner.run { isObjectInstanceField() || isFunctionReferenceInstanceField() }) {
super.visitSetField(expression, data)
}
}
@@ -56,7 +57,7 @@ internal class WasmUsefulDeclarationProcessor(
override fun visitGetField(expression: IrGetField, data: IrDeclaration) {
val field = expression.symbol.owner
if (field.isObjectInstanceField()) {
if (field.isObjectInstanceField() || field.isFunctionReferenceInstanceField()) {
field.type.classOrFail.owner.primaryConstructor?.enqueue(field, "object lazy initialization")
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.wasm.dce
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.backend.js.utils.isObjectInstanceField
import org.jetbrains.kotlin.ir.declarations.*
@@ -56,7 +57,7 @@ class WasmUselessDeclarationsRemover(
private fun IrSimpleFunction.removeUnusedObjectsInitializers() {
(body as? IrBlockBody)?.statements?.removeIf {
it is IrSetField && it.symbol.owner.isObjectInstanceField() && it.symbol.owner !in usefulDeclarations
it is IrSetField && it.symbol.owner.run { isObjectInstanceField() || isFunctionReferenceInstanceField() } && it.symbol.owner !in usefulDeclarations
}
}
}
@@ -310,7 +310,7 @@ internal class WasmPropertyReferenceLowering(val context: WasmBackendContext) :
return type.classifier == expectedClass
}
private companion object {
private val DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION = IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")
companion object {
val DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION = IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")
}
}
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2024 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.wasm.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.getOrPut
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
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.descriptors.DescriptorVisibilities
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.LAMBDA_IMPL
import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irExprBody
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
class WasmStaticCallableReferenceLowering(val context: WasmBackendContext) : FileLoweringPass {
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() {
override fun visitClass(declaration: IrClass): IrStatement {
declaration.transformChildrenVoid()
if (declaration.isSyntheticSingleton) {
val functionReferenceField = declaration.getOrCreateInstanceField().apply {
parent = irFile
initializer = context.createIrBuilder(symbol).run {
irExprBody(irCall(declaration.primaryConstructor!!))
}
}
irFields.add(functionReferenceField)
}
return declaration
}
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
val constructedClass = expression.symbol.owner.constructedClass
if (!constructedClass.isSyntheticSingleton)
return super.visitConstructorCall(expression)
val instanceField = constructedClass.getOrCreateInstanceField()
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
get() = (origin == LAMBDA_IMPL || origin == FUNCTION_REFERENCE_IMPL) && primaryConstructor!!.valueParameters.isEmpty()