diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt index f8b9179477c..1714f307d36 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/FunctionPostProcessor.kt @@ -22,6 +22,7 @@ class FunctionPostProcessor(root: JsFunction) { val optimizations = listOf( { TemporaryAssignmentElimination(root.body).apply() }, { RedundantLabelRemoval(root.body).apply() }, + { WhileConditionFolding(root.body).apply() }, { DoWhileGuardElimination(root.body).apply() }, { TemporaryVariableElimination(root).apply() }, { RedundantBindElimination(root.body).apply() }, diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/WhileConditionFolding.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/WhileConditionFolding.kt new file mode 100644 index 00000000000..d946da41d2d --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/WhileConditionFolding.kt @@ -0,0 +1,251 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.inline.clean + +import com.google.dart.compiler.backend.js.ast.* +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils + +class WhileConditionFolding(val body: JsBlock) { + private var changed = false + + fun apply(): Boolean { + body.accept(object : RecursiveJsVisitor() { + override fun visitLabel(x: JsLabel) { + val innerStatement = x.statement + when (innerStatement) { + is JsWhile -> process(innerStatement, x.name) + is JsDoWhile -> process(innerStatement, x.name) + else -> super.visitLabel(x) + } + } + + override fun visitWhile(x: JsWhile) { + process(x, null) + } + + override fun visitDoWhile(x: JsDoWhile) { + process(x, null) + } + + private fun process(statement: JsWhile, name: JsName?) { + process(statement, name, { first(it) }, { removeFirst(it) }, { a, b -> JsAstUtils.and(a, b) }) + } + + private fun process(statement: JsDoWhile, name: JsName?) { + if (!hasContinue(statement.body, name)) { + process(statement, name, { last(it) }, { removeLast(it) }, { a, b -> JsAstUtils.and(b, a) }) + } + } + + private fun process( + statement: JsWhile, + name: JsName?, + find: (JsStatement) -> JsStatement, + remove: (JsStatement) -> JsStatement, + combine: (JsExpression, JsExpression) -> JsExpression + ) { + statement.body.accept(this) + do { + var optimized = false + val first = find(statement.body) + val condition = extractCondition(first, name) + if (condition != null) { + statement.body = remove(statement.body) + val existingCondition = statement.condition + statement.condition = when (existingCondition) { + JsLiteral.TRUE -> condition + else -> combine(existingCondition, condition) + } + changed = true + optimized = true + } + } while (optimized) + } + + /** + * Gets condition from while or do..while body and convert it into while/do..while condition + * + * For example, + * + * while (true) { + * if (!A) break; + * B() + * } + * + * This function should return `A`, (negated condition of if statement). + */ + private fun extractCondition(statement: JsStatement, label: JsName?): JsExpression? = when (statement) { + // Code like this + // + // while (A) { + // break; + // B(); + // } + // + // can be rewritten as + // + // while (A && false) { + // B(); + // } + // + // therefore for single `break` we should return `false`. + is JsBreak -> { + val target = statement.label?.name + if (label == null || label == target) JsLiteral.FALSE else null + } + + // Code like this + // + // while (A) { + // if (!B) + // X; + // D(); + // } + // + // where X is a statement, and we can extract condition `C` from it, can be rewritten as + // + // while (A && (B || C)) { + // D() + // } + // therefore we return B || C + // + // an example is + // + // while (A) { + // if (!B) + // if (!C) + // break; + // D() + // } + // + // applying this rule repeatedly we get while (A && (B || C)), which is correct + + is JsIf -> { + val then = statement.thenStatement!! + if (statement.elseStatement == null) { + val nextCondition = extractCondition(then, label) + val result: JsExpression? = when (nextCondition) { + // Just a little optimization. When inner statement is a single `break`, `nextCondition` would be false. + // However, `A || false` can be rewritten as simply `A` + JsLiteral.FALSE -> JsAstUtils.negatedOptimized(statement.ifExpression) + null -> null + else -> JsAstUtils.or(JsAstUtils.negatedOptimized(statement.ifExpression), nextCondition) + } + result + } + else { + null + } + } + + // A single block containing a statement with extractable condition + is JsBlock -> { + if (statement.statements.size == 1) extractCondition(statement.statements[0], label) else null + } + else -> null + } + + private fun first(statement: JsStatement) = when (statement) { + is JsBlock -> statement.statements.firstOrNull() ?: statement + else -> statement + } + + private fun removeFirst(statement: JsStatement) = when (statement) { + is JsBlock -> { + val statements = statement.statements + if (statements.isNotEmpty()) { + statements.removeAt(0) + } + statement + } + else -> JsBlock() + } + + private fun last(statement: JsStatement) = when (statement) { + is JsBlock -> statement.statements.lastOrNull() ?: statement + else -> statement + } + + private fun removeLast(statement: JsStatement) = when (statement) { + is JsBlock -> { + val statements = statement.statements + if (statements.isNotEmpty()) { + statements.removeAt(statements.lastIndex) + } + statement + } + else -> JsBlock() + } + + override fun visitFunction(x: JsFunction) { } + }) + + return changed + } + + private fun hasContinue(statement: JsStatement, label: JsName?): Boolean { + var found = false + statement.accept(object : RecursiveJsVisitor() { + private var level = 0 + + override fun visitContinue(x: JsContinue) { + val name = x.label?.name + if (name == null) { + if (level == 0) { + found = true + } + } + else if (name == label) { + found = true + } + } + + override fun visitFor(x: JsFor) { + level++ + super.visitFor(x) + level-- + } + + override fun visitWhile(x: JsWhile) { + level++ + super.visitWhile(x) + level-- + } + + override fun visitDoWhile(x: JsDoWhile) { + level++ + super.visitDoWhile(x) + level-- + } + + override fun visitForIn(x: JsForIn) { + level++ + super.visitForIn(x) + level-- + } + + override fun visitFunction(x: JsFunction) { } + + override fun visitElement(node: JsNode) { + if (!found) { + super.visitElement(node) + } + } + }) + return found + } +} \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/WhileConditionFoldingTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/WhileConditionFoldingTest.kt new file mode 100644 index 00000000000..c3f7fddd79e --- /dev/null +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/WhileConditionFoldingTest.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.js.test.optimizer + +import org.junit.Test + +class WhileConditionFoldingTest : BasicOptimizerTest("while-condition-folding") { + @Test fun simpleWhile() = box() + + @Test fun simpleDoWhile() = box() + + @Test fun consequentConditions() = box() + + @Test fun nestedConditions() = box() + + @Test fun doWhileWithContinue() = box() + + @Test fun whileEvaluationOrder() = box() + + @Test fun doWhileEvaluationOrder() = box() + + @Test fun inNestedLoop() = box() + + @Test fun inLabeledBlock() = box() + + @Test fun doWhileWithNestedContinue() = box() + + @Test fun labeledContinueInNestedLoop() = box() +} \ No newline at end of file diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java index ce30cb65fea..db65a6edefa 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java @@ -36,7 +36,6 @@ import org.jetbrains.kotlin.js.translate.general.AbstractTranslator; import org.jetbrains.kotlin.js.translate.general.Translation; import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF; import org.jetbrains.kotlin.js.translate.utils.BindingUtils; -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.name.Name; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java index f6e69b2d081..f00dd8c4df4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java @@ -238,6 +238,43 @@ public final class JsAstUtils { return new JsPrefixOperation(JsUnaryOperator.NOT, expression); } + @NotNull + public static JsExpression negatedOptimized(@NotNull JsExpression expression) { + if (expression instanceof JsUnaryOperation) { + JsUnaryOperation unary = (JsUnaryOperation) expression; + if (unary.getOperator() == JsUnaryOperator.NOT) return unary.getArg(); + } + else if (expression instanceof JsBinaryOperation) { + JsBinaryOperation binary = (JsBinaryOperation) expression; + switch (binary.getOperator()) { + case AND: + return or(negatedOptimized(binary.getArg1()), negatedOptimized(binary.getArg2())); + case OR: + return and(negatedOptimized(binary.getArg1()), negatedOptimized(binary.getArg2())); + case EQ: + return new JsBinaryOperation(JsBinaryOperator.NEQ, binary.getArg1(), binary.getArg2()); + case NEQ: + return new JsBinaryOperation(JsBinaryOperator.EQ, binary.getArg1(), binary.getArg2()); + case REF_EQ: + return inequality(binary.getArg1(), binary.getArg2()); + case REF_NEQ: + return equality(binary.getArg1(), binary.getArg2()); + case LT: + return greaterThanEq(binary.getArg1(), binary.getArg2()); + case LTE: + return greaterThan(binary.getArg1(), binary.getArg2()); + case GT: + return lessThanEq(binary.getArg1(), binary.getArg2()); + case GTE: + return lessThan(binary.getArg1(), binary.getArg2()); + default: + break; + } + } + + return negated(expression); + } + @NotNull public static JsBinaryOperation and(@NotNull JsExpression op1, @NotNull JsExpression op2) { return new JsBinaryOperation(JsBinaryOperator.AND, op1, op2); diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/consequentConditions.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/consequentConditions.optimized.js new file mode 100644 index 00000000000..f29be267e58 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/consequentConditions.optimized.js @@ -0,0 +1,12 @@ +function box() { + var i = 1; + var sum = 0; + while (i < 10 && sum <= 30) { + sum += i; + i++ + } + + if (sum != 36) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/consequentConditions.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/consequentConditions.original.js new file mode 100644 index 00000000000..95d5ab49c23 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/consequentConditions.original.js @@ -0,0 +1,18 @@ +function box() { + var i = 1; + var sum = 0; + while (true) { + if (i >= 10) { + break; + } + if (sum > 30) { + break; + } + sum += i; + i++ + } + + if (sum != 36) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileEvaluationOrder.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileEvaluationOrder.optimized.js new file mode 100644 index 00000000000..2c0db4d4a65 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileEvaluationOrder.optimized.js @@ -0,0 +1,20 @@ +var global = ""; + +function foo(x) { + global += x + ";"; + return x; +} + +function box() { + var i = 1; + var sum = 0; + do { + sum += i; + i++; + } while (foo(i) < 10 && foo(sum) <= 30); + + if (global != "2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global; + if (sum != 36) return "fail2: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileEvaluationOrder.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileEvaluationOrder.original.js new file mode 100644 index 00000000000..44200e27dbe --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileEvaluationOrder.original.js @@ -0,0 +1,26 @@ +var global = ""; + +function foo(x) { + global += x + ";"; + return x; +} + +function box() { + var i = 1; + var sum = 0; + do { + sum += i; + i++; + if (foo(i) >= 10) { + break; + } + if (foo(sum) > 30) { + break; + } + } while (true); + + if (global != "2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global; + if (sum != 36) return "fail2: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithContinue.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithContinue.optimized.js new file mode 100644 index 00000000000..231aebdca67 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithContinue.optimized.js @@ -0,0 +1,24 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + do { + ++i; + if (i == 5) { + continue + } + global += ";"; + if (foo(i) >= 10) { + break; + } + } while (true); + + if (global != ";1;2;3;4;6;7;8;9;10") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithContinue.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithContinue.original.js new file mode 100644 index 00000000000..231aebdca67 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithContinue.original.js @@ -0,0 +1,24 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + do { + ++i; + if (i == 5) { + continue + } + global += ";"; + if (foo(i) >= 10) { + break; + } + } while (true); + + if (global != ";1;2;3;4;6;7;8;9;10") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithNestedContinue.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithNestedContinue.optimized.js new file mode 100644 index 00000000000..074d625e721 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithNestedContinue.optimized.js @@ -0,0 +1,45 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + var j; + do { + ++i; + global += ";"; + for (j = 0; j < 2; ++j) { + if (j == 1) { + continue; + } + global += "-"; + } + for (k in { a: 2, b: 3 }) { + if (k != "a") { + continue; + } + global += "@"; + } + j = 0; + while (j++ < 2) { + if (j == 1) { + continue; + } + global += "$"; + } + j = 0; + do { + if (j == 1) { + continue; + } + global += "#"; + } while (j++ < 2); + } while (foo(i) < 3); + + if (global != ";-@$##1;-@$##2;-@$##3") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithNestedContinue.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithNestedContinue.original.js new file mode 100644 index 00000000000..9a337c4381d --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/doWhileWithNestedContinue.original.js @@ -0,0 +1,48 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + var j; + do { + ++i; + global += ";"; + for (j = 0; j < 2; ++j) { + if (j == 1) { + continue; + } + global += "-"; + } + for (k in { a: 2, b: 3 }) { + if (k != "a") { + continue; + } + global += "@"; + } + j = 0; + while (j++ < 2) { + if (j == 1) { + continue; + } + global += "$"; + } + j = 0; + do { + if (j == 1) { + continue; + } + global += "#"; + } while (j++ < 2); + if (foo(i) >= 3) { + break; + } + } while (true); + + if (global != ";-@$##1;-@$##2;-@$##3") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/inLabeledBlock.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/inLabeledBlock.optimized.js new file mode 100644 index 00000000000..73d5a607657 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/inLabeledBlock.optimized.js @@ -0,0 +1,15 @@ +function box() { + var i = 1; + var sum = 0; + outer: { + while (i < 10) { + sum += i; + i++; + if (sum > 20) break outer; + } + } + + if (sum != 21) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/inLabeledBlock.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/inLabeledBlock.original.js new file mode 100644 index 00000000000..58a8a81d639 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/inLabeledBlock.original.js @@ -0,0 +1,18 @@ +function box() { + var i = 1; + var sum = 0; + outer: { + while (true) { + if (i >= 10) { + break; + } + sum += i; + i++; + if (sum > 20) break outer; + } + } + + if (sum != 21) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/inNestedLoop.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/inNestedLoop.optimized.js new file mode 100644 index 00000000000..f6662a41f2b --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/inNestedLoop.optimized.js @@ -0,0 +1,16 @@ +function box() { + var i; + var sum = 0; + var count = 2; + while (count-- > 0) { + i = 1; + while (i < 10) { + sum += i; + i++ + } + } + + if (sum != 90) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/inNestedLoop.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/inNestedLoop.original.js new file mode 100644 index 00000000000..48809fdaab9 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/inNestedLoop.original.js @@ -0,0 +1,19 @@ +function box() { + var i; + var sum = 0; + var count = 2; + while (count-- > 0) { + i = 1; + while (true) { + if (i >= 10) { + break; + } + sum += i; + i++ + } + } + + if (sum != 90) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/labeledContinueInNestedLoop.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/labeledContinueInNestedLoop.optimized.js new file mode 100644 index 00000000000..c4ffac63f94 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/labeledContinueInNestedLoop.optimized.js @@ -0,0 +1,28 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + var j; + loop: do { + ++i; + global += ";"; + for (j = 0; j < 2; ++j) { + if (j == 1 && i == 2) { + continue loop; + } + global += "-"; + } + if (foo(i) >= 5) { + break; + } + } while (true); + + if (global != ";--1;-;--3;--4;--5") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/labeledContinueInNestedLoop.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/labeledContinueInNestedLoop.original.js new file mode 100644 index 00000000000..c4ffac63f94 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/labeledContinueInNestedLoop.original.js @@ -0,0 +1,28 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + var j; + loop: do { + ++i; + global += ";"; + for (j = 0; j < 2; ++j) { + if (j == 1 && i == 2) { + continue loop; + } + global += "-"; + } + if (foo(i) >= 5) { + break; + } + } while (true); + + if (global != ";--1;-;--3;--4;--5") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/nestedConditions.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/nestedConditions.optimized.js new file mode 100644 index 00000000000..fb4e3883739 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/nestedConditions.optimized.js @@ -0,0 +1,12 @@ +function box() { + var i = 1; + var sum = 0; + while (i < 5 || sum <= 40) { + sum += i; + i++ + } + + if (sum != 45) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/nestedConditions.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/nestedConditions.original.js new file mode 100644 index 00000000000..afdf1e3a28c --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/nestedConditions.original.js @@ -0,0 +1,15 @@ +function box() { + var i = 1; + var sum = 0; + while (true) { + if (i >= 5) { + if (sum > 40) break; + } + sum += i; + i++ + } + + if (sum != 45) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/simpleDoWhile.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleDoWhile.optimized.js new file mode 100644 index 00000000000..43325aad8a0 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleDoWhile.optimized.js @@ -0,0 +1,18 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + do { + ++i; + global += ";"; + } while (foo(i) < 10); + + if (global != ";1;2;3;4;5;6;7;8;9;10") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/simpleDoWhile.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleDoWhile.original.js new file mode 100644 index 00000000000..28b5137c08b --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleDoWhile.original.js @@ -0,0 +1,21 @@ +var global = ""; + +function foo(x) { + global += x; + return x; +} + +function box() { + var i = 0; + do { + ++i; + global += ";"; + if (foo(i) >= 10) { + break; + } + } while (true); + + if (global != ";1;2;3;4;5;6;7;8;9;10") return "fail: " + global; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/simpleWhile.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleWhile.optimized.js new file mode 100644 index 00000000000..af37c5a27d1 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleWhile.optimized.js @@ -0,0 +1,12 @@ +function box() { + var i = 1; + var sum = 0; + while (i < 10) { + sum += i; + i++ + } + + if (sum != 45) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/simpleWhile.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleWhile.original.js new file mode 100644 index 00000000000..f170179aa62 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/simpleWhile.original.js @@ -0,0 +1,15 @@ +function box() { + var i = 1; + var sum = 0; + while (true) { + if (i >= 10) { + break; + } + sum += i; + i++ + } + + if (sum != 45) return "fail: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/whileEvaluationOrder.optimized.js b/js/js.translator/testData/js-optimizer/while-condition-folding/whileEvaluationOrder.optimized.js new file mode 100644 index 00000000000..b504efa8323 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/whileEvaluationOrder.optimized.js @@ -0,0 +1,20 @@ +var global = ""; + +function foo(x) { + global += x + ";"; + return x; +} + +function box() { + var i = 1; + var sum = 0; + while (foo(i) < 10 && foo(sum) <= 30) { + sum += i; + i++; + } + + if (global != "1;0;2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global; + if (sum != 36) return "fail2: " + sum; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/js-optimizer/while-condition-folding/whileEvaluationOrder.original.js b/js/js.translator/testData/js-optimizer/while-condition-folding/whileEvaluationOrder.original.js new file mode 100644 index 00000000000..fb82ad46e40 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/while-condition-folding/whileEvaluationOrder.original.js @@ -0,0 +1,26 @@ +var global = ""; + +function foo(x) { + global += x + ";"; + return x; +} + +function box() { + var i = 1; + var sum = 0; + while (true) { + if (foo(i) >= 10) { + break; + } + if (foo(sum) > 30) { + break; + } + sum += i; + i++; + } + + if (global != "1;0;2;1;3;3;4;6;5;10;6;15;7;21;8;28;9;36;") return "fail1: " + global; + if (sum != 36) return "fail2: " + sum; + + return "OK" +} \ No newline at end of file