From ec6108ee058ba18264dc834351258154ca629bcb Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Fri, 8 Aug 2014 17:40:33 +0400 Subject: [PATCH] JS inline: remove unused local function instances --- .../org/jetbrains/k2js/inline/JsInliner.java | 2 + .../inline/clean/LocalFunctionInstances.kt | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 js/js.inliner/src/org/jetbrains/k2js/inline/clean/LocalFunctionInstances.kt diff --git a/js/js.inliner/src/org/jetbrains/k2js/inline/JsInliner.java b/js/js.inliner/src/org/jetbrains/k2js/inline/JsInliner.java index fe2b9eb26cf..18336d71cfc 100644 --- a/js/js.inliner/src/org/jetbrains/k2js/inline/JsInliner.java +++ b/js/js.inliner/src/org/jetbrains/k2js/inline/JsInliner.java @@ -24,6 +24,7 @@ import java.util.IdentityHashMap; import java.util.Stack; import java.util.List; +import static org.jetbrains.k2js.inline.clean.CleanPackage.removeUnusedLocalFunctionInstances; import static org.jetbrains.k2js.inline.FunctionInlineMutator.getInlineableCallReplacement; public class JsInliner extends JsVisitorWithContextImpl { @@ -161,6 +162,7 @@ public class JsInliner extends JsVisitorWithContextImpl { @Override public void endVisit(JsFunction function, JsContext context) { super.endVisit(function, context); + removeUnusedLocalFunctionInstances(function); inliningContexts.pop(); } diff --git a/js/js.inliner/src/org/jetbrains/k2js/inline/clean/LocalFunctionInstances.kt b/js/js.inliner/src/org/jetbrains/k2js/inline/clean/LocalFunctionInstances.kt new file mode 100644 index 00000000000..73c4d436022 --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/k2js/inline/clean/LocalFunctionInstances.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2014 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.k2js.inline.clean + +import com.google.dart.compiler.backend.js.ast.* + +import java.util.ArrayList +import java.util.IdentityHashMap + +public fun removeUnusedLocalFunctionInstances(root: JsNode) { + val removable = + with(UnusedInstanceCollector()) { + accept(root) + removableInstances + } + + GenericRemover(removable).accept(root) +} + +private class UnusedInstanceCollector : JsVisitorWithContextImpl() { + private val tracker = ReferenceTracker() + + public val removableInstances: List + get() = tracker.removable + + override fun visit(x: JsVars.JsVar?, ctx: JsContext?): Boolean { + if (x == null) return false + + if (!isLocalFunctionInstance(x)) return super.visit(x, ctx) + + val name = x.getName()!! + val statementContext = getLastStatementLevelContext() + val currentNode = statementContext.getCurrentNode() + assert(currentNode is JsStatement) { "expected context containing statement" } + val currentStatement = currentNode as JsStatement + tracker.addCandidateForRemoval(name, currentStatement) + + val references = collectReferencesInside(x) + references.filterNotNull() + .forEach { tracker.addRemovableReference(name, it) } + + return false + } + + override fun visit(x: JsNameRef?, ctx: JsContext?): Boolean { + val name = x?.getName() + + if (name != null) { + tracker.markReachable(name) + } + + return false + } + + private fun isLocalFunctionInstance(jsVar: JsVars.JsVar): Boolean { + val name = jsVar.getName() + val expr = jsVar.getInitExpression() + val staticRef = name?.getStaticRef() + + return staticRef != null && staticRef == expr + } +} \ No newline at end of file