JS IR: introduce 'lower per module' mode

This mode is closer to how IC supposed to work - reusing work
from dependencies, not re-lowering them.
This commit is contained in:
Anton Bannykh
2021-06-18 14:25:01 +03:00
committed by TeamCityServer
parent a4cb70af31
commit eb0c13793b
4 changed files with 110 additions and 4 deletions
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.StageController
// Only allows to apply a lowering to the whole world and save the result
class WholeWorldStageController : StageController() {
override var currentStage: Int = 0
// TODO assert lowered
var declarationListsRestricted: Boolean = false
override fun <T> withStage(stage: Int, fn: () -> T): T {
val oldStage = currentStage
currentStage = stage
return try {
fn()
} finally {
currentStage = oldStage
}
}
override fun <T> withInitialIr(block: () -> T): T {
return withStage(0) {
declarationRestriction(true, block)
}
}
override fun <T> bodyLowering(fn: () -> T): T {
val wasRestricted = declarationListsRestricted
declarationListsRestricted = true
return try {
fn()
} finally {
declarationListsRestricted = wasRestricted
}
}
override fun <T> unrestrictDeclarationListsAccess(fn: () -> T): T {
return declarationRestriction(false, fn)
}
private fun <T> declarationRestriction(value: Boolean, fn: () -> T): T{
val wasRestricted = declarationListsRestricted
declarationListsRestricted = value
return try {
fn()
} finally {
declarationListsRestricted = wasRestricted
}
}
override fun canAccessDeclarationsOf(irClass: IrClass): Boolean {
return !declarationListsRestricted || irClass.visibility == DescriptorVisibilities.LOCAL/* && irClass !in context.extractedLocalClasses*/
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
import org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.config.CompilerConfiguration
@@ -54,6 +55,7 @@ fun compile(
propertyLazyInitialization: Boolean,
legacyPropertyAccess: Boolean = false,
baseClassIntoMetadata: Boolean = false,
lowerPerModule: Boolean = false,
): CompilerResult {
val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer, moduleToName) =
loadIr(project, mainModule, analyzer, configuration, allDependencies, friendDependencies, irFactory)
@@ -116,7 +118,17 @@ fun compile(
)
return transformer.generateModule(allModules)
} else {
jsPhases.invokeToplevel(phaseConfig, context, allModules)
if (lowerPerModule) {
val controller = WholeWorldStageController()
check(irFactory is PersistentIrFactory)
irFactory.stageController = controller
allModules.forEach {
lowerPreservingIcData(it, context, controller)
}
} else {
jsPhases.invokeToplevel(phaseConfig, context, allModules)
}
val transformer = IrModuleToJsTransformer(
context,
mainArguments,
@@ -130,6 +142,24 @@ fun compile(
}
}
fun lowerPreservingIcData(module: IrModuleFragment, context: JsIrBackendContext, controller: WholeWorldStageController) {
// Lower all the things
controller.currentStage = 0
pirLowerings.forEachIndexed { i, lowering ->
controller.currentStage = i + 1
when (lowering) {
is DeclarationLowering ->
lowering.declarationTransformer(context).lower(module)
is BodyLowering ->
lowering.bodyLowering(context).lower(module)
// else -> TODO what about other lowerings?
}
}
controller.currentStage = pirLowerings.size + 1
}
fun generateJsCode(
context: JsIrBackendContext,
moduleFragment: IrModuleFragment,
@@ -439,6 +439,13 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
coroutineClass.addFakeOverrides(context.irBuiltIns, implementedMembers)
// TODO constructing fake overrides on lowered declaration is tricky.
coroutineClass.declarations.transformFlat {
if (it is IrProperty && it.isFakeOverride) {
listOfNotNull(it.getter, it.setter)
} else null
}
// TODO: find out whether Kotlin/Native needs this call
initializeStateMachine(listOf(coroutineConstructor), coroutineClassThis)
@@ -49,11 +49,13 @@ abstract class BasicIrBoxTest(
private fun getBoolean(s: String, default: Boolean) = System.getProperty(s)?.let { parseBoolean(it) } ?: default
private val lowerPerModule: Boolean = getBoolean("kotlin.js.ir.lowerPerModule")
override val skipRegularMode: Boolean = getBoolean("kotlin.js.ir.skipRegularMode")
override val runIrDce: Boolean = getBoolean("kotlin.js.ir.dce", true)
override val runIrDce: Boolean = !lowerPerModule && getBoolean("kotlin.js.ir.dce", true)
override val runIrPir: Boolean = getBoolean("kotlin.js.ir.pir", true)
override val runIrPir: Boolean = !lowerPerModule && getBoolean("kotlin.js.ir.pir", true)
val runEs6Mode: Boolean = getBoolean("kotlin.js.ir.es6", false)
@@ -131,13 +133,14 @@ abstract class BasicIrBoxTest(
}
if (!skipRegularMode) {
val irFactory = if (lowerPerModule) PersistentIrFactory() else IrFactoryImpl
val compiledModule = compile(
project = config.project,
mainModule = MainModule.SourceFiles(filesToCompile),
analyzer = AnalyzerWithCompilerReport(config.configuration),
configuration = config.configuration,
phaseConfig = phaseConfig,
irFactory = IrFactoryImpl,
irFactory = irFactory,
allDependencies = resolvedLibraries,
friendDependencies = emptyList(),
mainArguments = mainCallParameters.run { if (shouldBeGenerated()) arguments() else null },
@@ -147,6 +150,7 @@ abstract class BasicIrBoxTest(
es6mode = runEs6Mode,
multiModule = splitPerModule || perModule,
propertyLazyInitialization = propertyLazyInitialization,
lowerPerModule = lowerPerModule
)
compiledModule.jsCode!!.writeTo(outputFile, config)