[Wasm] A name cache to distinguish same named declarations in DCE dump
This commit is contained in:
committed by
Space Team
parent
bc0afc36a2
commit
34c6afec5e
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalNextRoundChecker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.DceDumpNameCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.dumpDeclarationIrSizesIfNeed
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||
@@ -347,11 +348,12 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
exportedDeclarations = setOf(FqName("main")),
|
||||
propertyLazyInitialization = arguments.irPropertyLazyInitialization,
|
||||
)
|
||||
val dceDumpNameCache = DceDumpNameCache()
|
||||
if (arguments.irDce) {
|
||||
eliminateDeadDeclarations(allModules, backendContext)
|
||||
eliminateDeadDeclarations(allModules, backendContext, dceDumpNameCache)
|
||||
}
|
||||
|
||||
dumpDeclarationIrSizesIfNeed(arguments.irDceDumpDeclarationIrSizesToFile, allModules)
|
||||
dumpDeclarationIrSizesIfNeed(arguments.irDceDumpDeclarationIrSizesToFile, allModules, dceDumpNameCache)
|
||||
|
||||
val generateSourceMaps = configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ fun eliminateDeadDeclarations(
|
||||
modules: Iterable<IrModuleFragment>,
|
||||
context: JsIrBackendContext,
|
||||
removeUnusedAssociatedObjects: Boolean = true,
|
||||
dceDumpNameCache: DceDumpNameCache,
|
||||
) {
|
||||
val allRoots = buildRoots(modules, context)
|
||||
|
||||
@@ -31,7 +32,7 @@ fun eliminateDeadDeclarations(
|
||||
java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info")
|
||||
|
||||
val usefulDeclarationProcessor = JsUsefulDeclarationProcessor(context, printReachabilityInfo, removeUnusedAssociatedObjects)
|
||||
val usefulDeclarations = usefulDeclarationProcessor.collectDeclarations(allRoots)
|
||||
val usefulDeclarations = usefulDeclarationProcessor.collectDeclarations(allRoots, dceDumpNameCache)
|
||||
|
||||
val uselessDeclarationsProcessor =
|
||||
UselessDeclarationsRemover(removeUnusedAssociatedObjects, usefulDeclarations, context, context.dceRuntimeDiagnostic)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.dce
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
|
||||
class DceDumpNameCache {
|
||||
/**
|
||||
* This cache provides better dumping names for reachability and ir sizes infos.
|
||||
* The problem is that dumps contain several same named objects that should be consistently renamed.
|
||||
* The name for the first declaration with some name isn't changed. For other names suffix (i) is added, where i >= 1
|
||||
*/
|
||||
private val nameCache: MutableMap<IrDeclaration, String> = hashMapOf()
|
||||
private val indexCache: MutableMap<String, Int> = hashMapOf()
|
||||
|
||||
public fun getOrPut(declaration: IrDeclaration): String = nameCache.getOrPut(declaration) {
|
||||
val fqName = declaration.fqNameForDceDump()
|
||||
val index = indexCache.getOrDefault(fqName, 0)
|
||||
indexCache[fqName] = index + 1
|
||||
if (index == 0) fqName
|
||||
else "$fqName ($index)"
|
||||
}
|
||||
}
|
||||
+17
-11
@@ -235,7 +235,7 @@ abstract class UsefulDeclarationProcessor(
|
||||
|
||||
protected open fun handleAssociatedObjects(): Unit = Unit
|
||||
|
||||
fun collectDeclarations(rootDeclarations: Iterable<IrDeclaration>): Set<IrDeclaration> {
|
||||
fun collectDeclarations(rootDeclarations: Iterable<IrDeclaration>, dceDumpNameCache: DceDumpNameCache): Set<IrDeclaration> {
|
||||
|
||||
rootDeclarations.forEach {
|
||||
it.enqueue(it, "<ROOT>")
|
||||
@@ -274,7 +274,7 @@ abstract class UsefulDeclarationProcessor(
|
||||
|
||||
if (reachabilityInfos != null) {
|
||||
if (printReachabilityInfo) {
|
||||
println(transformToDotLikeString(reachabilityInfos))
|
||||
println(transformToDotLikeString(reachabilityInfos, dceDumpNameCache))
|
||||
}
|
||||
|
||||
if (dumpReachabilityInfoToFile != null) {
|
||||
@@ -285,7 +285,7 @@ abstract class UsefulDeclarationProcessor(
|
||||
else -> ::transformToDotLikeString
|
||||
}
|
||||
|
||||
out.writeText(stringify(reachabilityInfos))
|
||||
out.writeText(stringify(reachabilityInfos, dceDumpNameCache))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,18 +305,24 @@ private data class ReachabilityInfo(
|
||||
private fun transformToStringBy(
|
||||
reachabilityInfos: List<ReachabilityInfo>,
|
||||
separator: String,
|
||||
transformer: (sourceFqn: String, targetFqn: String, description: String, isTargetContagious: Boolean) -> String
|
||||
dceDumpNameCache: DceDumpNameCache,
|
||||
transformer: (sourceFqn: String, targetFqn: String, description: String, isTargetContagious: Boolean) -> String,
|
||||
): String {
|
||||
return reachabilityInfos
|
||||
.map {
|
||||
transformer(it.source.fqNameForDceDump(), it.target.fqNameForDceDump(), it.description, it.isTargetContagious)
|
||||
transformer(
|
||||
dceDumpNameCache.getOrPut(it.source),
|
||||
dceDumpNameCache.getOrPut(it.target),
|
||||
it.description,
|
||||
it.isTargetContagious
|
||||
)
|
||||
}
|
||||
.distinct()
|
||||
.joinToString(separator)
|
||||
}
|
||||
|
||||
private fun transformToDotLikeString(reachabilityInfos: List<ReachabilityInfo>): String {
|
||||
return transformToStringBy(reachabilityInfos, "\n") { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||
private fun transformToDotLikeString(reachabilityInfos: List<ReachabilityInfo>, dceDumpNameCache: DceDumpNameCache): String {
|
||||
return transformToStringBy(reachabilityInfos, "\n", dceDumpNameCache) { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||
val comment = description + (if (isTargetContagious) "[CONTAGIOUS!]" else "")
|
||||
val info = "\"$sourceFqn\" -> \"$targetFqn\"" + (if (comment.isBlank()) "" else " // $comment")
|
||||
|
||||
@@ -324,8 +330,8 @@ private fun transformToDotLikeString(reachabilityInfos: List<ReachabilityInfo>):
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformToJsonString(reachabilityInfos: List<ReachabilityInfo>): String {
|
||||
return "[\n" + transformToStringBy(reachabilityInfos, ",\n") { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||
private fun transformToJsonString(reachabilityInfos: List<ReachabilityInfo>, dceDumpNameCache: DceDumpNameCache): String {
|
||||
return "[\n" + transformToStringBy(reachabilityInfos, ",\n", dceDumpNameCache) { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||
"""
|
||||
| {
|
||||
| "source" : "${sourceFqn.removeQuotes()}",
|
||||
@@ -336,6 +342,6 @@ private fun transformToJsonString(reachabilityInfos: List<ReachabilityInfo>): St
|
||||
} + "\n]"
|
||||
}
|
||||
|
||||
private fun transformToJsConstDeclaration(reachabilityInfos: List<ReachabilityInfo>): String {
|
||||
return "export const kotlinReachabilityInfos = " + transformToJsonString(reachabilityInfos) + ";"
|
||||
private fun transformToJsConstDeclaration(reachabilityInfos: List<ReachabilityInfo>, dceDumpNameCache: DceDumpNameCache): String {
|
||||
return "export const kotlinReachabilityInfos = " + transformToJsonString(reachabilityInfos, dceDumpNameCache) + ";"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.dce
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.PrimaryConstructorLowering
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
|
||||
@@ -31,7 +32,7 @@ internal fun IrDeclaration.fqNameForDceDump(): String {
|
||||
|
||||
private data class IrDeclarationDumpInfo(val fqName: String, val type: String, val size: Int)
|
||||
|
||||
fun dumpDeclarationIrSizesIfNeed(path: String?, allModules: List<IrModuleFragment>) {
|
||||
fun dumpDeclarationIrSizesIfNeed(path: String?, allModules: List<IrModuleFragment>, dceDumpNameCache: DceDumpNameCache) {
|
||||
if (path == null) return
|
||||
|
||||
val declarations = linkedSetOf<IrDeclarationDumpInfo>()
|
||||
@@ -53,7 +54,7 @@ fun dumpDeclarationIrSizesIfNeed(path: String?, allModules: List<IrModuleFragmen
|
||||
type?.let {
|
||||
declarations.add(
|
||||
IrDeclarationDumpInfo(
|
||||
fqName = declaration.fqNameForDceDump().removeQuotes(),
|
||||
fqName = dceDumpNameCache.getOrPut(declaration).removeQuotes(),
|
||||
type = it,
|
||||
size = declaration.dumpKotlinLike().length
|
||||
)
|
||||
@@ -72,21 +73,13 @@ fun dumpDeclarationIrSizesIfNeed(path: String?, allModules: List<IrModuleFragmen
|
||||
else -> listOf("", "", "\n", "")
|
||||
}
|
||||
|
||||
val value = declarations
|
||||
// TODO: introduce a way to assign unique names to each declaration and use it for both reachability and size infos
|
||||
.groupBy { it.fqName }
|
||||
.flatMap { (_, v) ->
|
||||
v.mapIndexed { index: Int, declaration: IrDeclarationDumpInfo ->
|
||||
if (index == 0) declaration
|
||||
else declaration.copy(fqName = "${declaration.fqName} ($index)")
|
||||
}
|
||||
}.joinToString(separator, prefix, postfix) { declaration ->
|
||||
"""$indent"${declaration.fqName}": {
|
||||
val value = declarations.joinToString(separator, prefix, postfix) { declaration ->
|
||||
"""$indent"${declaration.fqName}": {
|
||||
|$indent$indent"size": ${declaration.size},
|
||||
|$indent$indent"type": "${declaration.type}"
|
||||
|$indent}
|
||||
""".trimMargin()
|
||||
}
|
||||
}
|
||||
|
||||
out.writeText(value)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.DceDumpNameCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
@@ -21,7 +22,8 @@ fun optimizeProgramByIr(
|
||||
context: JsIrBackendContext,
|
||||
removeUnusedAssociatedObjects: Boolean
|
||||
) {
|
||||
eliminateDeadDeclarations(modules, context, removeUnusedAssociatedObjects)
|
||||
val dceDumpNameCache = DceDumpNameCache() // in JS mode only DCE Graph could be dumped
|
||||
eliminateDeadDeclarations(modules, context, removeUnusedAssociatedObjects, dceDumpNameCache)
|
||||
jsOptimizationPhases.invokeToplevel(PhaseConfig(jsOptimizationPhases), context, modules)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.dce
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.DceDumpNameCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
@@ -16,7 +17,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
|
||||
fun eliminateDeadDeclarations(modules: List<IrModuleFragment>, context: WasmBackendContext) {
|
||||
fun eliminateDeadDeclarations(modules: List<IrModuleFragment>, context: WasmBackendContext, dceDumpNameCache: DceDumpNameCache) {
|
||||
val printReachabilityInfo =
|
||||
context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) ||
|
||||
java.lang.Boolean.getBoolean("kotlin.wasm.dce.print.reachability.info")
|
||||
@@ -29,7 +30,7 @@ fun eliminateDeadDeclarations(modules: List<IrModuleFragment>, context: WasmBack
|
||||
context = context,
|
||||
printReachabilityInfo = printReachabilityInfo,
|
||||
dumpReachabilityInfoToFile
|
||||
).collectDeclarations(rootDeclarations = buildRoots(modules, context))
|
||||
).collectDeclarations(rootDeclarations = buildRoots(modules, context), dceDumpNameCache)
|
||||
|
||||
val remover = WasmUselessDeclarationsRemover(context, usefulDeclarations)
|
||||
modules.onAllFiles {
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.wasm.dce.eliminateDeadDeclarations
|
||||
import org.jetbrains.kotlin.backend.wasm.wasmPhases
|
||||
import org.jetbrains.kotlin.ir.backend.js.MainModule
|
||||
import org.jetbrains.kotlin.ir.backend.js.ModulesStructure
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.DceDumpNameCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.dumpDeclarationIrSizesIfNeed
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||
import org.jetbrains.kotlin.ir.linkage.partial.PartialLinkageConfig
|
||||
@@ -97,9 +98,10 @@ class WasmBackendFacade(
|
||||
generateWat = generateWat,
|
||||
)
|
||||
|
||||
eliminateDeadDeclarations(allModules, backendContext)
|
||||
val dceDumpNameCache = DceDumpNameCache()
|
||||
eliminateDeadDeclarations(allModules, backendContext, dceDumpNameCache)
|
||||
|
||||
dumpDeclarationIrSizesIfNeed(System.getProperty("kotlin.wasm.dump.declaration.ir.size.to.file"), allModules)
|
||||
dumpDeclarationIrSizesIfNeed(System.getProperty("kotlin.wasm.dump.declaration.ir.size.to.file"), allModules, dceDumpNameCache)
|
||||
|
||||
val compilerResultWithDCE = compileWasm(
|
||||
allModules = allModules,
|
||||
|
||||
Reference in New Issue
Block a user