diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 9fcd54c2cb9..4bf2ef88328 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.declarations.* @@ -605,4 +606,4 @@ fun copyBodyWithParametersMapping( } val IrSymbol.isSuspend: Boolean - get() = this is IrSimpleFunctionSymbol && owner.isSuspend \ No newline at end of file + get() = this is IrSimpleFunctionSymbol && owner.isSuspend diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt index 09c20f7bff4..d60ddc98086 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt @@ -13,10 +13,12 @@ import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.backend.js.utils.isPure import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.isNothing import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -51,6 +53,49 @@ abstract class AbstractBlockDecomposerLowering(context: CommonBackendContext) : else -> listOf(declaration) } } + + irDeclarationContainer.transformChildrenVoid(CodeCleaner()) + } + + private inner class CodeCleaner : IrElementTransformerVoid() { + + private fun IrStatementContainer.cleanUpStatements() { + var unreachable = false + + val newStatements = statements.filter { + when { + unreachable -> false + it.isPure(true) -> false + it is IrGetField -> it.receiver?.let { !it.isPure(true) } ?: false + else -> { + unreachable = it is IrExpression && it.type.isNothing() + true + } + } + } + + statements.clear() + + statements += newStatements + } + + override fun visitBlock(expression: IrBlock): IrExpression { + expression.transformChildrenVoid(this) + expression.cleanUpStatements() + return expression + } + + override fun visitBlockBody(body: IrBlockBody): IrBody { + body.transformChildrenVoid(this) + body.cleanUpStatements() + return body + } + + override fun visitComposite(expression: IrComposite): IrExpression { + expression.transformChildrenVoid(this) + expression.cleanUpStatements() + return expression + } } fun lower(irScript: IrScript) { @@ -527,6 +572,7 @@ class BlockDecomposerTransformer( compositesLeft == 0 -> value index == 0 && dontDetachFirstArgument -> value value == null -> value + value.isPure(false) -> value else -> { // TODO: do not wrap if value is pure (const, variable, etc) val irVar = makeTempVar(value.type, value) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt index c5ae8884950..e616b9b546c 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.backend.js.utils.isPure import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent @@ -200,9 +201,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass { newStatements: MutableList, declaration: IrDeclarationParent ): () -> IrExpressionWithCopy { - val varDeclaration = JsIrBuilder.buildVar(value.type, declaration, initializer = value) - newStatements += varDeclaration - return { JsIrBuilder.buildGetValue(varDeclaration.symbol) } + return if (value.isPure(true)) { + { value.deepCopyWithSymbols() as IrExpressionWithCopy } + } else { + val varDeclaration = JsIrBuilder.buildVar(value.type, declaration, initializer = value) + newStatements += varDeclaration + { JsIrBuilder.buildGetValue(varDeclaration.symbol) } + } } private fun generateTypeCheck(argument: () -> IrExpressionWithCopy, toType: IrType): IrExpression { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt index 290e2148117..fa9cde588a4 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/misc.kt @@ -6,14 +6,19 @@ package org.jetbrains.kotlin.ir.backend.js.utils import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue +import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.isNullableAny +import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.util.isTopLevelDeclaration import org.jetbrains.kotlin.name.Name @@ -38,4 +43,19 @@ fun List.toJsArrayLiteral(context: JsIrBackendContext, arrayType: return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply { putValueArgument(0, irVararg) } +} + +// TODO: support more cases like built-in operator call, getField and so on +fun IrStatement.isPure(anyVariable: Boolean): Boolean { + return when (this) { + is IrConst<*> -> true + is IrGetValue -> { + if (anyVariable) return true + val valueDeclaration = symbol.owner + if (valueDeclaration is IrVariable) !valueDeclaration.isVar + else true + } + is IrGetObjectValue -> type.isUnit() + else -> false + } } \ No newline at end of file