JS IR: split compilation and deserialization

This commit is contained in:
Anton Bannykh
2019-03-21 15:59:10 +03:00
parent 08785b7cea
commit 0f183ed662
6 changed files with 343 additions and 312 deletions
@@ -9,15 +9,14 @@ import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.ir.Ir
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.js.JsDeclarationFactory
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager
@@ -43,12 +42,11 @@ import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.Variance
class JsIrBackendContext(
val module: ModuleDescriptorImpl,
val module: ModuleDescriptor,
override val irBuiltIns: IrBuiltIns,
val symbolTable: SymbolTable,
irModuleFragment: IrModuleFragment,
override val configuration: CompilerConfiguration,
val phaseConfig: PhaseConfig
override val configuration: CompilerConfiguration
) : CommonBackendContext {
override val builtIns = module.builtIns
@@ -83,8 +81,7 @@ class JsIrBackendContext(
}
}
override val sharedVariablesManager =
JsSharedVariablesManager(irBuiltIns, implicitDeclarationFile)
override val sharedVariablesManager = JsSharedVariablesManager(irBuiltIns, implicitDeclarationFile)
override val declarationFactory = JsDeclarationFactory()
companion object {
@@ -226,10 +223,6 @@ class JsIrBackendContext(
val newThrowableSymbol = symbolTable.referenceSimpleFunction(getJsInternalFunction("newThrowable"))
val throwISEymbol = symbolTable.referenceSimpleFunction(getFunctions(kotlinPackageFqn.child(Name.identifier("THROW_ISE"))).single())
val throwNPESymbol = ir.symbols.ThrowNullPointerException
val throwCCESymbol = ir.symbols.ThrowTypeCastException
val throwNWBESymbol = ir.symbols.ThrowNoWhenBranchMatchedException
val throwUPAESymbol = ir.symbols.ThrowUninitializedPropertyAccessException
val coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
@@ -6,173 +6,31 @@
package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsDeclarationTable
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.newJsDescriptorUniqId
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataSerializationUtil
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataVersion
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.createJsKlibMetadataPackageFragmentProvider
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.*
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.DFS
import java.io.File
import java.nio.file.Files.move
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
sealed class TranslationResult {
class CompiledJsCode(val jsCode: String) : TranslationResult()
object CompiledKlib : TranslationResult()
}
data class KlibModuleRef(
val moduleName: String,
val klibPath: String
)
enum class CompilationMode {
KLIB,
JS
}
internal val JS_KLIBRARY_CAPABILITY = ModuleDescriptor.Capability<File>("JS KLIBRARY")
internal val moduleHeaderFileName = "module.kji"
internal val declarationsDirName = "ir/"
private val logggg = object : LoggingContext {
override var inVerbosePhase: Boolean
get() = TODO("not implemented")
set(_) {}
override fun log(message: () -> String) {}
}
private fun metadataFileName(moduleName: String) = "$moduleName.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}"
private val CompilerConfiguration.metadataVersion
get() = get(CommonConfigurationKeys.METADATA_VERSION) as? JsKlibMetadataVersion ?: JsKlibMetadataVersion.INSTANCE
fun compile(
project: Project,
files: List<KtFile>,
configuration: CompilerConfiguration,
phaseConfig: PhaseConfig,
compileMode: CompilationMode,
immediateDependencies: List<KlibModuleRef>,
allDependencies: List<KlibModuleRef>,
outputKlibPath: String
): TranslationResult {
allDependencies: List<KlibModuleRef>
): String {
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
loadIr(project, files, configuration, immediateDependencies, allDependencies)
val deserializedModuleParts: Map<KlibModuleRef, JsKlibMetadataParts> =
allDependencies.associateWith { loadKlibMetadataParts(it) }
val moduleDescriptor = moduleFragment.descriptor
fun findModuleByName(name: String): KlibModuleRef =
allDependencies.find { it.moduleName == name } ?: error("Module is not found: $name")
val context = JsIrBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, configuration)
val moduleDependencies: Map<KlibModuleRef, List<KlibModuleRef>> =
deserializedModuleParts.mapValues { (_, parts) ->
parts.importedModules.map(::findModuleByName)
}
val sortedImmediateDependencies: List<KlibModuleRef> =
DFS.topologicalOrder(immediateDependencies) { moduleDependencies.getValue(it) }
.reversed()
val depsDescriptors = ModulesStructure(
LookupTracker.DO_NOTHING,
configuration.metadataVersion,
configuration.languageVersionSettings,
moduleDependencies
)
val builtInsDep = sortedImmediateDependencies.firstOrNull()
val builtInModuleDescriptor =
if (builtInsDep != null)
depsDescriptors.getModuleDescriptor(builtInsDep)
else
null // null in case compiling builtInModule itself
val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
configuration,
sortedImmediateDependencies.map { depsDescriptors.getModuleDescriptor(it) },
friendModuleDescriptors = emptyList(),
thisIsBuiltInsModule = builtInModuleDescriptor == null,
customBuiltInsModule = builtInModuleDescriptor
)
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val moduleDescriptor = analysisResult.moduleDescriptor as ModuleDescriptorImpl
val symbolTable = SymbolTable()
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(moduleDescriptor, analysisResult.bindingContext, symbolTable)
val irBuiltIns = psi2IrContext.irBuiltIns
val deserializer = JsIrLinker(moduleDescriptor, logggg, irBuiltIns, symbolTable)
val deserializedModuleFragments = sortedImmediateDependencies.map {
val moduleFile = File(it.klibPath, moduleHeaderFileName)
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
}
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files, deserializer)
if (compileMode == CompilationMode.KLIB) {
deserializedModuleFragments.forEach {
ExternalDependenciesGenerator(it.descriptor, symbolTable, irBuiltIns).generateUnboundSymbolsAsDependencies()
}
deserializedModuleFragments.forEach { it.patchDeclarationParents() }
val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME) as String
serializeModuleIntoKlib(
moduleName,
configuration.metadataVersion,
configuration.languageVersionSettings,
psi2IrContext.symbolTable,
psi2IrContext.bindingContext,
outputKlibPath,
immediateDependencies,
moduleFragment
)
return TranslationResult.CompiledKlib
}
val context = JsIrBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, configuration, phaseConfig)
deserializedModuleFragments.forEach {
// Load declarations referenced during `context` initialization
dependencyModules.forEach {
ExternalDependenciesGenerator(
it.descriptor,
symbolTable,
@@ -182,136 +40,21 @@ fun compile(
}
// TODO: check the order
val irFiles = deserializedModuleFragments.flatMap { it.files } + moduleFragment.files
val irFiles = dependencyModules.flatMap { it.files } + moduleFragment.files
moduleFragment.files.clear()
moduleFragment.files += irFiles
// TODO Why is this needed?
ExternalDependenciesGenerator(
moduleDescriptor = context.module,
symbolTable = context.symbolTable,
irBuiltIns = context.irBuiltIns
moduleDescriptor = moduleDescriptor,
symbolTable = symbolTable,
irBuiltIns = irBuiltIns
).generateUnboundSymbolsAsDependencies()
moduleFragment.patchDeclarationParents()
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
jsPhases.invokeToplevel(phaseConfig, context, moduleFragment)
val jsProgram = moduleFragment.accept(IrModuleToJsTransformer(context), null)
return TranslationResult.CompiledJsCode(jsProgram.toString())
}
private fun loadKlibMetadataParts(
moduleId: KlibModuleRef
): JsKlibMetadataParts {
val metadataFile = File(moduleId.klibPath, metadataFileName(moduleId.moduleName))
val serializer = JsKlibMetadataSerializationUtil
return serializer.readModuleAsProto(metadataFile.readBytes())
}
private fun loadKlibMetadata(
parts: JsKlibMetadataParts,
moduleId: KlibModuleRef,
isBuiltIn: Boolean,
lookupTracker: LookupTracker,
storageManager: LockBasedStorageManager,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
builtinsModule: ModuleDescriptorImpl?,
dependencies: List<ModuleDescriptorImpl>
): ModuleDescriptorImpl {
assert(isBuiltIn == (builtinsModule === null))
val builtIns = builtinsModule?.builtIns ?: object : KotlinBuiltIns(storageManager) {}
val md = ModuleDescriptorImpl(Name.special("<${moduleId.moduleName}>"), storageManager, builtIns,
capabilities = mapOf(JS_KLIBRARY_CAPABILITY to File(moduleId.klibPath)))
if (isBuiltIn) builtIns.builtInsModule = md
val currentModuleFragmentProvider = createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(languageVersionSettings),
lookupTracker
)
val packageFragmentProvider = if (isBuiltIn) {
val functionFragmentProvider = functionInterfacePackageFragmentProvider(storageManager, md)
CompositePackageFragmentProvider(listOf(functionFragmentProvider, currentModuleFragmentProvider))
} else currentModuleFragmentProvider
md.initialize(packageFragmentProvider)
md.setDependencies(listOf(md) + dependencies)
return md
}
class ModulesStructure(
private val lookupTracker: LookupTracker,
private val metadataVersion: JsKlibMetadataVersion,
private val languageVersionSettings: LanguageVersionSettings,
private val moduleDependencies: Map<KlibModuleRef, List<KlibModuleRef>>
) {
private val storageManager: LockBasedStorageManager = LockBasedStorageManager("ModulesStructure")
private var runtimeModule: ModuleDescriptorImpl? = null
private val descriptors = mutableMapOf<KlibModuleRef, ModuleDescriptorImpl>()
fun getModuleDescriptor(current: KlibModuleRef): ModuleDescriptorImpl = descriptors.getOrPut(current) {
val parts = loadKlibMetadataParts(current)
val isBuiltIns = parts.importedModules.isEmpty()
loadKlibMetadata(
parts,
current,
isBuiltIns,
lookupTracker,
storageManager,
metadataVersion,
languageVersionSettings,
runtimeModule,
moduleDependencies.getValue(current).map { getModuleDescriptor(it) }
).also {
if (isBuiltIns) runtimeModule = it
}
}
}
fun serializeModuleIntoKlib(
moduleName: String,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
symbolTable: SymbolTable,
bindingContext: BindingContext,
klibPath: String,
dependencies: List<KlibModuleRef>,
moduleFragment: IrModuleFragment
) {
val declarationTable = JsDeclarationTable(moduleFragment.irBuiltins, DescriptorTable())
val serializedIr = JsIrModuleSerializer(logggg, declarationTable).serializedIrModule(moduleFragment)
val serializer = JsKlibMetadataSerializationUtil
val moduleDescription =
JsKlibMetadataModuleDescriptor(moduleName, dependencies.map { it.moduleName }, moduleFragment.descriptor)
val serializedData = serializer.serializeMetadata(
bindingContext,
moduleDescription,
languageVersionSettings,
metadataVersion
) { declarationDescriptor ->
val index = declarationTable.descriptorTable.get(declarationDescriptor)
index?.let { newJsDescriptorUniqId(it) }
}
val klibDir = File(klibPath).also {
it.deleteRecursively()
it.mkdirs()
}
val moduleFile = File(klibDir, moduleHeaderFileName)
moduleFile.writeBytes(serializedIr.module)
val irDeclarationDir = File(klibDir, declarationsDirName).also { it.mkdir() }
val irCombinedFile = File(irDeclarationDir, "irCombined.knd")
move(Paths.get(serializedIr.combinedDeclarationFilePath), Paths.get(irCombinedFile.path), StandardCopyOption.REPLACE_EXISTING)
File(klibDir, "${moduleDescription.name}.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}").also {
it.writeBytes(serializedData.asByteArray())
}
}
return jsProgram.toString()
}
@@ -0,0 +1,298 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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 com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsDeclarationTable
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.newJsDescriptorUniqId
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataSerializationUtil
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataVersion
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.createJsKlibMetadataPackageFragmentProvider
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.*
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.DFS
import java.io.File
import java.nio.file.Files.move
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
data class KlibModuleRef(
val moduleName: String,
val klibPath: String
)
internal val JS_KLIBRARY_CAPABILITY = ModuleDescriptor.Capability<File>("JS KLIBRARY")
internal val moduleHeaderFileName = "module.kji"
internal val declarationsDirName = "ir/"
private val logggg = object : LoggingContext {
override var inVerbosePhase: Boolean
get() = TODO("not implemented")
set(_) {}
override fun log(message: () -> String) {}
}
private fun metadataFileName(moduleName: String) = "$moduleName.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}"
private val CompilerConfiguration.metadataVersion
get() = get(CommonConfigurationKeys.METADATA_VERSION) as? JsKlibMetadataVersion ?: JsKlibMetadataVersion.INSTANCE
fun generateKLib(
project: Project,
files: List<KtFile>,
configuration: CompilerConfiguration,
immediateDependencies: List<KlibModuleRef>,
allDependencies: List<KlibModuleRef>,
outputKlibPath: String
): KlibModuleRef {
val depsDescriptors = ModulesStructure(project, files, configuration, immediateDependencies, allDependencies)
val analysisResult = depsDescriptors.runAnalysis()
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext)
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files)
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
serializeModuleIntoKlib(
moduleName,
configuration.metadataVersion,
configuration.languageVersionSettings,
psi2IrContext.bindingContext,
outputKlibPath,
immediateDependencies,
moduleFragment
)
return KlibModuleRef(moduleName, outputKlibPath)
}
data class IrModuleInfo(
val module: IrModuleFragment,
val allDependencies: List<IrModuleFragment>,
val bultins: IrBuiltIns,
val symbolTable: SymbolTable,
val deserializer: JsIrLinker
)
fun loadIr(
project: Project,
files: List<KtFile>,
configuration: CompilerConfiguration,
immediateDependencies: List<KlibModuleRef>,
allDependencies: List<KlibModuleRef>
): IrModuleInfo {
val depsDescriptors = ModulesStructure(project, files, configuration, immediateDependencies, allDependencies)
val analysisResult = depsDescriptors.runAnalysis()
val moduleDescriptor = analysisResult.moduleDescriptor
val symbolTable = SymbolTable()
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(moduleDescriptor, analysisResult.bindingContext, symbolTable)
val irBuiltIns = psi2IrContext.irBuiltIns
val deserializer = JsIrLinker(moduleDescriptor, logggg, irBuiltIns, symbolTable)
val deserializedModuleFragments = depsDescriptors.sortedImmediateDependencies.map {
val moduleFile = File(it.klibPath, moduleHeaderFileName)
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
}
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files, deserializer)
return IrModuleInfo(moduleFragment, deserializedModuleFragments, irBuiltIns, symbolTable, deserializer)
}
private fun loadKlibMetadataParts(
moduleId: KlibModuleRef
): JsKlibMetadataParts {
val metadataFile = File(moduleId.klibPath, metadataFileName(moduleId.moduleName))
val serializer = JsKlibMetadataSerializationUtil
return serializer.readModuleAsProto(metadataFile.readBytes())
}
private fun loadKlibMetadata(
parts: JsKlibMetadataParts,
moduleId: KlibModuleRef,
isBuiltIn: Boolean,
lookupTracker: LookupTracker,
storageManager: LockBasedStorageManager,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
builtinsModule: ModuleDescriptorImpl?,
dependencies: List<ModuleDescriptorImpl>
): ModuleDescriptorImpl {
assert(isBuiltIn == (builtinsModule === null))
val builtIns = builtinsModule?.builtIns ?: object : KotlinBuiltIns(storageManager) {}
val md = ModuleDescriptorImpl(Name.special("<${moduleId.moduleName}>"), storageManager, builtIns,
capabilities = mapOf(JS_KLIBRARY_CAPABILITY to File(moduleId.klibPath)))
if (isBuiltIn) builtIns.builtInsModule = md
val currentModuleFragmentProvider = createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(languageVersionSettings),
lookupTracker
)
val packageFragmentProvider = if (isBuiltIn) {
val functionFragmentProvider = functionInterfacePackageFragmentProvider(storageManager, md)
CompositePackageFragmentProvider(listOf(functionFragmentProvider, currentModuleFragmentProvider))
} else currentModuleFragmentProvider
md.initialize(packageFragmentProvider)
md.setDependencies(listOf(md) + dependencies)
return md
}
class ModulesStructure(
private val project: Project,
private val files: List<KtFile>,
private val compilerConfiguration: CompilerConfiguration,
immediateDependencies: List<KlibModuleRef>,
private val allDependencies: List<KlibModuleRef>
) {
private val deserializedModuleParts: Map<KlibModuleRef, JsKlibMetadataParts> =
allDependencies.associateWith { loadKlibMetadataParts(it) }
fun findModuleByName(name: String): KlibModuleRef =
allDependencies.find { it.moduleName == name } ?: error("Module is not found: $name")
val moduleDependencies: Map<KlibModuleRef, List<KlibModuleRef>> =
deserializedModuleParts.mapValues { (_, parts) ->
parts.importedModules.map(::findModuleByName)
}
val sortedImmediateDependencies: List<KlibModuleRef> =
DFS.topologicalOrder(immediateDependencies) { moduleDependencies.getValue(it) }
.reversed()
val builtInsDep = sortedImmediateDependencies.firstOrNull()
fun runAnalysis(): JsAnalysisResult {
val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
compilerConfiguration,
sortedImmediateDependencies.map { getModuleDescriptor(it) },
friendModuleDescriptors = emptyList(),
thisIsBuiltInsModule = builtInModuleDescriptor == null,
customBuiltInsModule = builtInModuleDescriptor
)
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
return analysisResult
}
private val lookupTracker: LookupTracker = LookupTracker.DO_NOTHING
private val metadataVersion: JsKlibMetadataVersion = compilerConfiguration.metadataVersion
private val languageVersionSettings: LanguageVersionSettings = compilerConfiguration.languageVersionSettings
private val storageManager: LockBasedStorageManager = LockBasedStorageManager("ModulesStructure")
private var runtimeModule: ModuleDescriptorImpl? = null
private val descriptors = mutableMapOf<KlibModuleRef, ModuleDescriptorImpl>()
fun getModuleDescriptor(current: KlibModuleRef): ModuleDescriptorImpl = descriptors.getOrPut(current) {
val parts = loadKlibMetadataParts(current)
val isBuiltIns = parts.importedModules.isEmpty()
loadKlibMetadata(
parts,
current,
isBuiltIns,
lookupTracker,
storageManager,
metadataVersion,
languageVersionSettings,
runtimeModule,
moduleDependencies.getValue(current).map { getModuleDescriptor(it) }
).also {
if (isBuiltIns) runtimeModule = it
}
}
val builtInModuleDescriptor =
if (builtInsDep != null)
getModuleDescriptor(builtInsDep)
else
null // null in case compiling builtInModule itself
}
fun serializeModuleIntoKlib(
moduleName: String,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
bindingContext: BindingContext,
klibPath: String,
dependencies: List<KlibModuleRef>,
moduleFragment: IrModuleFragment
) {
val declarationTable = JsDeclarationTable(moduleFragment.irBuiltins, DescriptorTable())
val serializedIr = JsIrModuleSerializer(logggg, declarationTable).serializedIrModule(moduleFragment)
val serializer = JsKlibMetadataSerializationUtil
val moduleDescription =
JsKlibMetadataModuleDescriptor(moduleName, dependencies.map { it.moduleName }, moduleFragment.descriptor)
val serializedData = serializer.serializeMetadata(
bindingContext,
moduleDescription,
languageVersionSettings,
metadataVersion
) { declarationDescriptor ->
val index = declarationTable.descriptorTable.get(declarationDescriptor)
index?.let { newJsDescriptorUniqId(it) }
}
val klibDir = File(klibPath).also {
it.deleteRecursively()
it.mkdirs()
}
val moduleFile = File(klibDir, moduleHeaderFileName)
moduleFile.writeBytes(serializedIr.module)
val irDeclarationDir = File(klibDir, declarationsDirName).also { it.mkdir() }
val irCombinedFile = File(irDeclarationDir, "irCombined.knd")
move(Paths.get(serializedIr.combinedDeclarationFilePath), Paths.get(irCombinedFile.path), StandardCopyOption.REPLACE_EXISTING)
File(klibDir, "${moduleDescription.name}.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}").also {
it.writeBytes(serializedData.asByteArray())
}
}
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.library.CombinedIrFileReader
import org.jetbrains.kotlin.backend.common.library.DeclarationId
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.backend.js.JS_KLIBRARY_CAPABILITY
import org.jetbrains.kotlin.ir.backend.js.moduleHeaderFileName
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -9,14 +9,10 @@ import com.intellij.openapi.Disposable
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.ir.backend.js.CompilationMode
import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.ir.backend.js.jsPhases
import org.jetbrains.kotlin.ir.backend.js.generateKLib
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.JsIrTestRuntime
import org.jetbrains.kotlin.psi.KtFile
@@ -60,13 +56,10 @@ fun main() {
fun buildKlib(sources: List<String>, outputPath: String) {
val configuration = buildConfiguration(environment)
compile(
generateKLib(
project = environment.project,
files = sources.map(::createPsiFile),
configuration = configuration,
phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jsPhases),
compileMode = CompilationMode.KLIB,
configuration = buildConfiguration(environment),
immediateDependencies = emptyList(),
allDependencies = emptyList(),
outputKlibPath = outputPath
@@ -109,25 +109,30 @@ abstract class BasicIrBoxTest(
if (!isMainModule) it.replace("_v5.js", "/") else it
}
val result: TranslationResult = compile(
project = config.project,
files = filesToCompile,
configuration = config.configuration,
phaseConfig = config.configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jsPhases),
compileMode = if (isMainModule) CompilationMode.JS else CompilationMode.KLIB,
immediateDependencies = dependencies,
allDependencies = allDependencies,
outputKlibPath = actualOutputFile
)
if (isMainModule) {
val jsCode = compile(
project = config.project,
files = filesToCompile,
configuration = config.configuration,
phaseConfig = config.configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jsPhases),
immediateDependencies = dependencies,
allDependencies = allDependencies
)
val moduleName = config.configuration.get(CommonConfigurationKeys.MODULE_NAME) as String
val module = KlibModuleRef(moduleName, actualOutputFile)
compilationCache[outputFile.name.replace(".js", ".meta.js")] = module
if (result is TranslationResult.CompiledJsCode) {
val wrappedCode = wrapWithModuleEmulationMarkers(result.jsCode, moduleId = config.moduleId, moduleKind = config.moduleKind)
val wrappedCode = wrapWithModuleEmulationMarkers(jsCode, moduleId = config.moduleId, moduleKind = config.moduleKind)
outputFile.write(wrappedCode)
} else {
val module = generateKLib(
project = config.project,
files = filesToCompile,
configuration = config.configuration,
immediateDependencies = dependencies,
allDependencies = allDependencies,
outputKlibPath = actualOutputFile
)
compilationCache[outputFile.name.replace(".js", ".meta.js")] = module
}
}