[JS BE] Reduce temporary variable number produced during lowering

- Do not create temporary variable for pure expressions
 - Clean up unused and unreachable r-value on top level of statement block
This commit is contained in:
Roman Artemev
2019-12-07 14:05:11 +03:00
committed by romanart
parent fb3bd8a9ac
commit e4f83b96a3
4 changed files with 76 additions and 4 deletions
@@ -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
get() = this is IrSimpleFunctionSymbol && owner.isSuspend
@@ -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)
@@ -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<IrStatement>,
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 {
@@ -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<IrExpression>.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
}
}