Prohibit from eliminating non-local temporary variables

This commit is contained in:
Alexey Andreev
2016-03-22 13:48:41 +03:00
parent af7ddb4572
commit 8709289b0a
9 changed files with 93 additions and 4 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.inline.clean
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.canHaveSideEffect
import org.jetbrains.kotlin.js.inline.util.collectDefinedNames
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
@@ -29,6 +30,7 @@ internal class TemporaryAssignmentElimination(private val root: JsBlock) {
private val mappedUsages = mutableMapOf<JsName, Usage>()
private val syntheticNames = mutableSetOf<JsName>()
private var hasChanges = false
private val namesToProcess = mutableSetOf<JsName>()
fun apply(): Boolean {
analyze()
@@ -39,6 +41,8 @@ internal class TemporaryAssignmentElimination(private val root: JsBlock) {
}
private fun analyze() {
namesToProcess.addAll(collectDefinedNames(root))
object : JsVisitorWithContextImpl() {
override fun visit(x: JsReturn, ctx: JsContext<*>): Boolean {
val returnExpr = x.expression
@@ -253,6 +257,7 @@ internal class TemporaryAssignmentElimination(private val root: JsBlock) {
private fun tryRecord(expr: JsExpression, usage: Usage): Boolean {
if (expr !is JsNameRef) return false
val name = expr.name ?: return false
if (name !in namesToProcess) return false
usages[name] = usage
return true
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.inline.clean
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.synthetic
import org.jetbrains.kotlin.js.inline.util.canHaveSideEffect
import org.jetbrains.kotlin.js.inline.util.collectDefinedNames
import org.jetbrains.kotlin.js.inline.util.collectFreeVariables
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
@@ -28,6 +29,7 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
private val definedValues = mutableMapOf<JsName, JsExpression>()
private val temporary = mutableSetOf<JsName>()
private var hasChanges = false
private val namesToProcess = mutableSetOf<JsName>()
fun apply(): Boolean {
analyze()
@@ -36,6 +38,8 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
}
private fun analyze() {
namesToProcess.addAll(collectDefinedNames(root))
object : JsVisitorWithContextImpl() {
val lastAssignedVars = mutableListOf<JsName>()
@@ -44,7 +48,7 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
if (name != null && x.qualifier == null) {
val expr = definedValues[name]
useVariable(name)
if (lastAssignedVars.lastOrNull() == name) {
if (lastAssignedVars.lastOrNull() == name && name in namesToProcess) {
lastAssignedVars.removeAt(lastAssignedVars.lastIndex)
}
else if (expr == null || expr.canHaveSideEffect()) {
@@ -95,7 +99,7 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
val (name, value) = assignment
assignVariable(name, value)
accept(value)
if (x.synthetic) {
if (x.synthetic && name in namesToProcess) {
temporary += name
}
else if (value.canHaveSideEffect()) {
@@ -24,4 +24,6 @@ class TemporaryAssignmentEliminationTest : BasicOptimizerTest("temporary-assignm
@Test fun returnStatement() = box()
@Test fun declaration() = box()
@Test fun skipsGlobalDeclarations() = box()
}
@@ -22,4 +22,6 @@ class TemporaryVariableEliminationTest : BasicOptimizerTest("temporary-variable"
@Test fun declaration() = box()
@Test fun assignment() = box()
@Test fun skipsGlobalDeclarations() = box()
}
@@ -10,10 +10,10 @@ function test(n) {
}
function box() {
var result = test(20)
var result = test(20);
if (result != 20) return "fail1: " + result;
result = test(-20)
result = test(-20);
if (result != 20) return "fail2: " + result;
return "OK"
@@ -0,0 +1,24 @@
var $tmp;
function test(n) {
if (n >= 0) {
$tmp = n;
}
else {
$tmp = -n;
}
var result = $tmp;
return result;
}
function box() {
var result = test(20);
if (result != 20) return "fail1: " + result;
result = test(-20);
if (result != 20) return "fail2: " + result;
if ($tmp != 20) return "fail3: " + result;
return "OK"
}
@@ -0,0 +1,24 @@
var $tmp;
function test(n) {
if (n >= 0) {
$tmp = n;
}
else {
$tmp = -n;
}
var result = $tmp;
return result;
}
function box() {
var result = test(20);
if (result != 20) return "fail1: " + result;
result = test(-20);
if (result != 20) return "fail2: " + result;
if ($tmp != 20) return "fail3: " + result;
return "OK"
}
@@ -0,0 +1,14 @@
var $tmp;
function test(a, b, c) {
$tmp = a + b;
return $tmp + c;
}
function box() {
var result = test(2, 3, 4);
if (result != 9) return "fail1: " + result;
if ($tmp != 5) return "fail2: " + $tmp;
return "OK"
}
@@ -0,0 +1,14 @@
var $tmp;
function test(a, b, c) {
$tmp = a + b;
return $tmp + c;
}
function box() {
var result = test(2, 3, 4);
if (result != 9) return "fail1: " + result;
if ($tmp != 5) return "fail2: " + $tmp;
return "OK"
}