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(
modules: Iterable<IrModuleFragment>,
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<IrModuleFragment>, context: JsIrBackend
private fun processUselessDeclarations(
modules: Iterable<IrModuleFragment>,
usefulDeclarations: Set<IrDeclaration>,
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<IrDeclaration>, context: JsIrBackendContext): Set<IrDeclaration> {
fun usefulDeclarations(
roots: Iterable<IrDeclaration>,
context: JsIrBackendContext,
removeUnusedAssociatedObjects: Boolean,
): Set<IrDeclaration> {
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<IrDeclaration>, 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")
@@ -193,6 +193,7 @@ fun icCompile(
multiModule = multiModule,
relativeRequirePath = relativeRequirePath,
moduleToName = moduleToName,
removeUnusedAssociatedObjects = false,
)
irFactory.stageController = object : StageController(999) {}
@@ -41,6 +41,7 @@ class IrModuleToJsTransformer(
private val multiModule: Boolean = false,
private val relativeRequirePath: Boolean = false,
private val moduleToName: Map<IrModuleFragment, String> = 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)