[JS IR] Fix code clean-up optimizations
- Do not create an extra variable/field for in some lowerings
This commit is contained in:
-47
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -20,7 +18,6 @@ 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
|
||||
@@ -80,49 +77,6 @@ abstract class AbstractBlockDecomposerLowering(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// irDeclarationContainer.transformChildrenVoid(CodeCleaner()) TODO
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrExpressionBody.toBlockBody(containingFunction: IrFunction): IrBlockBody {
|
||||
@@ -146,7 +100,6 @@ class BlockDecomposerTransformer(
|
||||
|
||||
private val constTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val constFalse get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val nothingType = context.irBuiltIns.nothingNType
|
||||
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
private val unitValue get() = JsIrBuilder.buildGetObjectValue(unitType, context.irBuiltIns.unitClass)
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
newStatements: MutableList<IrStatement>,
|
||||
declaration: IrDeclarationParent
|
||||
): () -> IrExpressionWithCopy {
|
||||
return if (value.isPure(true)) {
|
||||
return if (value.isPure(anyVariable = true, checkFields = false)) {
|
||||
{ value.deepCopyWithSymbols() as IrExpressionWithCopy }
|
||||
} else {
|
||||
val varDeclaration = JsIrBuilder.buildVar(value.type, declaration, initializer = value)
|
||||
|
||||
+46
-2
@@ -7,20 +7,28 @@ package org.jetbrains.kotlin.ir.backend.js.lower.cleanup
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.types.isNothing
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
class CleanupLowering : BodyLoweringPass {
|
||||
|
||||
private val blockRemover = BlockRemover()
|
||||
private val codeCleaner = CodeCleaner()
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.acceptVoid(BlockRemover())
|
||||
// TODO: merge passes together
|
||||
irBody.acceptVoid(blockRemover)
|
||||
irBody.acceptVoid(codeCleaner)
|
||||
}
|
||||
}
|
||||
|
||||
private class BlockRemover: IrElementVisitorVoid {
|
||||
private class BlockRemover : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
@@ -42,4 +50,40 @@ private class BlockRemover: IrElementVisitorVoid {
|
||||
|
||||
process(expression)
|
||||
}
|
||||
}
|
||||
|
||||
private class CodeCleaner : IrElementVisitorVoid {
|
||||
|
||||
private fun IrStatementContainer.cleanUpStatements() {
|
||||
var unreachable = false
|
||||
|
||||
val newStatements = statements.filter {
|
||||
when {
|
||||
unreachable -> false
|
||||
it is IrExpression && it.isPure(true) -> false
|
||||
else -> {
|
||||
unreachable = it is IrExpression && it.type.isNothing()
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statements.clear()
|
||||
|
||||
statements += newStatements
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitBlockBody(body: IrBlockBody) {
|
||||
super.visitBlockBody(body)
|
||||
body.cleanUpStatements()
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression) {
|
||||
super.visitContainerExpression(expression)
|
||||
expression.cleanUpStatements()
|
||||
}
|
||||
}
|
||||
+13
-9
@@ -15,6 +15,7 @@ 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.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -483,16 +484,19 @@ class StateMachineBuilder(
|
||||
val newArguments = arrayOfNulls<IrExpression>(arguments.size)
|
||||
|
||||
for ((i, arg) in arguments.withIndex()) {
|
||||
newArguments[i] = if (arg != null && suspendableCount > 0) {
|
||||
if (arg in suspendableNodes) suspendableCount--
|
||||
arg.acceptVoid(this)
|
||||
val irVar = tempVar(arg.type, "ARGUMENT")
|
||||
transformLastExpression {
|
||||
irVar.apply { initializer = it }
|
||||
newArguments[i] = if (arg.isPure(false)) arg else {
|
||||
require(arg != null)
|
||||
if (suspendableCount > 0) {
|
||||
if (arg in suspendableNodes) suspendableCount--
|
||||
arg.acceptVoid(this)
|
||||
val irVar = tempVar(arg.type, "ARGUMENT")
|
||||
transformLastExpression {
|
||||
irVar.apply { initializer = it }
|
||||
}
|
||||
JsIrBuilder.buildGetValue(irVar.symbol)
|
||||
} else {
|
||||
arg.deepCopyWithSymbols(function.owner)
|
||||
}
|
||||
JsIrBuilder.buildGetValue(irVar.symbol)
|
||||
} else {
|
||||
arg?.deepCopyWithSymbols(function.owner)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@ 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.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
@@ -45,17 +42,37 @@ fun List<IrExpression>.toJsArrayLiteral(context: JsIrBackendContext, arrayType:
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// TODO: support more cases like built-in operator call and so on
|
||||
|
||||
fun IrExpression?.isPure(anyVariable: Boolean, checkFields: Boolean = true): Boolean {
|
||||
if (this == null) return true
|
||||
|
||||
fun IrExpression.isPureImpl(): 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
|
||||
}
|
||||
is IrGetObjectValue -> type.isUnit()
|
||||
else -> false
|
||||
}
|
||||
|
||||
if (isPureImpl()) return true
|
||||
|
||||
if (!checkFields) return false
|
||||
|
||||
if (this is IrGetField) {
|
||||
if (!symbol.owner.isFinal) {
|
||||
if (!anyVariable) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return receiver.isPure(anyVariable)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user