JS/Inlining: introduce removal of unused variables
This commit is contained in:
+55
-3
@@ -33,6 +33,7 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
||||
private val namesToProcess = mutableSetOf<JsName>()
|
||||
private val statementsToRemove = mutableSetOf<JsNode>()
|
||||
private val namesToSubstitute = mutableSetOf<JsName>()
|
||||
private val variablesToRemove = mutableSetOf<JsName>()
|
||||
|
||||
fun apply(): Boolean {
|
||||
analyze()
|
||||
@@ -268,7 +269,13 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
||||
}
|
||||
return
|
||||
}
|
||||
else if (shouldConsiderUnused(name)) {
|
||||
variablesToRemove += name
|
||||
handleTopLevel(value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
handleTopLevel(expression)
|
||||
}
|
||||
|
||||
@@ -383,6 +390,9 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (shouldConsiderUnused(name)) {
|
||||
variablesToRemove += name
|
||||
}
|
||||
handleTopLevel(initializer)
|
||||
}
|
||||
}
|
||||
@@ -428,8 +438,33 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
||||
|
||||
private fun cleanUp() {
|
||||
object : JsVisitorWithContextImpl() {
|
||||
override fun visit(x: JsVars, ctx: JsContext<*>): Boolean {
|
||||
x.vars.removeAll { it in statementsToRemove }
|
||||
override fun visit(x: JsVars, ctx: JsContext<JsNode>): Boolean {
|
||||
x.vars.removeAll(statementsToRemove)
|
||||
|
||||
var lastDroppedIndex = 0
|
||||
for ((index, v) in x.vars.toList().withIndex()) {
|
||||
val name = v.name
|
||||
if (name in variablesToRemove) {
|
||||
hasChanges = true
|
||||
if (index > lastDroppedIndex) {
|
||||
val droppedVars = JsVars(*x.vars.subList(lastDroppedIndex, index).toTypedArray())
|
||||
droppedVars.synthetic = x.synthetic
|
||||
ctx.addPrevious(droppedVars)
|
||||
}
|
||||
val initExpression = v.initExpression
|
||||
if (initExpression != null) {
|
||||
ctx.addPrevious(JsExpressionStatement(initExpression).apply {
|
||||
synthetic = true
|
||||
accept(this)
|
||||
})
|
||||
}
|
||||
lastDroppedIndex = index + 1
|
||||
}
|
||||
}
|
||||
if (lastDroppedIndex > 0) {
|
||||
x.vars.subList(0, lastDroppedIndex).clear()
|
||||
}
|
||||
|
||||
if (x.vars.isEmpty()) {
|
||||
ctx.removeMe()
|
||||
hasChanges = true
|
||||
@@ -438,12 +473,27 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
||||
return super.visit(x, ctx)
|
||||
}
|
||||
|
||||
override fun visit(x: JsExpressionStatement, ctx: JsContext<*>): Boolean {
|
||||
override fun visit(x: JsExpressionStatement, ctx: JsContext<JsNode>): Boolean {
|
||||
if (x in statementsToRemove) {
|
||||
ctx.removeMe()
|
||||
hasChanges = true
|
||||
return false
|
||||
}
|
||||
|
||||
val assignment = JsAstUtils.decomposeAssignmentToVariable(x.expression)
|
||||
if (assignment != null) {
|
||||
val (name, value) = assignment
|
||||
if (name in variablesToRemove) {
|
||||
hasChanges = true
|
||||
JsExpressionStatement(value).apply {
|
||||
synthetic = true
|
||||
accept(this)
|
||||
ctx.replaceMe(this)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return super.visit(x, ctx)
|
||||
}
|
||||
|
||||
@@ -481,6 +531,8 @@ internal class TemporaryVariableElimination(private val root: JsStatement) {
|
||||
usages[name] = (usages[name] ?: 0) + 1
|
||||
}
|
||||
|
||||
private fun shouldConsiderUnused(name: JsName) = (definitions[name] ?: 0) == 1 && (usages[name] ?: 0) == 0 && name in temporary
|
||||
|
||||
private fun shouldConsiderTemporary(name: JsName): Boolean {
|
||||
if (definitions[name] ?: 0 != 1 || name !in temporary) return false
|
||||
|
||||
|
||||
+6
@@ -34,4 +34,10 @@ class TemporaryVariableEliminationTest : BasicOptimizerTest("temporary-variable"
|
||||
@Test fun nonSideEffect() = box()
|
||||
|
||||
@Test fun propertyAccess() = box()
|
||||
|
||||
@Test fun removeUnused() = box()
|
||||
|
||||
@Test fun innerExpressionProcessed() = box()
|
||||
|
||||
@Test fun transitiveNotConsideredTrivial() = box()
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
function box() {
|
||||
var a = 2;
|
||||
|
||||
return "OK";
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
function box() {
|
||||
var a = 2;
|
||||
var $b = a;
|
||||
var $c = 2 + $b;
|
||||
|
||||
return "OK";
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
var global = 0;
|
||||
|
||||
function test1() {
|
||||
global++;
|
||||
return global;
|
||||
}
|
||||
|
||||
function test2() {
|
||||
global++;
|
||||
return global;
|
||||
}
|
||||
|
||||
function test3() {
|
||||
global++;
|
||||
var $b = global--;
|
||||
return $b + $b;
|
||||
}
|
||||
|
||||
function box() {
|
||||
var result = test1();
|
||||
if (result != 1) return "fail1: " + result;
|
||||
|
||||
result = test2();
|
||||
if (result != 2) return "fail2: " + result;
|
||||
|
||||
result = test3();
|
||||
if (result != 6) return "fail3: " + result;
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
var global = 0;
|
||||
|
||||
function test1() {
|
||||
var $tmp = global++;
|
||||
return global;
|
||||
}
|
||||
|
||||
function test2() {
|
||||
var $tmp;
|
||||
$tmp = global++;
|
||||
return global;
|
||||
}
|
||||
|
||||
function test3() {
|
||||
var $a = global++, $b = global--;
|
||||
return $b + $b;
|
||||
}
|
||||
|
||||
function box() {
|
||||
var result = test1();
|
||||
if (result != 1) return "fail1: " + result;
|
||||
|
||||
result = test2();
|
||||
if (result != 2) return "fail2: " + result;
|
||||
|
||||
result = test3();
|
||||
if (result != 6) return "fail3: " + result;
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user