[JS IR BE] Support mode of linking multiple klibs without .kt files

This commit is contained in:
Svyatoslav Kuzmich
2020-01-09 20:27:08 +03:00
parent 553128c3c9
commit fbf71be30c
7 changed files with 102 additions and 39 deletions
@@ -128,6 +128,13 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xir-only", description = "Disables pre-IR backend")
var irOnly: Boolean by FreezableVar(false)
@Argument(
value = "-Xinclude",
valueDescription = "<path>",
description = "A path to an intermediate library that should be processed in the same manner as source files."
)
var includes: String? by NullableStringFreezableVar(null)
@Argument(
value = "-Xgenerate-dts",
description = "Generate TypeScript declarations .d.ts file alongside JS file. Available in IR backend only."
@@ -36,11 +36,11 @@ import org.jetbrains.kotlin.js.config.EcmaVersion
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.util.Logger
import org.jetbrains.kotlin.utils.JsMetadataVersion
import org.jetbrains.kotlin.utils.KotlinPaths
import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
@@ -102,11 +102,13 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
if (arguments.version) {
return OK
}
messageCollector.report(ERROR, "Specify at least one source file or directory", null)
return COMPILATION_ERROR
if (arguments.includes.isNullOrEmpty()) {
messageCollector.report(ERROR, "Specify at least one source file or directory", null)
return COMPILATION_ERROR
}
}
val libraries: List<String> = configureLibraries(arguments.libraries)
val libraries: List<String> = configureLibraries(arguments.libraries) + listOfNotNull(arguments.includes)
val friendLibraries: List<String> = configureLibraries(arguments.friendModules)
configuration.put(JSConfigurationKeys.LIBRARIES, libraries)
@@ -138,7 +140,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
return ExitCode.COMPILATION_ERROR
}
if (sourcesFiles.isEmpty() && !IncrementalCompilation.isEnabledForJs()) {
if (sourcesFiles.isEmpty() && !IncrementalCompilation.isEnabledForJs() && arguments.includes.isNullOrEmpty()) {
messageCollector.report(ERROR, "No source files", null)
return COMPILATION_ERROR
}
@@ -200,10 +202,23 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
if (arguments.irProduceJs) {
val phaseConfig = createPhaseConfig(jsPhases, arguments, messageCollector)
val includes = arguments.includes
val mainModule = if (includes != null) {
if (sourcesFiles.isNotEmpty()) {
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
}
val allLibraries = resolvedLibraries.getFullList()
val mainLib = allLibraries.find { it.libraryFile.absolutePath == File(includes).absolutePath }!!
MainModule.Klib(mainLib)
} else {
MainModule.SourceFiles(sourcesFiles)
}
val compiledModule = try {
compile(
projectJs,
sourcesFiles,
mainModule,
config.configuration,
phaseConfig,
allDependencies = resolvedLibraries,
@@ -47,7 +47,7 @@ class CompilerResult(
fun compile(
project: Project,
files: List<KtFile>,
mainModule: MainModule,
configuration: CompilerConfiguration,
phaseConfig: PhaseConfig,
allDependencies: KotlinLibraryResolveResult,
@@ -57,8 +57,8 @@ fun compile(
generateFullJs: Boolean = true,
generateDceJs: Boolean = false
): CompilerResult {
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
loadIr(project, files, configuration, allDependencies, friendDependencies)
val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
loadIr(project, mainModule, configuration, allDependencies, friendDependencies)
val moduleDescriptor = moduleFragment.descriptor
@@ -72,7 +72,12 @@ fun compile(
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
}
val irFiles = dependencyModules.flatMap { it.files } + moduleFragment.files
val allModules = when (mainModule) {
is MainModule.SourceFiles -> dependencyModules + listOf(moduleFragment)
is MainModule.Klib -> dependencyModules
}
val irFiles = allModules.flatMap { it.files }
moduleFragment.files.clear()
moduleFragment.files += irFiles
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.backend.wasm.codegen.IrModuleToWasm
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.backend.js.MainModule
import org.jetbrains.kotlin.ir.backend.js.loadIr
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
@@ -31,7 +32,7 @@ fun compileWasm(
exportedDeclarations: Set<FqName> = emptySet()
): WasmCompilerResult {
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
loadIr(project, files, configuration, allDependencies, friendDependencies)
loadIr(project, MainModule.SourceFiles(files), configuration, allDependencies, friendDependencies)
val moduleDescriptor = moduleFragment.descriptor
val context = WasmBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, exportedDeclarations, configuration)
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
import org.jetbrains.kotlin.backend.common.serialization.KlibIrVersion
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
@@ -19,8 +20,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -32,10 +31,7 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KlibMetad
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
import org.jetbrains.kotlin.ir.util.IrDeserializer
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
@@ -126,7 +122,7 @@ fun generateKLib(
icData = emptyList()
}
val depsDescriptors = ModulesStructure(project, files, configuration, allDependencies, friendDependencies)
val depsDescriptors = ModulesStructure(project, MainModule.SourceFiles(files), configuration, allDependencies, friendDependencies)
val psi2IrContext = runAnalysisAndPreparePsi2Ir(depsDescriptors)
@@ -174,30 +170,63 @@ private fun sortDependencies(dependencies: List<KotlinLibrary>, mapping: Map<Kot
fun loadIr(
project: Project,
files: List<KtFile>,
mainModule: MainModule,
configuration: CompilerConfiguration,
allDependencies: KotlinLibraryResolveResult,
friendDependencies: List<KotlinLibrary>
): IrModuleInfo {
val depsDescriptors = ModulesStructure(project, files, configuration, allDependencies, friendDependencies)
val depsDescriptors = ModulesStructure(project, mainModule, configuration, allDependencies, friendDependencies)
val psi2IrContext = runAnalysisAndPreparePsi2Ir(depsDescriptors)
when (mainModule) {
is MainModule.SourceFiles -> {
val psi2IrContext: GeneratorContext = runAnalysisAndPreparePsi2Ir(depsDescriptors)
val irBuiltIns = psi2IrContext.irBuiltIns
val symbolTable = psi2IrContext.symbolTable
val moduleDescriptor = psi2IrContext.moduleDescriptor
val irBuiltIns = psi2IrContext.irBuiltIns
val symbolTable = psi2IrContext.symbolTable
val moduleDescriptor = psi2IrContext.moduleDescriptor
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
}
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
deserializer.initializeExpectActualLinker()
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, mainModule.files, deserializer)
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
}
is MainModule.Klib -> {
val moduleDescriptor = depsDescriptors.getModuleDescriptor(mainModule.lib)
val symbolTable = SymbolTable()
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
val typeTranslator = TypeTranslator(
symbolTable,
depsDescriptors.compilerConfiguration.languageVersionSettings,
builtIns = moduleDescriptor.builtIns
)
typeTranslator.constantValueGenerator = constantValueGenerator
constantValueGenerator.typeTranslator = typeTranslator
val irBuiltIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable)
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
val strategy =
if (it == mainModule.lib)
DeserializationStrategy.ALL
else
DeserializationStrategy.EXPLICITLY_EXPORTED
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), strategy)
}
deserializer.initializeExpectActualLinker()
val moduleFragment = deserializedModuleFragments.last()
val irProviders = generateTypicalIrProviderList(moduleDescriptor, irBuiltIns, symbolTable, deserializer)
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies()
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
}
}
deserializer.initializeExpectActualLinker()
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, files, deserializer)
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
}
private fun runAnalysisAndPreparePsi2Ir(depsDescriptors: ModulesStructure): GeneratorContext {
@@ -277,9 +306,14 @@ fun getModuleDescriptorByLibrary(current: KotlinLibrary, mapping: Map<String, Mo
object JsIrCompilationError : Throwable()
sealed class MainModule {
class SourceFiles(val files: List<KtFile>) : MainModule()
class Klib(val lib: KotlinLibrary) : MainModule()
}
private class ModulesStructure(
private val project: Project,
private val files: List<KtFile>,
private val mainModule: MainModule,
val compilerConfiguration: CompilerConfiguration,
val allDependencies: KotlinLibraryResolveResult,
private val friendDependencies: List<KotlinLibrary>
@@ -299,6 +333,9 @@ private class ModulesStructure(
val builtInsDep = allDependencies.getFullList().find { it.isBuiltIns }
fun runAnalysis(): JsAnalysisResult {
require(mainModule is MainModule.SourceFiles)
val files = mainModule.files
// TODO: Should we not provide default message collector?
val messageCollector: MessageCollector =
compilerConfiguration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) ?: MessageCollector.NONE
+1
View File
@@ -4,6 +4,7 @@ where advanced options include:
-Xfriend-modules=<path> Paths to friend modules
-Xfriend-modules-disabled Disable internal declaration export
-Xgenerate-dts Generate TypeScript declarations .d.ts file alongside JS file. Available in IR backend only.
-Xinclude=<path> A path to an intermediate library that should be processed in the same manner as source files.
-Xir-dce Perform experimental dead code elimination
-Xir-only Disables pre-IR backend
-Xir-produce-js Generates JS file using IR backend. Also disables pre-IR backend
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.js.messageCollectorLogger
import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.ir.backend.js.generateKLib
import org.jetbrains.kotlin.ir.backend.js.jsPhases
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.facade.MainCallParameters
@@ -115,7 +112,7 @@ abstract class BasicIrBoxTest(
val compiledModule = compile(
project = config.project,
files = filesToCompile,
mainModule = MainModule.SourceFiles(filesToCompile),
configuration = config.configuration,
phaseConfig = phaseConfig,
allDependencies = resolvedLibraries,