JS DCE: use Multimaps to reduce Node fields RAM

This commit is contained in:
Anton Bannykh
2021-01-28 17:39:54 +03:00
parent f42f2fa743
commit 165533fdb7
2 changed files with 27 additions and 39 deletions
+1
View File
@@ -9,6 +9,7 @@ dependencies {
compile(project(":js:js.ast")) compile(project(":js:js.ast"))
compile(project(":js:js.translator")) compile(project(":js:js.translator"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") } compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeJars("guava", rootProject = rootProject) }
} }
sourceSets { sourceSets {
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.js.dce package org.jetbrains.kotlin.js.dce
import com.google.common.collect.LinkedHashMultimap
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
@@ -24,6 +25,12 @@ import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.array
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.index import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.index
class Context { class Context {
// Collections per Node consumes too much RAM
private val nodeDependencies = LinkedHashMultimap.create<Node, Node>()
private val nodeExpressions = LinkedHashMultimap.create<Node, JsExpression>()
private val nodeFunctions = LinkedHashMultimap.create<Node, JsFunction>()
private val nodeUsedByAstNodes = LinkedHashMultimap.create<Node, JsNode>()
val globalScope = Node() val globalScope = Node()
val moduleExportsNode = globalScope.member("module").member("exports") val moduleExportsNode = globalScope.member("module").member("exports")
var currentModule = globalScope var currentModule = globalScope
@@ -134,36 +141,24 @@ class Context {
fun visit(n: Node) = n.visit(currentColor) fun visit(n: Node) = n.visit(currentColor)
class Node private constructor(val localName: JsName?, parent: Node?, val memberName: String?) { inner class Node private constructor(val localName: JsName?, parent: Node?, val memberName: String?) {
private var _dependenciesImpl: MutableSet<Node>? = null
private var _expressionsImpl: MutableSet<JsExpression>? = null
private var _functionsImpl: MutableSet<JsFunction>? = null
private var _membersImpl: MutableMap<String, Node>? = null private var _membersImpl: MutableMap<String, Node>? = null
private var _usedByAstNodesImpl: MutableSet<JsNode>? = null
private val dependenciesImpl: MutableSet<Node>
get() = _dependenciesImpl ?: mutableSetOf<Node>().also { _dependenciesImpl = it }
private val expressionsImpl: MutableSet<JsExpression>
get() = _expressionsImpl ?: mutableSetOf<JsExpression>().also { _expressionsImpl = it }
private val functionsImpl: MutableSet<JsFunction>
get() = _functionsImpl ?: mutableSetOf<JsFunction>().also { _functionsImpl = it }
private val membersImpl: MutableMap<String, Node> private val membersImpl: MutableMap<String, Node>
get() = _membersImpl ?: mutableMapOf<String, Node>().also { _membersImpl = it } get() = _membersImpl ?: mutableMapOf<String, Node>().also { _membersImpl = it }
private val usedByAstNodesImpl: MutableSet<JsNode>
get() = _usedByAstNodesImpl ?: mutableSetOf<JsNode>().also { _usedByAstNodesImpl = it }
private var rank = 0 private var rank = 0
private var hasSideEffectsImpl = false private var hasSideEffectsImpl = false
private var reachableImpl = false private var reachableImpl = false
private var declarationReachableImpl = false private var declarationReachableImpl = false
val dependencies: Set<Node> get() = original._dependenciesImpl ?: emptySet() val dependencies: Set<Node> get() = nodeDependencies[original]
val expressions: Set<JsExpression> get() = original._expressionsImpl ?: emptySet() val expressions: Set<JsExpression> get() = nodeExpressions[original]
val functions: Set<JsFunction> get() = original._functionsImpl ?: emptySet() val functions: Set<JsFunction> get() = nodeFunctions[original]
val usedByAstNodes: Set<JsNode> get() = original._usedByAstNodesImpl ?: emptySet() val usedByAstNodes: Set<JsNode> get() = nodeUsedByAstNodes[original]
var hasSideEffects: Boolean var hasSideEffects: Boolean
get() = original.hasSideEffectsImpl get() = original.hasSideEffectsImpl
@@ -210,19 +205,19 @@ class Context {
val members: Map<String, Node> get() = original._membersImpl ?: emptyMap() val members: Map<String, Node> get() = original._membersImpl ?: emptyMap()
fun addDependency(node: Node) { fun addDependency(node: Node) {
original.dependenciesImpl += node nodeDependencies.put(original, node)
} }
fun addFunction(function: JsFunction) { fun addFunction(function: JsFunction) {
original.functionsImpl += function nodeFunctions.put(original, function)
} }
fun addExpression(expression: JsExpression) { fun addExpression(expression: JsExpression) {
original.expressionsImpl += expression nodeExpressions.put(original, expression)
} }
fun addUsedByAstNode(node: JsNode) { fun addUsedByAstNode(node: JsNode) {
original.usedByAstNodesImpl += node nodeUsedByAstNodes.put(original, node)
} }
fun member(name: String): Node = original.membersImpl.getOrPut(name) { Node(null, this, name) }.original fun member(name: String): Node = original.membersImpl.getOrPut(name) { Node(null, this, name) }.original
@@ -247,8 +242,8 @@ class Context {
} }
private fun makeDependencies(other: Node) { private fun makeDependencies(other: Node) {
dependenciesImpl += other nodeDependencies.put(this, other)
other.dependenciesImpl += this nodeDependencies.put(other, this)
} }
private fun evacuateFrom(other: Node) { private fun evacuateFrom(other: Node) {
@@ -267,23 +262,15 @@ class Context {
other.membersImpl.clear() other.membersImpl.clear()
hasSideEffectsImpl = hasSideEffectsImpl || other.hasSideEffectsImpl hasSideEffectsImpl = hasSideEffectsImpl || other.hasSideEffectsImpl
if (!other._expressionsImpl.isNullOrEmpty()) { nodeExpressions.putAll(this, nodeExpressions[other])
expressionsImpl += other.expressionsImpl nodeFunctions.putAll(this, nodeFunctions[other])
} nodeDependencies.putAll(this, nodeDependencies[other])
if (!other._functionsImpl.isNullOrEmpty()) { nodeUsedByAstNodes.putAll(this, nodeUsedByAstNodes[other])
functionsImpl += other.functionsImpl
}
if (!other._dependenciesImpl.isNullOrEmpty()) {
dependenciesImpl += other.dependenciesImpl
}
if (!other._usedByAstNodesImpl.isNullOrEmpty()) {
usedByAstNodesImpl += other.usedByAstNodesImpl
}
other._expressionsImpl = null nodeExpressions.removeAll(other)
other._functionsImpl = null nodeFunctions.removeAll(other)
other._dependenciesImpl = null nodeDependencies.removeAll(other)
other._usedByAstNodesImpl = null nodeUsedByAstNodes.removeAll(other)
} }
private fun merge(other: Node) { private fun merge(other: Node) {