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:
committed by
teamcityserver
parent
508d3bd9c0
commit
4cee44cd6e
@@ -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) {}
|
||||||
|
|||||||
+2
-1
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user