[JS IR] tests both per-module and regular mode

This commit is contained in:
Anton Bannykh
2021-12-08 19:13:02 +03:00
parent 95b5c44fba
commit aa628ae7b3
17 changed files with 176 additions and 128 deletions
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
import org.jetbrains.kotlin.ir.declarations.IrFactory
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -30,8 +31,7 @@ import org.jetbrains.kotlin.js.config.RuntimeDiagnostic
import org.jetbrains.kotlin.name.FqName
class CompilerResult(
val outputs: CompilationOutputs?,
val outputsAfterDce: CompilationOutputs?,
val outputs: Map<TranslationMode, CompilationOutputs>,
val tsDefinitions: String? = null
)
@@ -228,5 +228,5 @@ fun generateJsCode(
jsPhases.invokeToplevel(PhaseConfig(jsPhases), context, listOf(moduleFragment))
val transformer = IrModuleToJsTransformer(context, null, true, nameTables)
return transformer.generateModule(listOf(moduleFragment)).outputs!!.jsCode
return transformer.generateModule(listOf(moduleFragment)).outputs[TranslationMode.FULL]!!.jsCode
}
@@ -92,9 +92,6 @@ fun compileWithIC(
val transformer = IrModuleToJsTransformerTmp(
context,
mainArguments,
fullJs = generateFullJs,
dceJs = generateDceJs,
multiModule = multiModule,
relativeRequirePath = relativeRequirePath,
)
@@ -129,24 +126,28 @@ fun generateJsFromAst(
mainModuleName: String,
moduleKind: ModuleKind,
sourceMapsInfo: SourceMapsInfo?,
translationModes: Set<TranslationMode>,
caches: Map<String, ModuleCache>,
): CompilerResult {
val deserializer = JsIrAstDeserializer()
val jsIrProgram = JsIrProgram(caches.values.map {
JsIrModule(
it.name.safeModuleName,
sanitizeName(it.name.safeModuleName),
it.asts.values.sortedBy { it.name }.mapNotNull { it.ast?.let { deserializer.deserialize(ByteArrayInputStream(it)) } })
})
return CompilerResult(
generateWrappedModuleBody(
multiModule = true,
fun compilationOutput(multiModule: Boolean): CompilationOutputs {
val deserializer = JsIrAstDeserializer()
val jsIrProgram = JsIrProgram(caches.values.map {
JsIrModule(
it.name.safeModuleName,
sanitizeName(it.name.safeModuleName),
it.asts.values.sortedBy { it.name }.mapNotNull { it.ast?.let { deserializer.deserialize(ByteArrayInputStream(it)) } })
})
return generateWrappedModuleBody(
multiModule = multiModule,
mainModuleName = mainModuleName,
moduleKind = moduleKind,
jsIrProgram,
sourceMapsInfo = sourceMapsInfo,
relativeRequirePath = false,
generateScriptModule = false,
), null
)
)
}
return CompilerResult(translationModes.associate { it to compilationOutput(it.perModule) }, null)
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
import org.jetbrains.kotlin.js.util.TextOutputImpl
import org.jetbrains.kotlin.utils.DFS
import java.io.File
import java.util.*
class IrModuleToJsTransformer(
private val backendContext: JsIrBackendContext,
@@ -65,18 +66,20 @@ class IrModuleToJsTransformer(
namer.merge(module.files, additionalPackages)
}
val jsCode = if (fullJs) generateWrappedModuleBody(modules, exportedModule, namer) else null
val code = EnumMap<TranslationMode, CompilationOutputs>(TranslationMode::class.java)
val dceJsCode = if (dceJs) {
if (fullJs) code[TranslationMode.fromFlags(false, multiModule)] = generateWrappedModuleBody(modules, exportedModule, namer)
if (dceJs) {
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)
namer.merge(modules.flatMap { it.files }, additionalPackages)
generateWrappedModuleBody(modules, exportedModule, namer)
} else null
code[TranslationMode.fromFlags(true, multiModule)] = generateWrappedModuleBody(modules, exportedModule, namer)
}
return CompilerResult(jsCode, dceJsCode, dts)
return CompilerResult(code, dts)
}
private fun generateWrappedModuleBody(modules: Iterable<IrModuleFragment>, exportedModule: ExportedModule, namer: NameTables): CompilationOutputs {
@@ -30,15 +30,30 @@ import org.jetbrains.kotlin.js.util.TextOutputImpl
import org.jetbrains.kotlin.serialization.js.ModuleKind
import java.io.ByteArrayOutputStream
import java.io.File
import java.util.*
enum class TranslationMode(val dce: Boolean, val perModule: Boolean) {
FULL(dce = false, perModule = false),
FULL_DCE(dce = true, perModule = false),
PER_MODULE(dce = false, perModule = true),
PER_MODULE_DCE(dce = true, perModule = true);
companion object {
fun fromFlags(dce: Boolean, perModule: Boolean): TranslationMode {
return if (perModule) {
if (dce) PER_MODULE_DCE else PER_MODULE
} else {
if (dce) FULL_DCE else FULL
}
}
}
}
class IrModuleToJsTransformerTmp(
private val backendContext: JsIrBackendContext,
private val mainArguments: List<String>?,
private val generateScriptModule: Boolean = false,
var namer: NameTables = NameTables(emptyList(), context = backendContext),
private val fullJs: Boolean = true,
private val dceJs: Boolean = false,
private val multiModule: Boolean = false,
private val relativeRequirePath: Boolean = false,
private val moduleToName: Map<IrModuleFragment, String> = emptyMap(),
private val removeUnusedAssociatedObjects: Boolean = true,
@@ -48,7 +63,7 @@ class IrModuleToJsTransformerTmp(
private val mainModuleName = backendContext.configuration[CommonConfigurationKeys.MODULE_NAME]!!
private val moduleKind = backendContext.configuration[JSConfigurationKeys.MODULE_KIND]!!
fun generateModule(modules: Iterable<IrModuleFragment>): CompilerResult {
fun generateModule(modules: Iterable<IrModuleFragment>, modes: Set<TranslationMode>): CompilerResult {
val exportModelGenerator = ExportModelGenerator(backendContext, generateNamespacesForPackages = true)
val exportData = modules.associate { module ->
@@ -63,7 +78,7 @@ class IrModuleToJsTransformerTmp(
module.files.forEach { StaticMembersLowering(backendContext).lower(it) }
}
val jsCode = if (fullJs) generateWrappedModuleBody(
fun compilationOutput(multiModule: Boolean) = generateWrappedModuleBody(
multiModule,
mainModuleName,
moduleKind,
@@ -71,23 +86,23 @@ class IrModuleToJsTransformerTmp(
SourceMapsInfo.from(backendContext.configuration),
relativeRequirePath,
generateScriptModule,
) else null
)
val dceJsCode = if (dceJs) {
val result = EnumMap<TranslationMode, CompilationOutputs>(TranslationMode::class.java)
modes.filter { !it.dce }.forEach {
result[it] = compilationOutput(it.perModule)
}
if (modes.any { it.dce }) {
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
}
generateWrappedModuleBody(
multiModule,
mainModuleName,
moduleKind,
generateProgramFragments(modules, exportData),
SourceMapsInfo.from(backendContext.configuration),
relativeRequirePath,
generateScriptModule,
)
} else null
modes.filter { it.dce }.forEach {
result[it] = compilationOutput(it.perModule)
}
return CompilerResult(jsCode, dceJsCode, dts)
return CompilerResult(result, dts)
}
fun generateBinaryAst(files: Iterable<IrFile>): Map<String, ByteArray> {