diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt index 02619a9c1ab..a59021a966e 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/Dce.kt @@ -29,18 +29,20 @@ import java.util.* fun eliminateDeadDeclarations( modules: Iterable, - context: JsIrBackendContext + context: JsIrBackendContext, + removeUnusedAssociatedObjects: Boolean = true, ) { val allRoots = context.irFactory.stageController.withInitialIr { buildRoots(modules, context) } - val usefulDeclarations = usefulDeclarations(allRoots, context) + val usefulDeclarations = usefulDeclarations(allRoots, context, removeUnusedAssociatedObjects) context.irFactory.stageController.unrestrictDeclarationListsAccess { processUselessDeclarations( modules, usefulDeclarations, - context + context, + removeUnusedAssociatedObjects, ) } } @@ -111,7 +113,8 @@ private fun buildRoots(modules: Iterable, context: JsIrBackend private fun processUselessDeclarations( modules: Iterable, usefulDeclarations: Set, - context: JsIrBackendContext + context: JsIrBackendContext, + removeUnusedAssociatedObjects: Boolean, ) { modules.forEach { module -> module.files.forEach { @@ -136,7 +139,7 @@ private fun processUselessDeclarations( // Remove annotations for `findAssociatedObject` feature, which reference objects eliminated by the DCE. // Otherwise `JsClassGenerator.generateAssociatedKeyProperties` will try to reference the object factory (which is removed). // That will result in an error from the Namer. It cannot generate a name for an absent declaration. - if (declaration.annotations.any { !it.shouldKeepAnnotation() }) { + if (removeUnusedAssociatedObjects && declaration.annotations.any { !it.shouldKeepAnnotation() }) { declaration.annotations = declaration.annotations.filter { it.shouldKeepAnnotation() } } } @@ -216,7 +219,11 @@ private fun IrField.isKotlinPackage() = fqNameWhenAvailable?.asString()?.startsWith("kotlin") == true // TODO refactor it, the function became too big. Please contact me (Zalim) before doing it. -fun usefulDeclarations(roots: Iterable, context: JsIrBackendContext): Set { +fun usefulDeclarations( + roots: Iterable, + context: JsIrBackendContext, + removeUnusedAssociatedObjects: Boolean, +): Set { val printReachabilityInfo = context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) || java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info") @@ -479,11 +486,11 @@ fun usefulDeclarations(roots: Iterable, context: JsIrBackendConte // Handle objects, constructed via `findAssociatedObject` annotation referencedJsClassesFromExpressions += constructedClasses.filterDescendantsOf(referencedJsClassesFromExpressions) // Grow the set of possible results of instance::class expression for (klass in classesWithObjectAssociations) { - if (klass !in referencedJsClasses && klass !in referencedJsClassesFromExpressions) continue + if (removeUnusedAssociatedObjects && klass !in referencedJsClasses && klass !in referencedJsClassesFromExpressions) continue for (annotation in klass.annotations) { val annotationClass = annotation.symbol.owner.constructedClass - if (annotationClass !in referencedJsClasses) continue + if (removeUnusedAssociatedObjects && annotationClass !in referencedJsClasses) continue annotation.associatedObject()?.let { obj -> context.mapping.objectToGetInstanceFunction[obj]?.enqueue(klass, "associated object factory") diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ic.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ic.kt index c2f726395ce..ae05bf3ac1d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ic.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic/ic.kt @@ -193,6 +193,7 @@ fun icCompile( multiModule = multiModule, relativeRequirePath = relativeRequirePath, moduleToName = moduleToName, + removeUnusedAssociatedObjects = false, ) irFactory.stageController = object : StageController(999) {} diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index ad2efbe884b..89f7db93abd 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -41,6 +41,7 @@ class IrModuleToJsTransformer( private val multiModule: Boolean = false, private val relativeRequirePath: Boolean = false, private val moduleToName: Map = emptyMap(), + private val removeUnusedAssociatedObjects: Boolean = true, ) { private val generateRegionComments = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_REGION_COMMENTS) @@ -69,7 +70,7 @@ class IrModuleToJsTransformer( val jsCode = if (fullJs) generateWrappedModuleBody(modules, exportedModule, namer) else null val dceJsCode = if (dceJs) { - eliminateDeadDeclarations(modules, backendContext) + eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects) // Use a fresh namer for DCE so that we could compare the result with DCE-driven // TODO: is this mode relevant for scripting? If yes, refactor so that the external name tables are used here when needed. val namer = NameTables(emptyList(), context = backendContext)