[JS IR] move fragment generation closer to the beginning

This commit is contained in:
Anton Bannykh
2021-09-23 10:31:12 +03:00
committed by teamcityserver
parent b1b263615c
commit 7e7c84fcfb
2 changed files with 64 additions and 29 deletions
@@ -72,7 +72,7 @@ class IrModuleToJsTransformer(
namer.merge(module.files, additionalPackages) namer.merge(module.files, additionalPackages)
} }
val jsCode = if (fullJs) generateWrappedModuleBody(modules, exportData, namer) else null val jsCode = if (fullJs) generateWrappedModuleBody(modules, generateProgramFragments(modules, exportData, namer), namer) else null
val dceJsCode = if (dceJs) { val dceJsCode = if (dceJs) {
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects) eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
@@ -80,15 +80,51 @@ class IrModuleToJsTransformer(
// 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)
namer.merge(modules.flatMap { it.files }, additionalPackages) namer.merge(modules.flatMap { it.files }, additionalPackages)
generateWrappedModuleBody(modules, exportData, namer) generateWrappedModuleBody(modules, generateProgramFragments(modules, exportData, namer), namer)
} else null } else null
return CompilerResult(jsCode, dceJsCode, dts) return CompilerResult(jsCode, dceJsCode, dts)
} }
private fun generateWrappedModuleBody( private fun generateProgramFragments(
modules: Iterable<IrModuleFragment>, modules: Iterable<IrModuleFragment>,
exportData: Map<IrModuleFragment, Map<IrFile, List<ExportedDeclaration>>>, exportData: Map<IrModuleFragment, Map<IrFile, List<ExportedDeclaration>>>,
namer: NameTables,
): Map<IrFile, JsIrProgramFragment> {
val nameGenerator = IrNamerImpl(newNameTables = namer, backendContext)
val fragments = mutableMapOf<IrFile, JsIrProgramFragment>()
modules.forEach { m ->
m.files.forEach { f ->
val fragment = JsIrProgramFragment(f.fqName.asString())
val exports = exportData[m]!![f]!! // TODO
val internalModuleName = JsName("_")
val globalNames = NameTable<String>(namer.globalNames)
val exportStatements =
ExportModelToJsStatements(nameGenerator, { globalNames.declareFreshName(it, it) }).generateModuleExport(
ExportedModule(mainModuleName, moduleKind, exports),
internalModuleName,
)
fragment.exports.statements += exportStatements
if (exports.isNotEmpty()) {
fragment.dts = exports.toTypeScript(moduleKind)
}
fragments[f] = fragment
}
}
return fragments
}
private fun generateWrappedModuleBody(
modules: Iterable<IrModuleFragment>,
fragments: Map<IrFile, JsIrProgramFragment>,
namer: NameTables namer: NameTables
): CompilationOutputs { ): CompilationOutputs {
if (multiModule) { if (multiModule) {
@@ -104,7 +140,7 @@ class IrModuleToJsTransformer(
mainModuleName, mainModuleName,
listOf(main), listOf(main),
others, others,
exportData, fragments,
namer, namer,
refInfo, refInfo,
generateMainCall = true generateMainCall = true
@@ -117,7 +153,7 @@ class IrModuleToJsTransformer(
moduleName, moduleName,
listOf(module), listOf(module),
others.drop(index + 1), others.drop(index + 1),
exportData, fragments,
namer, namer,
refInfo, refInfo,
generateMainCall = false generateMainCall = false
@@ -130,7 +166,7 @@ class IrModuleToJsTransformer(
mainModuleName, mainModuleName,
modules, modules,
emptyList(), emptyList(),
exportData, fragments,
namer, namer,
EmptyCrossModuleReferenceInfo EmptyCrossModuleReferenceInfo
) )
@@ -141,7 +177,7 @@ class IrModuleToJsTransformer(
moduleName: String, moduleName: String,
modules: Iterable<IrModuleFragment>, modules: Iterable<IrModuleFragment>,
dependencies: Iterable<IrModuleFragment>, dependencies: Iterable<IrModuleFragment>,
exportData: Map<IrModuleFragment, Map<IrFile, List<ExportedDeclaration>>>, fragments: Map<IrFile, JsIrProgramFragment>,
namer: NameTables, namer: NameTables,
refInfo: CrossModuleReferenceInfo, refInfo: CrossModuleReferenceInfo,
generateMainCall: Boolean = true generateMainCall: Boolean = true
@@ -163,17 +199,9 @@ class IrModuleToJsTransformer(
declareFreshGlobal = { JsName(sanitizeName(it)) } // TODO: Declare fresh name declareFreshGlobal = { JsName(sanitizeName(it)) } // TODO: Declare fresh name
) )
val (moduleBody, callToMain) = generateModuleBody(modules, staticContext) val (moduleBody, callToMain, exportStatements) = generateModuleBody(modules, staticContext, fragments)
val internalModuleName = JsName("_") val internalModuleName = JsName("_")
val globalNames = NameTable<String>(namer.globalNames)
val exportStatements = exportData.entries.filter { (m, _) -> m in modules }.flatMap { (_, f) -> f.values.flatMap {
ExportModelToJsStatements(nameGenerator, { globalNames.declareFreshName(it, it) }).generateModuleExport(
ExportedModule(moduleName, moduleKind, it),
internalModuleName,
)
} }
val (crossModuleImports, importedKotlinModules) = generateCrossModuleImports( val (crossModuleImports, importedKotlinModules) = generateCrossModuleImports(
nameGenerator, nameGenerator,
@@ -304,23 +332,26 @@ class IrModuleToJsTransformer(
} }
} }
private data class ModuleBody(val statements: List<JsStatement>, val mainFunction: JsStatement?) private data class ModuleBody(val statements: List<JsStatement>, val mainFunction: JsStatement?, val exportStatements: List<JsStatement>)
private fun generateModuleBody(modules: Iterable<IrModuleFragment>, staticContext: JsStaticContext): ModuleBody { private fun generateModuleBody(
val fragments = modules.map { it.files.map { generateProgramFragment(it, staticContext) } } modules: Iterable<IrModuleFragment>,
staticContext: JsStaticContext,
fragments: Map<IrFile, JsIrProgramFragment>
): ModuleBody {
val thisModuleFragments = modules.map { it.files.map { fragments[it]!!.fillProgramFragment(it, staticContext) } }
return merge(fragments, staticContext) return merge(thisModuleFragments, staticContext)
} }
private val generateFilePaths = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_COMMENTS_WITH_FILE_PATH) private val generateFilePaths = backendContext.configuration.getBoolean(JSConfigurationKeys.GENERATE_COMMENTS_WITH_FILE_PATH)
private val pathPrefixMap = backendContext.configuration.getMap(JSConfigurationKeys.FILE_PATHS_PREFIX_MAP) private val pathPrefixMap = backendContext.configuration.getMap(JSConfigurationKeys.FILE_PATHS_PREFIX_MAP)
private fun generateProgramFragment(file: IrFile, staticContext: JsStaticContext): JsIrProgramFragment { private fun JsIrProgramFragment.fillProgramFragment(file: IrFile, staticContext: JsStaticContext): JsIrProgramFragment {
require(staticContext.classModels.isEmpty()) require(staticContext.classModels.isEmpty())
require(staticContext.initializerBlock.statements.isEmpty()) require(staticContext.initializerBlock.statements.isEmpty())
val result = JsIrProgramFragment(file.fqName.asString()) val statements = this.declarations.statements
val statements = result.declarations.statements
val fileStatements = file.accept(IrFileToJsTransformer(), staticContext).statements val fileStatements = file.accept(IrFileToJsTransformer(), staticContext).statements
if (fileStatements.isNotEmpty()) { if (fileStatements.isNotEmpty()) {
@@ -348,26 +379,26 @@ class IrModuleToJsTransformer(
statements.endRegion() statements.endRegion()
} }
result.classes += staticContext.classModels this.classes += staticContext.classModels
result.initializers.statements += staticContext.initializerBlock.statements this.initializers.statements += staticContext.initializerBlock.statements
if (mainArguments != null) { if (mainArguments != null) {
JsMainFunctionDetector(backendContext).getMainFunctionOrNull(file)?.let { JsMainFunctionDetector(backendContext).getMainFunctionOrNull(file)?.let {
val jsName = staticContext.getNameForStaticFunction(it) val jsName = staticContext.getNameForStaticFunction(it)
val generateArgv = it.valueParameters.firstOrNull()?.isStringArrayParameter() ?: false val generateArgv = it.valueParameters.firstOrNull()?.isStringArrayParameter() ?: false
val generateContinuation = it.isLoweredSuspendFunction(backendContext) val generateContinuation = it.isLoweredSuspendFunction(backendContext)
result.mainFunction = JsInvocation(jsName.makeRef(), generateMainArguments(generateArgv, generateContinuation, staticContext)).makeStmt() this.mainFunction = JsInvocation(jsName.makeRef(), generateMainArguments(generateArgv, generateContinuation, staticContext)).makeStmt()
} }
} }
backendContext.testFunsPerFile[file]?.let { backendContext.testFunsPerFile[file]?.let {
result.testFunInvocation = JsInvocation(staticContext.getNameForStaticFunction(it).makeRef()).makeStmt() this.testFunInvocation = JsInvocation(staticContext.getNameForStaticFunction(it).makeRef()).makeStmt()
} }
staticContext.classModels.clear() staticContext.classModels.clear()
staticContext.initializerBlock.statements.clear() staticContext.initializerBlock.statements.clear()
return result return this
} }
private fun merge(fragments: List<List<JsIrProgramFragment>>, staticContext: JsStaticContext): ModuleBody { private fun merge(fragments: List<List<JsIrProgramFragment>>, staticContext: JsStaticContext): ModuleBody {
@@ -420,7 +451,9 @@ class IrModuleToJsTransformer(
val callToMain = lastModuleFragments.sortedBy { it.packageFqn }.firstNotNullOfOrNull { it.mainFunction } val callToMain = lastModuleFragments.sortedBy { it.packageFqn }.firstNotNullOfOrNull { it.mainFunction }
return ModuleBody(statements, callToMain) val exportStatements = fragments.flatMap { it.flatMap { it.exports.statements } }
return ModuleBody(statements, callToMain, exportStatements)
} }
private fun generateMainArguments( private fun generateMainArguments(
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.js.backend.ast.JsStatement
class JsIrProgramFragment(val packageFqn: String) { class JsIrProgramFragment(val packageFqn: String) {
val declarations = JsGlobalBlock() val declarations = JsGlobalBlock()
val exports = JsGlobalBlock()
var dts: String? = null
val classes = mutableMapOf<IrClassSymbol, JsIrClassModel>() val classes = mutableMapOf<IrClassSymbol, JsIrClassModel>()
val initializers = JsGlobalBlock() val initializers = JsGlobalBlock()
var mainFunction: JsStatement? = null var mainFunction: JsStatement? = null