JS/Inlining: in temporary variable elimination don't treat FQN without side effects as trivial, i.e. disable moving these vars freely across function body
This commit is contained in:
@@ -22,7 +22,7 @@ class FunctionPostProcessor(root: JsFunction) {
|
|||||||
val optimizations = listOf(
|
val optimizations = listOf(
|
||||||
{ TemporaryAssignmentElimination(root.body).apply() },
|
{ TemporaryAssignmentElimination(root.body).apply() },
|
||||||
{ RedundantLabelRemoval(root.body).apply() },
|
{ RedundantLabelRemoval(root.body).apply() },
|
||||||
{ TemporaryVariableElimination(root.body).apply() },
|
{ TemporaryVariableElimination(root).apply() },
|
||||||
{ IfStatementReduction(root.body).apply() },
|
{ IfStatementReduction(root.body).apply() },
|
||||||
{ DeadCodeElimination(root.body).apply() },
|
{ DeadCodeElimination(root.body).apply() },
|
||||||
{ RedundantVariableDeclarationElimination(root.body).apply() },
|
{ RedundantVariableDeclarationElimination(root.body).apply() },
|
||||||
|
|||||||
+9
-21
@@ -19,18 +19,19 @@ package org.jetbrains.kotlin.js.inline.clean
|
|||||||
import com.google.dart.compiler.backend.js.ast.*
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
|
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
|
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
|
||||||
import org.jetbrains.kotlin.js.inline.util.collectDefinedNames
|
|
||||||
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
|
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
|
||||||
|
import org.jetbrains.kotlin.js.inline.util.collectLocalVariables
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
|
|
||||||
internal class TemporaryVariableElimination(private val root: JsStatement) {
|
internal class TemporaryVariableElimination(function: JsFunction) {
|
||||||
|
private val root = function.body
|
||||||
private val definitions = mutableMapOf<JsName, Int>()
|
private val definitions = mutableMapOf<JsName, Int>()
|
||||||
private val usages = mutableMapOf<JsName, Int>()
|
private val usages = mutableMapOf<JsName, Int>()
|
||||||
private val inconsistent = mutableSetOf<JsName>()
|
private val inconsistent = mutableSetOf<JsName>()
|
||||||
private val definedValues = mutableMapOf<JsName, JsExpression>()
|
private val definedValues = mutableMapOf<JsName, JsExpression>()
|
||||||
private val temporary = mutableSetOf<JsName>()
|
private val temporary = mutableSetOf<JsName>()
|
||||||
private var hasChanges = false
|
private var hasChanges = false
|
||||||
private val namesToProcess = mutableSetOf<JsName>()
|
private val namesToProcess = function.collectLocalVariables()
|
||||||
private val statementsToRemove = mutableSetOf<JsNode>()
|
private val statementsToRemove = mutableSetOf<JsNode>()
|
||||||
private val namesToSubstitute = mutableSetOf<JsName>()
|
private val namesToSubstitute = mutableSetOf<JsName>()
|
||||||
private val variablesToRemove = mutableSetOf<JsName>()
|
private val variablesToRemove = mutableSetOf<JsName>()
|
||||||
@@ -43,8 +44,6 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun analyze() {
|
private fun analyze() {
|
||||||
namesToProcess += collectDefinedNames(root)
|
|
||||||
|
|
||||||
object : RecursiveJsVisitor() {
|
object : RecursiveJsVisitor() {
|
||||||
val currentScope = mutableSetOf<JsName>()
|
val currentScope = mutableSetOf<JsName>()
|
||||||
var localVars = mutableSetOf<JsName>()
|
var localVars = mutableSetOf<JsName>()
|
||||||
@@ -543,22 +542,11 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
|||||||
|
|
||||||
private fun isTrivial(expr: JsExpression): Boolean = when (expr) {
|
private fun isTrivial(expr: JsExpression): Boolean = when (expr) {
|
||||||
is JsNameRef -> {
|
is JsNameRef -> {
|
||||||
val qualifier = expr.qualifier
|
val name = expr.name
|
||||||
if (qualifier == null) {
|
name in namesToProcess && when (definitions[name]) {
|
||||||
if (!expr.sideEffects) {
|
null, 0 -> true
|
||||||
true
|
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false
|
||||||
}
|
else -> false
|
||||||
else {
|
|
||||||
val name = expr.name
|
|
||||||
name != null && when (definitions[name] ?: 0) {
|
|
||||||
0 -> true
|
|
||||||
1 -> name !in namesToSubstitute || definedValues[name]?.let { isTrivial(it) } ?: false
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
!expr.sideEffects && isTrivial(qualifier)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is JsLiteral.JsValueLiteral -> true
|
is JsLiteral.JsValueLiteral -> true
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package foo
|
package foo
|
||||||
|
|
||||||
// CHECK_CONTAINS_NO_CALLS: test
|
// CHECK_CONTAINS_NO_CALLS: test
|
||||||
// CHECK_VARS_COUNT: function=test count=0
|
// CHECK_VARS_COUNT: function=test count=1
|
||||||
|
|
||||||
object SumHolder {
|
object SumHolder {
|
||||||
var sum = 0
|
var sum = 0
|
||||||
|
|||||||
Reference in New Issue
Block a user