diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt index 156191ced7e..45bc29c8892 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineBodyTransformer.kt @@ -123,14 +123,18 @@ class CoroutineBodyTransformer(val program: JsProgram, val scope: JsScope, val t if (target != null) { val lhs = JsNameRef(stateFieldName, JsLiteral.THIS) val rhs = program.getNumberLiteral(blockIndexes[target]!!) - ctx.replaceMe(JsAstUtils.assignment(lhs, rhs).makeStmt()) + ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs)).apply { + targetBlock = true + }) } val exceptionTarget = x.targetExceptionBlock if (exceptionTarget != null) { val lhs = JsNameRef(exceptionStateName, JsLiteral.THIS) val rhs = program.getNumberLiteral(blockIndexes[exceptionTarget]!!) - ctx.replaceMe(JsAstUtils.assignment(lhs, rhs).makeStmt()) + ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs)).apply { + targetExceptionBlock = true + }) } val finallyPath = x.finallyPath @@ -138,7 +142,9 @@ class CoroutineBodyTransformer(val program: JsProgram, val scope: JsScope, val t if (finallyPath.isNotEmpty()) { val lhs = JsNameRef(finallyPathFieldName, JsLiteral.THIS) val rhs = JsArrayLiteral(finallyPath.map { program.getNumberLiteral(blockIndexes[it]!!) }) - ctx.replaceMe(JsAstUtils.assignment(lhs, rhs).makeStmt()) + ctx.replaceMe(JsExpressionStatement(JsAstUtils.assignment(lhs, rhs)).apply { + this.finallyPath = true + }) } else { ctx.removeMe() @@ -623,7 +629,3 @@ private fun CoroutineBlock.collectFinallyPaths(): List> { }) return finallyPaths } - -private var JsDebugger.targetBlock: CoroutineBlock? by MetadataProperty(default = null) -private var JsDebugger.targetExceptionBlock: CoroutineBlock? by MetadataProperty(default = null) -private var JsDebugger.finallyPath: List? by MetadataProperty(default = null) \ No newline at end of file diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineMetadataProperties.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineMetadataProperties.kt new file mode 100644 index 00000000000..e429cf5206f --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/coroutine/CoroutineMetadataProperties.kt @@ -0,0 +1,29 @@ +/* + * 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.coroutine + +import com.google.dart.compiler.backend.js.ast.JsDebugger +import com.google.dart.compiler.backend.js.ast.JsExpressionStatement +import com.google.dart.compiler.backend.js.ast.metadata.MetadataProperty + +var JsDebugger.targetBlock: CoroutineBlock? by MetadataProperty(default = null) +var JsDebugger.targetExceptionBlock: CoroutineBlock? by MetadataProperty(default = null) +var JsDebugger.finallyPath: List? by MetadataProperty(default = null) + +var JsExpressionStatement.targetBlock by MetadataProperty(default = false) +var JsExpressionStatement.targetExceptionBlock by MetadataProperty(default = false) +var JsExpressionStatement.finallyPath by MetadataProperty(default = false) \ No newline at end of file diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/CoroutineStateElimination.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/CoroutineStateElimination.kt new file mode 100644 index 00000000000..04c7cfa5e2e --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/CoroutineStateElimination.kt @@ -0,0 +1,87 @@ +/* + * 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.coroutine.finallyPath +import org.jetbrains.kotlin.js.coroutine.targetBlock +import org.jetbrains.kotlin.js.coroutine.targetExceptionBlock + +class CoroutineStateElimination(private val body: JsBlock) { + fun apply(): Boolean { + var changed = false + + body.accept(object : RecursiveJsVisitor() { + override fun visitBlock(x: JsBlock) { + visitStatements(x.statements) + super.visitBlock(x) + } + + override fun visitCase(x: JsCase) { + visitStatements(x.statements) + super.visitCase(x) + } + + private fun visitStatements(statements: MutableList) { + class IndexHolder { + var value: Int? = null + } + + val indexesToRemove = mutableSetOf() + val lastTargetBlockIndex = IndexHolder() + val lastTargetExceptionBlockIndex = IndexHolder() + val lastFinallyPathIndex = IndexHolder() + + for ((index, statement) in statements.withIndex()) { + val indexesToUpdate = mutableListOf() + if (statement is JsExpressionStatement) { + if (statement.targetBlock) { + indexesToUpdate += lastTargetBlockIndex + } + if (statement.targetExceptionBlock) { + indexesToUpdate += lastTargetExceptionBlockIndex + } + if (statement.finallyPath) { + indexesToUpdate += lastFinallyPathIndex + } + } + + if (indexesToUpdate.isNotEmpty()) { + for (indexToUpdate in indexesToUpdate) { + indexToUpdate.value?.let { indexesToRemove += it } + indexToUpdate.value = index + } + } + else { + lastTargetBlockIndex.value = null + lastTargetExceptionBlockIndex.value = null + lastFinallyPathIndex.value = null + } + } + + for (index in indexesToRemove.sorted().reversed()) { + statements.removeAt(index) + } + if (indexesToRemove.isNotEmpty()) { + changed = true + } + } + }) + + return changed + } +} \ No newline at end of file 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 1714f307d36..b0654694291 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 @@ -29,7 +29,8 @@ class FunctionPostProcessor(root: JsFunction) { { IfStatementReduction(root.body).apply() }, { DeadCodeElimination(root.body).apply() }, { RedundantVariableDeclarationElimination(root.body).apply() }, - { RedundantStatementElimination(root).apply() } + { RedundantStatementElimination(root).apply() }, + { CoroutineStateElimination(root.body).apply() } ) // TODO: reduce to A || B, A && B if possible