[JS IR] Optimize JS AST for closures

^KT-58891 Fixed
This commit is contained in:
Alexander Korepanov
2023-07-06 22:17:50 +02:00
committed by Space Team
parent 524c475834
commit a588e75c11
9 changed files with 136 additions and 2 deletions
@@ -30,6 +30,7 @@ fun optimizeProgramByIr(
fun optimizeFragmentByJsAst(fragment: JsIrProgramFragment) {
val optimizer = object : RecursiveJsVisitor() {
override fun visitFunction(x: JsFunction) {
super.visitFunction(x)
FunctionPostProcessor(x).apply()
}
@@ -19,5 +19,9 @@ package org.jetbrains.kotlin.js.testOld.optimizer
import org.junit.Test
class DeadCodeEliminationTest : BasicOptimizerTest("dead-code-elimination") {
@Test fun switchCases() = box()
}
@Test
fun switchCases() = box()
@Test
fun afterReturn() = box()
}
@@ -6928,6 +6928,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/jsAstOptimizations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("deadCodeElimination.kt")
public void testDeadCodeElimination() throws Exception {
runTest("js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt");
}
@Test
@TestMetadata("tempVarDeclOnAssignment.kt")
public void testTempVarDeclOnAssignment() throws Exception {
@@ -7034,6 +7034,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/jsAstOptimizations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@Test
@TestMetadata("deadCodeElimination.kt")
public void testDeadCodeElimination() throws Exception {
runTest("js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt");
}
@Test
@TestMetadata("tempVarDeclOnAssignment.kt")
public void testTempVarDeclOnAssignment() throws Exception {
@@ -6928,6 +6928,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/jsAstOptimizations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true);
}
@Test
@TestMetadata("deadCodeElimination.kt")
public void testDeadCodeElimination() throws Exception {
runTest("js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt");
}
@Test
@TestMetadata("tempVarDeclOnAssignment.kt")
public void testTempVarDeclOnAssignment() throws Exception {
@@ -0,0 +1,23 @@
// IGNORE_BACKEND_K2: JS_IR
// FIR works fine, however it generates another names for the temporary variables, therefore ignore it
fun demo(f: () -> String) = f()
// EXPECT_GENERATED_JS: function=test$lambda expect=deadCodeEliminationTestLambda.js
fun test(x: String?): String {
val r = demo {
val z = x ?: run {
return@demo "OK"
}
"Fail 1: $z"
}
return r
}
fun box(): String {
val r = test(null)
if (r != "OK") {
return "Fail test, got $r"
}
return "OK"
}
@@ -0,0 +1,15 @@
function test$lambda($x) {
return function () {
var tmp0_elvis_lhs = $x;
var tmp;
if (tmp0_elvis_lhs == null) {
// Inline function 'kotlin.run' call
// Inline function 'kotlin.contracts.contract' call
return 'OK';
} else {
tmp = tmp0_elvis_lhs;
}
var z = tmp;
return 'Fail 1: ' + z;
};
}
@@ -0,0 +1,34 @@
function test1(x) {
var $tmp;
if (x == null) {
return 'OK';
} else {
$tmp = x;
}
var z = $tmp;
return 'Fail 1: ' + z;
}
function test2(x) {
return function () {
var $tmp0_elvis_lhs = x;
var $tmp;
if ($tmp0_elvis_lhs == null) {
return 'OK';
} else {
$tmp = $tmp0_elvis_lhs;
}
var z = $tmp;
return 'Fail 1: ' + z;
}
}
function box() {
if (test1(null) != "OK") {
return "Fail test1";
}
if (test2(null)() != "OK") {
return "Fail test2";
}
return "OK"
}
@@ -0,0 +1,39 @@
function test1(x) {
var $tmp0_elvis_lhs = x;
var $tmp;
if ($tmp0_elvis_lhs == null) {
var $tmp$ret$0;
return 'OK';
$tmp = $tmp$ret$0;
} else {
$tmp = $tmp0_elvis_lhs;
}
var z = $tmp;
return 'Fail 1: ' + z;
}
function test2(x) {
return function () {
var $tmp0_elvis_lhs = x;
var $tmp;
if ($tmp0_elvis_lhs == null) {
var $tmp$ret$0;
return 'OK';
$tmp = $tmp$ret$0;
} else {
$tmp = $tmp0_elvis_lhs;
}
var z = $tmp;
return 'Fail 1: ' + z;
}
}
function box() {
if (test1(null) != "OK") {
return "Fail test1";
}
if (test2(null)() != "OK") {
return "Fail test2";
}
return "OK"
}