JS IR IC: add a flag for DCE hack

The deserialized PIR does not support declaration mutation.
Until that's fixed the associatedObject removal optimization
has to be disabled.
This commit is contained in:
Anton Bannykh
2021-07-19 13:21:58 +03:00
committed by teamcityserver
parent 508d3bd9c0
commit 4cee44cd6e
3 changed files with 18 additions and 9 deletions
@@ -29,18 +29,20 @@ import java.util.*
fun eliminateDeadDeclarations( fun eliminateDeadDeclarations(
modules: Iterable<IrModuleFragment>, modules: Iterable<IrModuleFragment>,
context: JsIrBackendContext context: JsIrBackendContext,
removeUnusedAssociatedObjects: Boolean = true,
) { ) {
val allRoots = context.irFactory.stageController.withInitialIr { buildRoots(modules, context) } val allRoots = context.irFactory.stageController.withInitialIr { buildRoots(modules, context) }
val usefulDeclarations = usefulDeclarations(allRoots, context) val usefulDeclarations = usefulDeclarations(allRoots, context, removeUnusedAssociatedObjects)
context.irFactory.stageController.unrestrictDeclarationListsAccess { context.irFactory.stageController.unrestrictDeclarationListsAccess {
processUselessDeclarations( processUselessDeclarations(
modules, modules,
usefulDeclarations, usefulDeclarations,
context context,
removeUnusedAssociatedObjects,
) )
} }
} }
@@ -111,7 +113,8 @@ private fun buildRoots(modules: Iterable<IrModuleFragment>, context: JsIrBackend
private fun processUselessDeclarations( private fun processUselessDeclarations(
modules: Iterable<IrModuleFragment>, modules: Iterable<IrModuleFragment>,
usefulDeclarations: Set<IrDeclaration>, usefulDeclarations: Set<IrDeclaration>,
context: JsIrBackendContext context: JsIrBackendContext,
removeUnusedAssociatedObjects: Boolean,
) { ) {
modules.forEach { module -> modules.forEach { module ->
module.files.forEach { module.files.forEach {
@@ -136,7 +139,7 @@ private fun processUselessDeclarations(
// Remove annotations for `findAssociatedObject` feature, which reference objects eliminated by the DCE. // 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). // 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. // 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() } declaration.annotations = declaration.annotations.filter { it.shouldKeepAnnotation() }
} }
} }
@@ -216,7 +219,11 @@ private fun IrField.isKotlinPackage() =
fqNameWhenAvailable?.asString()?.startsWith("kotlin") == true fqNameWhenAvailable?.asString()?.startsWith("kotlin") == true
// TODO refactor it, the function became too big. Please contact me (Zalim) before doing it. // TODO refactor it, the function became too big. Please contact me (Zalim) before doing it.
fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendContext): Set<IrDeclaration> { fun usefulDeclarations(
roots: Iterable<IrDeclaration>,
context: JsIrBackendContext,
removeUnusedAssociatedObjects: Boolean,
): Set<IrDeclaration> {
val printReachabilityInfo = val printReachabilityInfo =
context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) || context.configuration.getBoolean(JSConfigurationKeys.PRINT_REACHABILITY_INFO) ||
java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info") java.lang.Boolean.getBoolean("kotlin.js.ir.dce.print.reachability.info")
@@ -479,11 +486,11 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
// Handle objects, constructed via `findAssociatedObject` annotation // Handle objects, constructed via `findAssociatedObject` annotation
referencedJsClassesFromExpressions += constructedClasses.filterDescendantsOf(referencedJsClassesFromExpressions) // Grow the set of possible results of instance::class expression referencedJsClassesFromExpressions += constructedClasses.filterDescendantsOf(referencedJsClassesFromExpressions) // Grow the set of possible results of instance::class expression
for (klass in classesWithObjectAssociations) { 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) { for (annotation in klass.annotations) {
val annotationClass = annotation.symbol.owner.constructedClass val annotationClass = annotation.symbol.owner.constructedClass
if (annotationClass !in referencedJsClasses) continue if (removeUnusedAssociatedObjects && annotationClass !in referencedJsClasses) continue
annotation.associatedObject()?.let { obj -> annotation.associatedObject()?.let { obj ->
context.mapping.objectToGetInstanceFunction[obj]?.enqueue(klass, "associated object factory") context.mapping.objectToGetInstanceFunction[obj]?.enqueue(klass, "associated object factory")
@@ -193,6 +193,7 @@ fun icCompile(
multiModule = multiModule, multiModule = multiModule,
relativeRequirePath = relativeRequirePath, relativeRequirePath = relativeRequirePath,
moduleToName = moduleToName, moduleToName = moduleToName,
removeUnusedAssociatedObjects = false,
) )
irFactory.stageController = object : StageController(999) {} irFactory.stageController = object : StageController(999) {}
@@ -41,6 +41,7 @@ class IrModuleToJsTransformer(
private val multiModule: Boolean = false, private val multiModule: Boolean = false,
private val relativeRequirePath: Boolean = false, private val relativeRequirePath: Boolean = false,
private val moduleToName: Map<IrModuleFragment, String> = emptyMap(), private val moduleToName: Map<IrModuleFragment, String> = emptyMap(),
private val removeUnusedAssociatedObjects: Boolean = true,
) { ) {
private val generateRegionComments = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_REGION_COMMENTS) 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 jsCode = if (fullJs) generateWrappedModuleBody(modules, exportedModule, namer) else null
val dceJsCode = if (dceJs) { 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 // 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. // 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) val namer = NameTables(emptyList(), context = backendContext)