JS DCE: inline Qualifier class to reduce RAM usage
This commit is contained in:
@@ -278,7 +278,7 @@ class Analyzer(private val context: Context) : JsVisitor() {
|
||||
leftNode.addFunction(rhs)
|
||||
return leftNode
|
||||
}
|
||||
leftNode.qualifier?.memberName == Namer.METADATA -> {
|
||||
leftNode.memberName == Namer.METADATA -> {
|
||||
// lhs.$metadata$ = expression
|
||||
// During reachability tracking phase: eliminate it if lhs is unreachable, traverse expression
|
||||
// It's commonly used to supply class's metadata
|
||||
|
||||
@@ -76,7 +76,7 @@ class Context {
|
||||
|
||||
fun extractNode(expression: JsExpression): Node? {
|
||||
val node = extractNodeImpl(expression)?.original
|
||||
return if (node != null && moduleExportsNode in generateSequence(node) { it.qualifier?.parent }) {
|
||||
return if (node != null && moduleExportsNode in generateSequence(node) { it.parent }) {
|
||||
val path = node.pathFromRoot().drop(2)
|
||||
path.fold(currentModule.original) { n, memberName -> n.member(memberName) }
|
||||
}
|
||||
@@ -134,7 +134,7 @@ class Context {
|
||||
|
||||
fun visit(n: Node) = n.visit(currentColor)
|
||||
|
||||
class Node private constructor(val localName: JsName?, qualifier: Qualifier?) {
|
||||
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
|
||||
@@ -183,7 +183,7 @@ class Context {
|
||||
original.declarationReachableImpl = value
|
||||
}
|
||||
|
||||
var qualifier: Qualifier? = qualifier
|
||||
var parent: Node? = parent
|
||||
private set
|
||||
|
||||
private var color: Byte = 0
|
||||
@@ -196,7 +196,7 @@ class Context {
|
||||
|
||||
val memberNames: Set<String> get() = original._membersImpl?.keys ?: emptySet()
|
||||
|
||||
constructor(localName: JsName? = null) : this(localName, null)
|
||||
constructor(localName: JsName? = null) : this(localName, null, null)
|
||||
|
||||
var original: Node = this
|
||||
get() {
|
||||
@@ -225,20 +225,20 @@ class Context {
|
||||
original.usedByAstNodesImpl += node
|
||||
}
|
||||
|
||||
fun member(name: String): Node = original.membersImpl.getOrPut(name) { Node(null, Qualifier(this, name)) }.original
|
||||
fun member(name: String): Node = original.membersImpl.getOrPut(name) { Node(null, this, name) }.original
|
||||
|
||||
fun alias(other: Node) {
|
||||
val a = original
|
||||
val b = other.original
|
||||
if (a == b) return
|
||||
|
||||
if (a.qualifier == null && b.qualifier == null) {
|
||||
if (a.parent == null && b.parent == null) {
|
||||
a.merge(b)
|
||||
}
|
||||
else if (a.qualifier == null) {
|
||||
else if (a.parent == null) {
|
||||
if (b.root() == a) a.makeDependencies(b) else b.evacuateFrom(a)
|
||||
}
|
||||
else if (b.qualifier == null) {
|
||||
else if (b.parent == null) {
|
||||
if (a.root() == b) a.makeDependencies(b) else a.evacuateFrom(b)
|
||||
}
|
||||
else {
|
||||
@@ -257,12 +257,12 @@ class Context {
|
||||
|
||||
for ((name, member) in newMembers) {
|
||||
membersImpl[name] = member
|
||||
member.original.qualifier = Qualifier(this, member.original.qualifier!!.memberName)
|
||||
member.original.parent = this
|
||||
}
|
||||
for ((name, member) in existingMembers) {
|
||||
membersImpl[name]!!.original.merge(member.original)
|
||||
membersImpl[name] = member.original
|
||||
member.original.qualifier = Qualifier(this, member.original.qualifier!!.memberName)
|
||||
member.original.parent = this
|
||||
}
|
||||
other.membersImpl.clear()
|
||||
|
||||
@@ -301,14 +301,12 @@ class Context {
|
||||
}
|
||||
}
|
||||
|
||||
fun root(): Node = generateSequence(original) { it.qualifier?.parent?.original }.last()
|
||||
fun root(): Node = generateSequence(original) { it.parent?.original }.last()
|
||||
|
||||
fun pathFromRoot(): List<String> =
|
||||
generateSequence(original) { it.qualifier?.parent?.original }.mapNotNull { it.qualifier?.memberName }
|
||||
generateSequence(original) { it.parent?.original }.mapNotNull { it.memberName }
|
||||
.toList().asReversed()
|
||||
|
||||
override fun toString(): String = (root().localName?.ident ?: "<unknown>") + pathFromRoot().joinToString("") { ".$it" }
|
||||
}
|
||||
|
||||
class Qualifier(val parent: Node, val memberName: String)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ class ReachabilityTracker(
|
||||
invocation in analysisResult.invocationsToSkip -> {}
|
||||
else -> {
|
||||
val node = context.extractNode(invocation.qualifier)
|
||||
if (node != null && node.qualifier?.memberName in CALL_FUNCTIONS) {
|
||||
val parent = node.qualifier!!.parent
|
||||
if (node != null && node.memberName in CALL_FUNCTIONS) {
|
||||
val parent = node.parent!!
|
||||
reach(parent)
|
||||
currentNodeWithLocation?.let { parent.addUsedByAstNode(it) }
|
||||
}
|
||||
@@ -178,15 +178,14 @@ class ReachabilityTracker(
|
||||
var current = node
|
||||
while (true) {
|
||||
for (ancestorDependency in current.dependencies) {
|
||||
if (current in generateSequence(ancestorDependency) { it.qualifier?.parent }) continue
|
||||
if (current in generateSequence(ancestorDependency) { it.parent }) continue
|
||||
val dependency = path.asReversed().fold(ancestorDependency) { n, memberName -> n.member(memberName) }
|
||||
if (!dependency.reachable) {
|
||||
reportAndNest("reach: dependency $dependency", null) { reach(dependency) }
|
||||
}
|
||||
}
|
||||
val qualifier = current.qualifier ?: break
|
||||
path += qualifier.memberName
|
||||
current = qualifier.parent
|
||||
path += current.memberName ?: break
|
||||
current = current.parent!! // memberName != null => parent != null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +201,7 @@ class ReachabilityTracker(
|
||||
reachableNodesImpl += node
|
||||
}
|
||||
|
||||
node.original.qualifier?.parent?.let {
|
||||
node.original.parent?.let {
|
||||
reportAndNest("reach-decl: parent $it", null) {
|
||||
reachDeclaration(it)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ fun printTree(root: Node, consumer: (String) -> Unit, printNestedMembers: Boolea
|
||||
|
||||
private fun printTree(node: Node, consumer: (String) -> Unit, depth: Int, settings: Settings) {
|
||||
val sb = StringBuilder()
|
||||
sb.append(" ".repeat(depth)).append(node.qualifier?.memberName ?: node.toString())
|
||||
sb.append(" ".repeat(depth)).append(node.memberName ?: node.toString())
|
||||
|
||||
if (node.reachable) {
|
||||
sb.append(" (reachable")
|
||||
|
||||
@@ -83,11 +83,11 @@ fun Iterable<Node>.extractReachableRoots(context: Context): Iterable<Node> {
|
||||
|
||||
private fun Node.extractRootsImpl(target: MutableList<Node>, context: Context) {
|
||||
if (!context.visit(original)) return
|
||||
val qualifier = original.qualifier
|
||||
if (qualifier == null) {
|
||||
val parent = original.parent
|
||||
if (parent == null) {
|
||||
target += original
|
||||
}
|
||||
else {
|
||||
qualifier.parent.extractRootsImpl(target, context)
|
||||
parent.extractRootsImpl(target, context)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user