[JS IR] Fix file name clashes during JS BE invalidation

This commit is contained in:
Alexander Korepanov
2023-10-24 11:39:08 +02:00
committed by Space Team
parent 73bf7fa506
commit ec71fe20e2
10 changed files with 123 additions and 52 deletions
@@ -273,11 +273,11 @@ class CacheUpdater(
symbolCanBeExported = true symbolCanBeExported = true
} }
if (symbolCanBeExported) { if (symbolCanBeExported) {
idSignatureToFile[signature] = IdSignatureSource(libFile, fileSymbolProvider.irFile, symbol) idSignatureToFile[signature] = IdSignatureSource(libFile, fileSymbolProvider, symbol)
} }
} }
val libSrcFile = KotlinSourceFile(fileSymbolProvider.irFile) val libSrcFile = fileSymbolProvider.srcFile
if (libSrcFile in dirtySrcFiles) { if (libSrcFile in dirtySrcFiles) {
val metadata = incrementalCache.fetchSourceFileFullMetadata(libSrcFile) val metadata = incrementalCache.fetchSourceFileFullMetadata(libSrcFile)
this[libFile, libSrcFile] = DirtyFileMetadata(maybeImportedSignatures, metadata.directDependencies) this[libFile, libSrcFile] = DirtyFileMetadata(maybeImportedSignatures, metadata.directDependencies)
@@ -296,10 +296,10 @@ class CacheUpdater(
for (importedSignature in allImportedSignatures) { for (importedSignature in allImportedSignatures) {
val dependency = idSignatureToFile[importedSignature] ?: continue val dependency = idSignatureToFile[importedSignature] ?: continue
signatureHashCalculator[importedSignature]?.also { signatureHash -> signatureHashCalculator[importedSignature]?.also { signatureHash ->
addDirectDependency(dependency.lib, dependency.src, importedSignature, signatureHash) addDirectDependency(dependency.lib, dependency.srcFile, importedSignature, signatureHash)
} ?: notFoundIcError("signature $importedSignature hash", dependency.lib, dependency.src) } ?: notFoundIcError("signature $importedSignature hash", dependency.lib, dependency.srcFile)
updatedMetadata[dependency.lib, dependency.src]?.also { dependencyMetadata -> updatedMetadata[dependency.lib, dependency.srcFile]?.also { dependencyMetadata ->
dependencyMetadata.addInverseDependency(libFile, srcFile, importedSignature) dependencyMetadata.addInverseDependency(libFile, srcFile, importedSignature)
} }
} }
@@ -328,7 +328,7 @@ class CacheUpdater(
signatures.forEach { signature -> signatures.forEach { signature ->
val signatureSrc = idSignatureToFile[signature] val signatureSrc = idSignatureToFile[signature]
val dependencyLib = signatureSrc?.lib ?: libFile val dependencyLib = signatureSrc?.lib ?: libFile
val dependencyFile = signatureSrc?.src ?: srcFile val dependencyFile = signatureSrc?.srcFile ?: srcFile
updatedMetadata[dependencyLib, dependencyFile]?.also { dependencyMetadata -> updatedMetadata[dependencyLib, dependencyFile]?.also { dependencyMetadata ->
dependencyMetadata.addInverseDependency(dependentLibFile, dependentSrcFile, signature) dependencyMetadata.addInverseDependency(dependentLibFile, dependentSrcFile, signature)
} }
@@ -590,14 +590,16 @@ class CacheUpdater(
val libFile = KotlinLibraryFile(library) val libFile = KotlinLibraryFile(library)
val incrementalCache = getLibIncrementalCache(libFile) val incrementalCache = getLibIncrementalCache(libFile)
val providers = loadedIr.getSignatureProvidersForLib(libFile) val providers = loadedIr.getSignatureProvidersForLib(libFile)
val signatureToIndexMapping = providers.associate { KotlinSourceFile(it.irFile) to it.getSignatureToIndexMapping() } val signatureToIndexMapping = providers.associate { it.srcFile to it.getSignatureToIndexMapping() }
val cacheArtifact = incrementalCache.buildAndCommitCacheArtifact(signatureToIndexMapping, stubbedSignatures) val cacheArtifact = incrementalCache.buildAndCommitCacheArtifact(signatureToIndexMapping, stubbedSignatures)
val libFragment = loadedIr.loadedFragments[libFile] ?: notFoundIcError("loaded fragment", libFile) val libFragment = loadedIr.loadedFragments[libFile] ?: notFoundIcError("loaded fragment", libFile)
val sourceNames = loadedIr.getIrFileNames(libFragment)
val sourceFilesFromCache = cacheArtifact.getSourceFiles() val sourceFilesFromCache = cacheArtifact.getSourceFiles()
for (irFile in libFragment.files) { for (irFile in libFragment.files) {
if (KotlinSourceFile(irFile) !in sourceFilesFromCache) { val srcName = sourceNames[irFile] ?: notFoundIcError("source file name", libFile, irFile)
if (srcName !in sourceFilesFromCache) {
// IC doesn't support cases when extra IrFiles (which don't exist in klib) are added into IrModuleFragment // IC doesn't support cases when extra IrFiles (which don't exist in klib) are added into IrModuleFragment
icError("file ${irFile.fileEntry.name} is absent in incremental cache and klib", libFile) icError("file ${irFile.fileEntry.name} is absent in incremental cache and klib", libFile)
} }
@@ -623,16 +625,17 @@ class CacheUpdater(
private fun compileDirtyFiles( private fun compileDirtyFiles(
compilerForIC: JsIrCompilerICInterface, compilerForIC: JsIrCompilerICInterface,
loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>, loadedIr: LoadedJsIr,
dirtyFiles: Map<KotlinLibraryFile, Set<KotlinSourceFile>> dirtyFiles: Map<KotlinLibraryFile, Set<KotlinSourceFile>>
): MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> JsIrProgramFragments>> = ): MutableList<Triple<KotlinLibraryFile, KotlinSourceFile, () -> JsIrProgramFragments>> =
stopwatch.measure("Processing IR - lowering") { stopwatch.measure("Processing IR - lowering") {
val dirtyFilesForCompiling = mutableListOf<IrFile>() val dirtyFilesForCompiling = mutableListOf<IrFile>()
val dirtyFilesForRestoring = mutableListOf<Pair<KotlinLibraryFile, KotlinSourceFile>>() val dirtyFilesForRestoring = mutableListOf<Pair<KotlinLibraryFile, KotlinSourceFile>>()
for ((libFile, libFragment) in loadedFragments) { for ((libFile, libFragment) in loadedIr.loadedFragments) {
val dirtySrcFiles = dirtyFiles[libFile] ?: continue val dirtySrcFiles = dirtyFiles[libFile] ?: continue
val sourceNames = loadedIr.getIrFileNames(libFragment)
for (irFile in libFragment.files) { for (irFile in libFragment.files) {
val srcFile = KotlinSourceFile(irFile) val srcFile = sourceNames[irFile] ?: notFoundIcError("source file name", libFile, irFile)
if (srcFile in dirtySrcFiles) { if (srcFile in dirtySrcFiles) {
dirtyFilesForCompiling += irFile dirtyFilesForCompiling += irFile
dirtyFilesForRestoring += libFile to srcFile dirtyFilesForRestoring += libFile to srcFile
@@ -640,7 +643,7 @@ class CacheUpdater(
} }
} }
val fragmentGenerators = compilerForIC.compile(loadedFragments.values, dirtyFilesForCompiling) val fragmentGenerators = compilerForIC.compile(loadedIr.loadedFragments.values, dirtyFilesForCompiling)
dirtyFilesForRestoring.mapIndexedTo(ArrayList(dirtyFilesForRestoring.size)) { i, libFileAndSrcFile -> dirtyFilesForRestoring.mapIndexedTo(ArrayList(dirtyFilesForRestoring.size)) { i, libFileAndSrcFile ->
Triple(libFileAndSrcFile.first, libFileAndSrcFile.second, fragmentGenerators[i]) Triple(libFileAndSrcFile.first, libFileAndSrcFile.second, fragmentGenerators[i])
@@ -649,7 +652,7 @@ class CacheUpdater(
private data class IrForDirtyFilesAndCompiler( private data class IrForDirtyFilesAndCompiler(
val incrementalCacheArtifacts: Map<KotlinLibraryFile, IncrementalCacheArtifact>, val incrementalCacheArtifacts: Map<KotlinLibraryFile, IncrementalCacheArtifact>,
val loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>, val loadedIr: LoadedJsIr,
val dirtyFiles: Map<KotlinLibraryFile, Set<KotlinSourceFile>>, val dirtyFiles: Map<KotlinLibraryFile, Set<KotlinSourceFile>>,
val irCompiler: JsIrCompilerICInterface val irCompiler: JsIrCompilerICInterface
) )
@@ -726,7 +729,7 @@ class CacheUpdater(
val incrementalCachesArtifacts = updater.buildAndCommitCacheArtifacts(loadedIr) val incrementalCachesArtifacts = updater.buildAndCommitCacheArtifacts(loadedIr)
stopwatch.stop() stopwatch.stop()
return IrForDirtyFilesAndCompiler(incrementalCachesArtifacts, loadedIr.loadedFragments, dirtyFiles, compilerForIC) return IrForDirtyFilesAndCompiler(incrementalCachesArtifacts, loadedIr, dirtyFiles, compilerForIC)
} }
private data class FragmentGenerators( private data class FragmentGenerators(
@@ -736,11 +739,11 @@ class CacheUpdater(
) )
private fun loadIrAndMakeIrFragmentGenerators(): FragmentGenerators { private fun loadIrAndMakeIrFragmentGenerators(): FragmentGenerators {
val (incrementalCachesArtifacts, irFragments, dirtyFiles, irCompiler) = loadIrForDirtyFilesAndInitCompiler() val (incrementalCachesArtifacts, loadedIr, dirtyFiles, irCompiler) = loadIrForDirtyFilesAndInitCompiler()
val moduleNames = irFragments.entries.associate { it.key to it.value.name.asString() } val moduleNames = loadedIr.loadedFragments.entries.associate { it.key to it.value.name.asString() }
val rebuiltFragmentGenerators = compileDirtyFiles(irCompiler, irFragments, dirtyFiles) val rebuiltFragmentGenerators = compileDirtyFiles(irCompiler, loadedIr, dirtyFiles)
return FragmentGenerators(incrementalCachesArtifacts, moduleNames, rebuiltFragmentGenerators) return FragmentGenerators(incrementalCachesArtifacts, moduleNames, rebuiltFragmentGenerators)
} }
@@ -784,7 +787,9 @@ fun rebuildCacheForDirtyFiles(
} }
val libFile = KotlinLibraryFile(library) val libFile = KotlinLibraryFile(library)
val dirtySrcFiles = dirtyFiles?.memoryOptimizedMap { KotlinSourceFile(it) } ?: KotlinLoadedLibraryHeader(library, internationService).sourceFileFingerprints.keys val dirtySrcFiles = dirtyFiles?.let {
KotlinSourceFile.fromSources(it.toList())
} ?: KotlinLoadedLibraryHeader(library, internationService).sourceFileFingerprints.keys
val modifiedFiles = mapOf(libFile to dirtySrcFiles.associateWith { emptyMetadata }) val modifiedFiles = mapOf(libFile to dirtySrcFiles.associateWith { emptyMetadata })
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js.ic package org.jetbrains.kotlin.ir.backend.js.ic
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.protobuf.CodedInputStream import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.CodedOutputStream import org.jetbrains.kotlin.protobuf.CodedOutputStream
@@ -43,8 +44,8 @@ internal inline fun <T> CodedInputStream.ifTrue(then: () -> T): T? {
return if (readBool()) then() else null return if (readBool()) then() else null
} }
internal fun icError(what: String, libFile: KotlinLibraryFile? = null, srcFile: KotlinSourceFile? = null): Nothing { internal fun icError(what: String, libFile: KotlinLibraryFile? = null, srcFile: KotlinSourceFile? = null, irFile: IrFile? = null): Nothing {
val filePath = listOfNotNull(libFile?.path, srcFile?.path).joinToString(":") { File(it).name } val filePath = listOfNotNull(libFile?.path, (srcFile?.path ?: irFile?.fileEntry?.name)).joinToString(":") { File(it).name }
val msg = if (filePath.isEmpty()) what else "$what for $filePath" val msg = if (filePath.isEmpty()) what else "$what for $filePath"
error("IC internal error: $msg") error("IC internal error: $msg")
} }
@@ -53,6 +54,10 @@ internal fun notFoundIcError(what: String, libFile: KotlinLibraryFile? = null, s
icError("can not find $what", libFile, srcFile) icError("can not find $what", libFile, srcFile)
} }
internal fun notFoundIcError(what: String, libFile: KotlinLibraryFile, irFile: IrFile): Nothing {
icError("can not find $what", libFile, irFile = irFile)
}
internal inline fun <E> buildSetUntil(to: Int, builderAction: MutableSet<E>.(Int) -> Unit): Set<E> { internal inline fun <E> buildSetUntil(to: Int, builderAction: MutableSet<E>.(Int) -> Unit): Set<E> {
return newHashSetWithExpectedSize<E>(to).apply { repeat(to) { builderAction(it) } } return newHashSetWithExpectedSize<E>(to).apply { repeat(to) { builderAction(it) } }
} }
@@ -88,7 +88,7 @@ internal class IdSignatureHashCalculator(private val icHasher: ICHasher) {
} }
private fun IrSymbol.calculateSymbolHash(): ICHash { private fun IrSymbol.calculateSymbolHash(): ICHash {
var srcIrFile = signature?.let { sig -> idSignatureSources[sig]?.srcIrFile } var srcIrFile = signature?.let { sig -> idSignatureSources[sig]?.irFile }
if (srcIrFile == null) { if (srcIrFile == null) {
var parentDeclaration = (owner as? IrDeclaration)?.parent var parentDeclaration = (owner as? IrDeclaration)?.parent
while (parentDeclaration is IrDeclaration) { while (parentDeclaration is IrDeclaration) {
@@ -14,11 +14,14 @@ import org.jetbrains.kotlin.ir.util.resolveFakeOverride
internal class IdSignatureSource( internal class IdSignatureSource(
val lib: KotlinLibraryFile, val lib: KotlinLibraryFile,
val srcIrFile: IrFile, private val fileSignatureProvider: FileSignatureProvider,
val symbol: IrSymbol val symbol: IrSymbol
) { ) {
val src: KotlinSourceFile val irFile: IrFile
get() = KotlinSourceFile(srcIrFile) get() = fileSignatureProvider.irFile
val srcFile: KotlinSourceFile
get() = fileSignatureProvider.srcFile
} }
internal fun addParentSignatures( internal fun addParentSignatures(
@@ -31,7 +34,7 @@ internal fun addParentSignatures(
fun addAllParents(sig: IdSignature) { fun addAllParents(sig: IdSignature) {
val signatureSrc = idSignatureToFile[sig] ?: return val signatureSrc = idSignatureToFile[sig] ?: return
if (signatureSrc.lib == importerLibFile && signatureSrc.src == importerSrcFile) { if (signatureSrc.lib == importerLibFile && signatureSrc.srcFile == importerSrcFile) {
return return
} }
if (allSignatures.add(sig)) { if (allSignatures.add(sig)) {
@@ -100,12 +103,12 @@ private fun collectImplementedSymbol(deserializedSymbols: Map<IdSignature, IrSym
} }
} }
internal sealed class FileSignatureProvider(val irFile: IrFile) { internal sealed class FileSignatureProvider(val irFile: IrFile, val srcFile: KotlinSourceFile) {
abstract fun getSignatureToIndexMapping(): Map<IdSignature, Int> abstract fun getSignatureToIndexMapping(): Map<IdSignature, Int>
abstract fun getReachableSignatures(): Set<IdSignature> abstract fun getReachableSignatures(): Set<IdSignature>
abstract fun getImplementedSymbols(): Map<IdSignature, IrSymbol> abstract fun getImplementedSymbols(): Map<IdSignature, IrSymbol>
class DeserializedFromKlib(private val fileDeserializer: IrFileDeserializer) : FileSignatureProvider(fileDeserializer.file) { class DeserializedFromKlib(private val fileDeserializer: IrFileDeserializer, srcFile: KotlinSourceFile) : FileSignatureProvider(fileDeserializer.file, srcFile) {
override fun getSignatureToIndexMapping(): Map<IdSignature, Int> { override fun getSignatureToIndexMapping(): Map<IdSignature, Int> {
return fileDeserializer.symbolDeserializer.signatureDeserializer.signatureToIndexMapping() return fileDeserializer.symbolDeserializer.signatureDeserializer.signatureToIndexMapping()
} }
@@ -127,7 +130,7 @@ internal sealed class FileSignatureProvider(val irFile: IrFile) {
} }
} }
class GeneratedFunctionTypeInterface(file: IrFile) : FileSignatureProvider(file) { class GeneratedFunctionTypeInterface(file: IrFile, srcFile: KotlinSourceFile) : FileSignatureProvider(file, srcFile) {
private val allSignatures = run { private val allSignatures = run {
val topLevelSymbols = buildMap { val topLevelSymbols = buildMap {
for (declaration in irFile.declarations) { for (declaration in irFile.declarations) {
@@ -86,7 +86,7 @@ internal class IncrementalCache(private val library: KotlinLibraryHeader, val ca
private fun KotlinSourceFile.getCacheFile(suffix: String): File { private fun KotlinSourceFile.getCacheFile(suffix: String): File {
val pathHash = path.cityHash64String() val pathHash = path.cityHash64String()
return File(cacheDir, "${File(path).name}.$pathHash.$suffix") return File(cacheDir, "${File(path).name}.$id.$pathHash.$suffix")
} }
fun buildAndCommitCacheArtifact( fun buildAndCommitCacheArtifact(
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsFactories
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
import org.jetbrains.kotlin.ir.declarations.IrFactory import org.jetbrains.kotlin.ir.declarations.IrFactory
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrDescriptorBasedFunctionFactory import org.jetbrains.kotlin.ir.descriptors.IrDescriptorBasedFunctionFactory
import org.jetbrains.kotlin.ir.linkage.partial.partialLinkageConfig import org.jetbrains.kotlin.ir.linkage.partial.partialLinkageConfig
@@ -42,21 +43,25 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager
internal data class LoadedJsIr( internal data class LoadedJsIr(
val loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>, val loadedFragments: Map<KotlinLibraryFile, IrModuleFragment>,
private val linker: JsIrLinker, private val linker: JsIrLinker,
private val functionTypeInterfacePackages: FunctionTypeInterfacePackages private val functionTypeInterfacePackages: FunctionTypeInterfacePackages,
) { ) {
private val signatureProvidersImpl = hashMapOf<KotlinLibraryFile, List<FileSignatureProvider>>() private val signatureProvidersImpl = hashMapOf<KotlinLibraryFile, List<FileSignatureProvider>>()
private fun collectSignatureProviders(irModule: IrModuleFragment): List<FileSignatureProvider> { private val irFileSourceNames = hashMapOf<IrModuleFragment, Map<IrFile, KotlinSourceFile>>()
private fun collectSignatureProviders(lib: KotlinLibraryFile, irModule: IrModuleFragment): List<FileSignatureProvider> {
val moduleDeserializer = linker.moduleDeserializer(irModule.descriptor) val moduleDeserializer = linker.moduleDeserializer(irModule.descriptor)
val deserializers = moduleDeserializer.fileDeserializers() val deserializers = moduleDeserializer.fileDeserializers()
val providers = ArrayList<FileSignatureProvider>(deserializers.size) val providers = ArrayList<FileSignatureProvider>(deserializers.size)
val sourceFiles = getIrFileNames(irModule)
for (fileDeserializer in deserializers) { for (fileDeserializer in deserializers) {
val irFile = fileDeserializer.file val irFile = fileDeserializer.file
val sourceFile = sourceFiles[irFile] ?: notFoundIcError("source file name", lib, irFile)
if (functionTypeInterfacePackages.isFunctionTypeInterfacePackageFile(irFile)) { if (functionTypeInterfacePackages.isFunctionTypeInterfacePackageFile(irFile)) {
providers += FileSignatureProvider.GeneratedFunctionTypeInterface(irFile) providers += FileSignatureProvider.GeneratedFunctionTypeInterface(irFile, sourceFile)
} else { } else {
providers += FileSignatureProvider.DeserializedFromKlib(fileDeserializer) providers += FileSignatureProvider.DeserializedFromKlib(fileDeserializer, sourceFile)
} }
} }
@@ -66,7 +71,7 @@ internal data class LoadedJsIr(
fun getSignatureProvidersForLib(lib: KotlinLibraryFile): List<FileSignatureProvider> { fun getSignatureProvidersForLib(lib: KotlinLibraryFile): List<FileSignatureProvider> {
return signatureProvidersImpl.getOrPut(lib) { return signatureProvidersImpl.getOrPut(lib) {
val irFragment = loadedFragments[lib] ?: notFoundIcError("loaded fragment", lib) val irFragment = loadedFragments[lib] ?: notFoundIcError("loaded fragment", lib)
collectSignatureProviders(irFragment) collectSignatureProviders(lib, irFragment)
} }
} }
@@ -81,6 +86,17 @@ internal data class LoadedJsIr(
fun collectSymbolsReplacedWithStubs(): Set<IrSymbol> { fun collectSymbolsReplacedWithStubs(): Set<IrSymbol> {
return linker.partialLinkageSupport.collectAllStubbedSymbols() return linker.partialLinkageSupport.collectAllStubbedSymbols()
} }
fun getIrFileNames(fragment: IrModuleFragment): Map<IrFile, KotlinSourceFile> {
return irFileSourceNames.getOrPut(fragment) {
val files = linker.getDeserializedFilesInKlibOrder(fragment)
val names = files.map { it.fileEntry.name }
val sourceFiles = KotlinSourceFile.fromSources(names)
files.indices.associate {
files[it] to sourceFiles[it]
}
}
}
} }
internal class JsIrLinkerLoader( internal class JsIrLinkerLoader(
@@ -88,7 +104,7 @@ internal class JsIrLinkerLoader(
private val dependencyGraph: Map<KotlinLibrary, List<KotlinLibrary>>, private val dependencyGraph: Map<KotlinLibrary, List<KotlinLibrary>>,
private val mainModuleFriends: Collection<KotlinLibrary>, private val mainModuleFriends: Collection<KotlinLibrary>,
private val irFactory: IrFactory, private val irFactory: IrFactory,
private val stubbedSignatures: Set<IdSignature> private val stubbedSignatures: Set<IdSignature>,
) { ) {
private val mainLibrary = dependencyGraph.keys.lastOrNull() ?: notFoundIcError("main library") private val mainLibrary = dependencyGraph.keys.lastOrNull() ?: notFoundIcError("main library")
@@ -97,7 +113,7 @@ internal class JsIrLinkerLoader(
val symbolTable: SymbolTable, val symbolTable: SymbolTable,
val typeTranslator: TypeTranslatorImpl, val typeTranslator: TypeTranslatorImpl,
val irBuiltIns: IrBuiltInsOverDescriptors, val irBuiltIns: IrBuiltInsOverDescriptors,
val linker: JsIrLinker val linker: JsIrLinker,
) { ) {
val functionTypeInterfacePackages = FunctionTypeInterfacePackages() val functionTypeInterfacePackages = FunctionTypeInterfacePackages()
@@ -183,9 +199,9 @@ internal class JsIrLinkerLoader(
module == mainLibrary -> DeserializationStrategy.ALL module == mainLibrary -> DeserializationStrategy.ALL
else -> DeserializationStrategy.EXPLICITLY_EXPORTED else -> DeserializationStrategy.EXPLICITLY_EXPORTED
} }
val modified = modifiedFiles[libraryFile] ?: emptyMap() val modified = modifiedFiles[libraryFile]?.keys?.mapTo(hashSetOf()) { it.path } ?: emptySet()
libraryFile to linkerContext.linker.deserializeIrModuleHeader(descriptor, module, { libraryFile to linkerContext.linker.deserializeIrModuleHeader(descriptor, module, {
when (KotlinSourceFile(it)) { when (it) {
in modified -> modifiedStrategy in modified -> modifiedStrategy
else -> DeserializationStrategy.WITH_INLINE_BODIES else -> DeserializationStrategy.WITH_INLINE_BODIES
} }
@@ -66,10 +66,11 @@ internal class KotlinLoadedLibraryHeader(
private val sourceFiles by lazy(LazyThreadSafetyMode.NONE) { private val sourceFiles by lazy(LazyThreadSafetyMode.NONE) {
val extReg = ExtensionRegistryLite.newInstance() val extReg = ExtensionRegistryLite.newInstance()
Array(library.fileCount()) { val sources = (0 until library.fileCount()).map {
val fileProto = IrFile.parseFrom(library.file(it).codedInputStream, extReg) val fileProto = IrFile.parseFrom(library.file(it).codedInputStream, extReg)
KotlinSourceFile(fileProto.fileEntry.name) fileProto.fileEntry.name
} }
KotlinSourceFile.fromSources(sources)
} }
} }
@@ -26,18 +26,45 @@ value class KotlinLibraryFile(val path: String) {
override fun toString(): String = File(path).name override fun toString(): String = File(path).name
} }
@JvmInline class KotlinSourceFile private constructor(val path: String, val id: Int) {
value class KotlinSourceFile(val path: String) { fun toProtoStream(out: CodedOutputStream) {
constructor(irFile: IrFile) : this(irFile.fileEntry.name) out.writeStringNoTag(path)
out.writeInt32NoTag(id)
}
fun toProtoStream(out: CodedOutputStream) = out.writeStringNoTag(path) override fun hashCode(): Int {
return path.hashCode() xor id
}
companion object { override fun equals(other: Any?): Boolean {
fun fromProtoStream(input: CodedInputStream) = KotlinSourceFile(input.readString()) return other is KotlinSourceFile && other.path == path && other.id == id
} }
// for debugging purposes only // for debugging purposes only
override fun toString(): String = File(path).name override fun toString(): String = "${File(path).name}${if (id != 0) ".$id" else ""}"
companion object {
fun fromProtoStream(input: CodedInputStream): KotlinSourceFile {
val path = input.readString()
val fileIndex = input.readInt32()
return KotlinSourceFile(path, fileIndex)
}
/**
* Source file paths in one module may clash;
* for example, common and platform parts of the module could have files with the same root paths.
* @param sources is a list of the module sources and must be in the same order as they appear in the klib.
* @return a list of [KotlinSourceFile] containing the file path and the unique id in case of a clash
*/
fun fromSources(sources: List<String>): List<KotlinSourceFile> {
val counters = hashMapOf<String, Int>()
return sources.map { fileName ->
val id = counters[fileName] ?: 0
counters[fileName] = id + 1
KotlinSourceFile(fileName, id)
}
}
}
} }
open class KotlinSourceFileMap<out T>(files: Map<KotlinLibraryFile, Map<KotlinSourceFile, T>>) : open class KotlinSourceFileMap<out T>(files: Map<KotlinLibraryFile, Map<KotlinSourceFile, T>>) :
@@ -54,7 +81,7 @@ open class KotlinSourceFileMap<out T>(files: Map<KotlinLibraryFile, Map<KotlinSo
@Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") // K2 warning suppression, TODO: KT-62472 @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") // K2 warning suppression, TODO: KT-62472
class KotlinSourceFileMutableMap<T>( class KotlinSourceFileMutableMap<T>(
private val files: MutableMap<KotlinLibraryFile, MutableMap<KotlinSourceFile, T>> = hashMapOf() private val files: MutableMap<KotlinLibraryFile, MutableMap<KotlinSourceFile, T>> = hashMapOf(),
) : KotlinSourceFileMap<T>(files) { ) : KotlinSourceFileMap<T>(files) {
operator fun set(libFile: KotlinLibraryFile, sourceFile: KotlinSourceFile, data: T) = getOrPutFiles(libFile).put(sourceFile, data) operator fun set(libFile: KotlinLibraryFile, sourceFile: KotlinSourceFile, data: T) = getOrPutFiles(libFile).put(sourceFile, data)
@@ -126,7 +153,7 @@ internal class DirtyFileExports : KotlinSourceFileExports() {
internal class DirtyFileMetadata( internal class DirtyFileMetadata(
val maybeImportedSignatures: Collection<IdSignature>, val maybeImportedSignatures: Collection<IdSignature>,
val oldDirectDependencies: KotlinSourceFileMap<*> val oldDirectDependencies: KotlinSourceFileMap<*>,
) : KotlinSourceFileMetadata() { ) : KotlinSourceFileMetadata() {
override val inverseDependencies: KotlinSourceFileMutableMap<MutableSet<IdSignature>> = KotlinSourceFileMutableMap() override val inverseDependencies: KotlinSourceFileMutableMap<MutableSet<IdSignature>> = KotlinSourceFileMutableMap()
override val directDependencies: KotlinSourceFileMutableMap<MutableMap<IdSignature, ICHash>> = KotlinSourceFileMutableMap() override val directDependencies: KotlinSourceFileMutableMap<MutableMap<IdSignature, ICHash>> = KotlinSourceFileMutableMap()
@@ -161,7 +188,7 @@ internal class UpdatedDependenciesMetadata(oldMetadata: KotlinSourceFileMetadata
} }
internal fun KotlinSourceFileMutableMap<UpdatedDependenciesMetadata>.addNewMetadata( internal fun KotlinSourceFileMutableMap<UpdatedDependenciesMetadata>.addNewMetadata(
libFile: KotlinLibraryFile, srcFile: KotlinSourceFile, oldMetadata: KotlinSourceFileMetadata libFile: KotlinLibraryFile, srcFile: KotlinSourceFile, oldMetadata: KotlinSourceFileMetadata,
) = this[libFile, srcFile] ?: UpdatedDependenciesMetadata(oldMetadata).also { ) = this[libFile, srcFile] ?: UpdatedDependenciesMetadata(oldMetadata).also {
this[libFile, srcFile] = it this[libFile, srcFile] = it
} }
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.containsErrorCode import org.jetbrains.kotlin.library.containsErrorCode
import org.jetbrains.kotlin.utils.memoryOptimizedMap
class JsIrLinker( class JsIrLinker(
private val currentModule: ModuleDescriptor?, messageLogger: IrMessageLogger, builtIns: IrBuiltIns, symbolTable: SymbolTable, private val currentModule: ModuleDescriptor?, messageLogger: IrMessageLogger, builtIns: IrBuiltIns, symbolTable: SymbolTable,
@@ -67,8 +69,16 @@ class JsIrLinker(
} }
} }
private val deserializedFilesInKlibOrder = mutableMapOf<IrModuleFragment, List<IrFile>>()
private inner class JsModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary, strategyResolver: (String) -> DeserializationStrategy, libraryAbiVersion: KotlinAbiVersion, allowErrorCode: Boolean) : private inner class JsModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary, strategyResolver: (String) -> DeserializationStrategy, libraryAbiVersion: KotlinAbiVersion, allowErrorCode: Boolean) :
BasicIrModuleDeserializer(this, moduleDescriptor, klib, strategyResolver, libraryAbiVersion, allowErrorCode, false) BasicIrModuleDeserializer(this, moduleDescriptor, klib, strategyResolver, libraryAbiVersion, allowErrorCode, true) {
override fun init(delegate: IrModuleDeserializer) {
super.init(delegate)
deserializedFilesInKlibOrder[moduleFragment] = fileDeserializationStates.memoryOptimizedMap { it.file }
}
}
override fun createCurrentModuleDeserializer(moduleFragment: IrModuleFragment, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer { override fun createCurrentModuleDeserializer(moduleFragment: IrModuleFragment, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer {
val currentModuleDeserializer = super.createCurrentModuleDeserializer(moduleFragment, dependencies) val currentModuleDeserializer = super.createCurrentModuleDeserializer(moduleFragment, dependencies)
@@ -91,6 +101,10 @@ class JsIrLinker(
return deserializersForModules[moduleDescriptor.name.asString()] ?: error("Deserializer for $moduleDescriptor not found") return deserializersForModules[moduleDescriptor.name.asString()] ?: error("Deserializer for $moduleDescriptor not found")
} }
fun getDeserializedFilesInKlibOrder(fragment: IrModuleFragment): List<IrFile> {
return deserializedFilesInKlibOrder[fragment] ?: emptyList()
}
class JsFePluginContext( class JsFePluginContext(
override val moduleDescriptor: ModuleDescriptor, override val moduleDescriptor: ModuleDescriptor,
override val symbolTable: ReferenceSymbolTable, override val symbolTable: ReferenceSymbolTable,
@@ -242,7 +242,7 @@ abstract class AbstractInvalidationTest(
for ((srcFile, dirtyStats) in updateStatus) { for ((srcFile, dirtyStats) in updateStatus) {
for (dirtyStat in dirtyStats) { for (dirtyStat in dirtyStats) {
if (dirtyStat != DirtyFileState.NON_MODIFIED_IR) { if (dirtyStat != DirtyFileState.NON_MODIFIED_IR) {
got.getOrPut(dirtyStat.str) { mutableSetOf() }.add(File(srcFile.path).name) got.getOrPut(dirtyStat.str) { mutableSetOf() }.add(srcFile.toString())
} }
} }
} }