[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.IncrementalNextRoundChecker
|
||||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.*
|
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.dce.dumpDeclarationIrSizesIfNeed
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
import org.jetbrains.kotlin.ir.backend.js.ic.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.*
|
||||||
@@ -347,11 +348,12 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
|||||||
exportedDeclarations = setOf(FqName("main")),
|
exportedDeclarations = setOf(FqName("main")),
|
||||||
propertyLazyInitialization = arguments.irPropertyLazyInitialization,
|
propertyLazyInitialization = arguments.irPropertyLazyInitialization,
|
||||||
)
|
)
|
||||||
|
val dceDumpNameCache = DceDumpNameCache()
|
||||||
if (arguments.irDce) {
|
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)
|
val generateSourceMaps = configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ fun eliminateDeadDeclarations(
|
|||||||
modules: Iterable<IrModuleFragment>,
|
modules: Iterable<IrModuleFragment>,
|
||||||
context: JsIrBackendContext,
|
context: JsIrBackendContext,
|
||||||
removeUnusedAssociatedObjects: Boolean = true,
|
removeUnusedAssociatedObjects: Boolean = true,
|
||||||
|
dceDumpNameCache: DceDumpNameCache,
|
||||||
) {
|
) {
|
||||||
val allRoots = buildRoots(modules, context)
|
val allRoots = buildRoots(modules, context)
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ fun eliminateDeadDeclarations(
|
|||||||
java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info")
|
java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info")
|
||||||
|
|
||||||
val usefulDeclarationProcessor = JsUsefulDeclarationProcessor(context, printReachabilityInfo, removeUnusedAssociatedObjects)
|
val usefulDeclarationProcessor = JsUsefulDeclarationProcessor(context, printReachabilityInfo, removeUnusedAssociatedObjects)
|
||||||
val usefulDeclarations = usefulDeclarationProcessor.collectDeclarations(allRoots)
|
val usefulDeclarations = usefulDeclarationProcessor.collectDeclarations(allRoots, dceDumpNameCache)
|
||||||
|
|
||||||
val uselessDeclarationsProcessor =
|
val uselessDeclarationsProcessor =
|
||||||
UselessDeclarationsRemover(removeUnusedAssociatedObjects, usefulDeclarations, context, context.dceRuntimeDiagnostic)
|
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
|
protected open fun handleAssociatedObjects(): Unit = Unit
|
||||||
|
|
||||||
fun collectDeclarations(rootDeclarations: Iterable<IrDeclaration>): Set<IrDeclaration> {
|
fun collectDeclarations(rootDeclarations: Iterable<IrDeclaration>, dceDumpNameCache: DceDumpNameCache): Set<IrDeclaration> {
|
||||||
|
|
||||||
rootDeclarations.forEach {
|
rootDeclarations.forEach {
|
||||||
it.enqueue(it, "<ROOT>")
|
it.enqueue(it, "<ROOT>")
|
||||||
@@ -274,7 +274,7 @@ abstract class UsefulDeclarationProcessor(
|
|||||||
|
|
||||||
if (reachabilityInfos != null) {
|
if (reachabilityInfos != null) {
|
||||||
if (printReachabilityInfo) {
|
if (printReachabilityInfo) {
|
||||||
println(transformToDotLikeString(reachabilityInfos))
|
println(transformToDotLikeString(reachabilityInfos, dceDumpNameCache))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumpReachabilityInfoToFile != null) {
|
if (dumpReachabilityInfoToFile != null) {
|
||||||
@@ -285,7 +285,7 @@ abstract class UsefulDeclarationProcessor(
|
|||||||
else -> ::transformToDotLikeString
|
else -> ::transformToDotLikeString
|
||||||
}
|
}
|
||||||
|
|
||||||
out.writeText(stringify(reachabilityInfos))
|
out.writeText(stringify(reachabilityInfos, dceDumpNameCache))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -305,18 +305,24 @@ private data class ReachabilityInfo(
|
|||||||
private fun transformToStringBy(
|
private fun transformToStringBy(
|
||||||
reachabilityInfos: List<ReachabilityInfo>,
|
reachabilityInfos: List<ReachabilityInfo>,
|
||||||
separator: String,
|
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 {
|
): String {
|
||||||
return reachabilityInfos
|
return reachabilityInfos
|
||||||
.map {
|
.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()
|
.distinct()
|
||||||
.joinToString(separator)
|
.joinToString(separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformToDotLikeString(reachabilityInfos: List<ReachabilityInfo>): String {
|
private fun transformToDotLikeString(reachabilityInfos: List<ReachabilityInfo>, dceDumpNameCache: DceDumpNameCache): String {
|
||||||
return transformToStringBy(reachabilityInfos, "\n") { sourceFqn, targetFqn, description, isTargetContagious ->
|
return transformToStringBy(reachabilityInfos, "\n", dceDumpNameCache) { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||||
val comment = description + (if (isTargetContagious) "[CONTAGIOUS!]" else "")
|
val comment = description + (if (isTargetContagious) "[CONTAGIOUS!]" else "")
|
||||||
val info = "\"$sourceFqn\" -> \"$targetFqn\"" + (if (comment.isBlank()) "" else " // $comment")
|
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 {
|
private fun transformToJsonString(reachabilityInfos: List<ReachabilityInfo>, dceDumpNameCache: DceDumpNameCache): String {
|
||||||
return "[\n" + transformToStringBy(reachabilityInfos, ",\n") { sourceFqn, targetFqn, description, isTargetContagious ->
|
return "[\n" + transformToStringBy(reachabilityInfos, ",\n", dceDumpNameCache) { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||||
"""
|
"""
|
||||||
| {
|
| {
|
||||||
| "source" : "${sourceFqn.removeQuotes()}",
|
| "source" : "${sourceFqn.removeQuotes()}",
|
||||||
@@ -336,6 +342,6 @@ private fun transformToJsonString(reachabilityInfos: List<ReachabilityInfo>): St
|
|||||||
} + "\n]"
|
} + "\n]"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transformToJsConstDeclaration(reachabilityInfos: List<ReachabilityInfo>): String {
|
private fun transformToJsConstDeclaration(reachabilityInfos: List<ReachabilityInfo>, dceDumpNameCache: DceDumpNameCache): String {
|
||||||
return "export const kotlinReachabilityInfos = " + transformToJsonString(reachabilityInfos) + ";"
|
return "export const kotlinReachabilityInfos = " + transformToJsonString(reachabilityInfos, dceDumpNameCache) + ";"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.dce
|
package org.jetbrains.kotlin.ir.backend.js.dce
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
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.backend.js.lower.PrimaryConstructorLowering
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
|
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)
|
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
|
if (path == null) return
|
||||||
|
|
||||||
val declarations = linkedSetOf<IrDeclarationDumpInfo>()
|
val declarations = linkedSetOf<IrDeclarationDumpInfo>()
|
||||||
@@ -53,7 +54,7 @@ fun dumpDeclarationIrSizesIfNeed(path: String?, allModules: List<IrModuleFragmen
|
|||||||
type?.let {
|
type?.let {
|
||||||
declarations.add(
|
declarations.add(
|
||||||
IrDeclarationDumpInfo(
|
IrDeclarationDumpInfo(
|
||||||
fqName = declaration.fqNameForDceDump().removeQuotes(),
|
fqName = dceDumpNameCache.getOrPut(declaration).removeQuotes(),
|
||||||
type = it,
|
type = it,
|
||||||
size = declaration.dumpKotlinLike().length
|
size = declaration.dumpKotlinLike().length
|
||||||
)
|
)
|
||||||
@@ -72,21 +73,13 @@ fun dumpDeclarationIrSizesIfNeed(path: String?, allModules: List<IrModuleFragmen
|
|||||||
else -> listOf("", "", "\n", "")
|
else -> listOf("", "", "\n", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
val value = declarations
|
val value = declarations.joinToString(separator, prefix, postfix) { declaration ->
|
||||||
// TODO: introduce a way to assign unique names to each declaration and use it for both reachability and size infos
|
"""$indent"${declaration.fqName}": {
|
||||||
.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}": {
|
|
||||||
|$indent$indent"size": ${declaration.size},
|
|$indent$indent"size": ${declaration.size},
|
||||||
|$indent$indent"type": "${declaration.type}"
|
|$indent$indent"type": "${declaration.type}"
|
||||||
|$indent}
|
|$indent}
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
}
|
}
|
||||||
|
|
||||||
out.writeText(value)
|
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.PhaseConfig
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
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.dce.eliminateDeadDeclarations
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
@@ -21,7 +22,8 @@ fun optimizeProgramByIr(
|
|||||||
context: JsIrBackendContext,
|
context: JsIrBackendContext,
|
||||||
removeUnusedAssociatedObjects: Boolean
|
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)
|
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.backend.wasm.WasmBackendContext
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
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.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
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.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
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 =
|
val printReachabilityInfo =
|
||||||
context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) ||
|
context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) ||
|
||||||
java.lang.Boolean.getBoolean("kotlin.wasm.dce.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,
|
context = context,
|
||||||
printReachabilityInfo = printReachabilityInfo,
|
printReachabilityInfo = printReachabilityInfo,
|
||||||
dumpReachabilityInfoToFile
|
dumpReachabilityInfoToFile
|
||||||
).collectDeclarations(rootDeclarations = buildRoots(modules, context))
|
).collectDeclarations(rootDeclarations = buildRoots(modules, context), dceDumpNameCache)
|
||||||
|
|
||||||
val remover = WasmUselessDeclarationsRemover(context, usefulDeclarations)
|
val remover = WasmUselessDeclarationsRemover(context, usefulDeclarations)
|
||||||
modules.onAllFiles {
|
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.backend.wasm.wasmPhases
|
||||||
import org.jetbrains.kotlin.ir.backend.js.MainModule
|
import org.jetbrains.kotlin.ir.backend.js.MainModule
|
||||||
import org.jetbrains.kotlin.ir.backend.js.ModulesStructure
|
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.backend.js.dce.dumpDeclarationIrSizesIfNeed
|
||||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
|
||||||
import org.jetbrains.kotlin.ir.linkage.partial.PartialLinkageConfig
|
import org.jetbrains.kotlin.ir.linkage.partial.PartialLinkageConfig
|
||||||
@@ -97,9 +98,10 @@ class WasmBackendFacade(
|
|||||||
generateWat = generateWat,
|
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(
|
val compilerResultWithDCE = compileWasm(
|
||||||
allModules = allModules,
|
allModules = allModules,
|
||||||
|
|||||||
Reference in New Issue
Block a user