[Wasm] Add an option to dump reachability info to file
This commit is contained in:
+14
@@ -294,6 +294,20 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
field = value
|
||||
}
|
||||
|
||||
@Argument(
|
||||
value = "-Xir-dce-dump-reachability-info-to-file",
|
||||
valueDescription = "<path>",
|
||||
description = "Dump declarations' reachability info collected during performing DCE to a file. " +
|
||||
"The format will be chosen automatically based on the file extension. " +
|
||||
"Supported output formats include JSON for .json, JS const initialized with a plain object containing information for .js, " +
|
||||
"and plain text for all other file types."
|
||||
)
|
||||
var irDceDumpReachabilityInfoToFile: String? = null
|
||||
set(value) {
|
||||
checkFrozen()
|
||||
field = value
|
||||
}
|
||||
|
||||
@Argument(value = "-Xir-property-lazy-initialization", description = "Perform lazy initialization for properties")
|
||||
var irPropertyLazyInitialization = true
|
||||
set(value) {
|
||||
|
||||
@@ -723,6 +723,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
|
||||
configuration.put(JSConfigurationKeys.PRINT_REACHABILITY_INFO, arguments.irDcePrintReachabilityInfo)
|
||||
configuration.put(JSConfigurationKeys.FAKE_OVERRIDE_VALIDATOR, arguments.fakeOverrideValidator)
|
||||
configuration.putIfNotNull(JSConfigurationKeys.DUMP_REACHABILITY_INFO_TO_FILE, arguments.irDceDumpReachabilityInfoToFile)
|
||||
|
||||
configuration.setupPartialLinkageConfig(
|
||||
mode = arguments.partialLinkageMode,
|
||||
|
||||
+71
-13
@@ -16,11 +16,13 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
abstract class UsefulDeclarationProcessor(
|
||||
private val printReachabilityInfo: Boolean,
|
||||
protected val removeUnusedAssociatedObjects: Boolean
|
||||
protected val removeUnusedAssociatedObjects: Boolean,
|
||||
private val dumpReachabilityInfoToFile: String? = null
|
||||
) {
|
||||
abstract val context: JsCommonBackendContext
|
||||
|
||||
@@ -85,12 +87,7 @@ abstract class UsefulDeclarationProcessor(
|
||||
description: String?,
|
||||
isContagiousOverridableDeclaration: Boolean,
|
||||
) {
|
||||
if (!printReachabilityInfo) return
|
||||
val fromFqn = (from as? IrDeclarationWithName)?.fqNameWhenAvailable?.asString() ?: "<unknown>"
|
||||
val toFqn = (to as? IrDeclarationWithName)?.fqNameWhenAvailable?.asString() ?: "<unknown>"
|
||||
val comment = (description ?: "") + (if (isContagiousOverridableDeclaration) "[CONTAGIOUS!]" else "")
|
||||
val info = "\"$fromFqn\" -> \"$toFqn\"" + (if (comment.isBlank()) "" else " // $comment")
|
||||
reachabilityInfo.add(info)
|
||||
reachabilityInfos?.add(ReachabilityInfo(from, to, description, isContagiousOverridableDeclaration))
|
||||
}
|
||||
|
||||
protected fun IrDeclaration.enqueue(
|
||||
@@ -133,11 +130,12 @@ abstract class UsefulDeclarationProcessor(
|
||||
//
|
||||
// The collection must be a subset of [result] set.
|
||||
private val contagiousReachableDeclarations = hashSetOf<IrOverridableDeclaration<*>>()
|
||||
protected val constructedClasses = hashSetOf<IrClass>()
|
||||
private val reachabilityInfo: MutableSet<String> = if (printReachabilityInfo) linkedSetOf() else Collections.emptySet()
|
||||
protected val constructedClasses = linkedSetOf<IrClass>()
|
||||
private val reachabilityInfos =
|
||||
if (printReachabilityInfo || dumpReachabilityInfoToFile != null) mutableListOf<ReachabilityInfo>() else null
|
||||
private val queue = ArrayDeque<IrDeclaration>()
|
||||
protected val result = hashSetOf<IrDeclaration>()
|
||||
protected val classesWithObjectAssociations = hashSetOf<IrClass>()
|
||||
protected val classesWithObjectAssociations = linkedSetOf<IrClass>()
|
||||
|
||||
val usefulPolyfilledDeclarations = hashSetOf<IrDeclaration>()
|
||||
|
||||
@@ -268,10 +266,70 @@ abstract class UsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
if (printReachabilityInfo) {
|
||||
reachabilityInfo.forEach(::println)
|
||||
if (reachabilityInfos != null) {
|
||||
if (printReachabilityInfo) {
|
||||
println(transformToDotLikeString(reachabilityInfos))
|
||||
}
|
||||
|
||||
if (dumpReachabilityInfoToFile != null) {
|
||||
val out = File(dumpReachabilityInfoToFile)
|
||||
val stringify = when (out.extension) {
|
||||
"json" -> ::transformToJsonString
|
||||
"js" -> ::transformToJsConstDeclaration
|
||||
else -> ::transformToDotLikeString
|
||||
}
|
||||
|
||||
out.writeText(stringify(reachabilityInfos))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class ReachabilityInfo(
|
||||
val source: IrDeclaration,
|
||||
val target: IrDeclaration,
|
||||
val description: String?,
|
||||
val isTargetContagious: Boolean
|
||||
)
|
||||
|
||||
private fun transformToStringBy(
|
||||
reachabilityInfos: List<ReachabilityInfo>,
|
||||
separator: String,
|
||||
transformer: (sourceFqn: String, targetFqn: String, description: String, isTargetContagious: Boolean) -> String
|
||||
): String {
|
||||
fun IrDeclaration.fqnOrUnknown() = (this as? IrDeclarationWithName)?.fqNameWhenAvailable?.asString() ?: "<unknown>"
|
||||
|
||||
return reachabilityInfos
|
||||
.map {
|
||||
transformer(it.source.fqnOrUnknown(), it.target.fqnOrUnknown(), it.description ?: "", it.isTargetContagious)
|
||||
}
|
||||
.distinct()
|
||||
.joinToString(separator)
|
||||
}
|
||||
|
||||
private fun transformToDotLikeString(reachabilityInfos: List<ReachabilityInfo>): String {
|
||||
return transformToStringBy(reachabilityInfos, "\n") { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||
val comment = description + (if (isTargetContagious) "[CONTAGIOUS!]" else "")
|
||||
val info = "\"$sourceFqn\" -> \"$targetFqn\"" + (if (comment.isBlank()) "" else " // $comment")
|
||||
|
||||
info
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformToJsonString(reachabilityInfos: List<ReachabilityInfo>): String {
|
||||
return "[\n" + transformToStringBy(reachabilityInfos, ",\n") { sourceFqn, targetFqn, description, isTargetContagious ->
|
||||
"""
|
||||
| {
|
||||
| "source" : "$sourceFqn",
|
||||
| "target" : "$targetFqn",
|
||||
| "description" : "$description",
|
||||
| "isTargetContagious" : $isTargetContagious
|
||||
| }""".trimMargin()
|
||||
} + "\n]"
|
||||
}
|
||||
|
||||
private fun transformToJsConstDeclaration(reachabilityInfos: List<ReachabilityInfo>): String {
|
||||
return "const kotlinReachabilityInfos = " + transformToJsonString(reachabilityInfos) + ";"
|
||||
}
|
||||
|
||||
@@ -20,9 +20,14 @@ fun eliminateDeadDeclarations(modules: List<IrModuleFragment>, context: WasmBack
|
||||
context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) ||
|
||||
java.lang.Boolean.getBoolean("kotlin.wasm.dce.print.reachability.info")
|
||||
|
||||
val dumpReachabilityInfoToFile: String? =
|
||||
context.configuration.get(JSConfigurationKeys.DUMP_REACHABILITY_INFO_TO_FILE)
|
||||
?: System.getProperty("kotlin.wasm.dce.dump.reachability.info.to.file")
|
||||
|
||||
val usefulDeclarations = WasmUsefulDeclarationProcessor(
|
||||
context = context,
|
||||
printReachabilityInfo = printReachabilityInfo
|
||||
printReachabilityInfo = printReachabilityInfo,
|
||||
dumpReachabilityInfoToFile
|
||||
).collectDeclarations(rootDeclarations = buildRoots(modules, context))
|
||||
|
||||
val remover = WasmUselessDeclarationsRemover(usefulDeclarations)
|
||||
|
||||
+3
-2
@@ -18,8 +18,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
internal class WasmUsefulDeclarationProcessor(
|
||||
override val context: WasmBackendContext,
|
||||
printReachabilityInfo: Boolean
|
||||
) : UsefulDeclarationProcessor(printReachabilityInfo, removeUnusedAssociatedObjects = false) {
|
||||
printReachabilityInfo: Boolean,
|
||||
dumpReachabilityInfoToFile: String?
|
||||
) : UsefulDeclarationProcessor(printReachabilityInfo, removeUnusedAssociatedObjects = false, dumpReachabilityInfoToFile) {
|
||||
|
||||
private val unitGetInstance: IrSimpleFunction = context.findUnitGetInstanceFunction()
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ public class JSConfigurationKeys {
|
||||
public static final CompilerConfigurationKey<Boolean> PRINT_REACHABILITY_INFO =
|
||||
CompilerConfigurationKey.create("print declarations' reachability info during performing DCE");
|
||||
|
||||
public static final CompilerConfigurationKey<String> DUMP_REACHABILITY_INFO_TO_FILE =
|
||||
CompilerConfigurationKey.create("dump declarations' reachability info to file during performing DCE");
|
||||
|
||||
public static final CompilerConfigurationKey<Boolean> FAKE_OVERRIDE_VALIDATOR =
|
||||
CompilerConfigurationKey.create("IR fake override validator");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user