[IC] Refactor IC maps to reuse code and ensure consistency - Part 2

In commit 4e89dcf, we have prepared the API for IC maps in top
interfaces and provide the implementation in abstract classes.

In this commit, we refactor IC maps so that they directly inherit/reuse
the implementation from the superclasses without having to reimplement
the APIs for a map.

Test: Existing tests (refactoring change)
^KT-63456: In progress

Authored-by: Hung Nguyen <hungnv@google.com>

Merge-request: KOTLIN-MR-801
Merged-by: Evgenii Mazhukin <evgenii.mazhukin@jetbrains.com>
This commit is contained in:
Hung Nguyen
2023-11-15 12:22:40 +00:00
committed by Space Cloud
parent c0a05e435c
commit 5562c95155
27 changed files with 473 additions and 578 deletions
@@ -50,20 +50,13 @@ abstract class IncrementalCachesManager<PlatformCache : AbstractIncrementalCache
val closer = Closer.create()
caches.forEach {
closer.register(CacheCloser(it))
closer.register(it)
}
closer.close()
isClosed = true
}
private class CacheCloser(private val cache: BasicMapsOwner) : Closeable {
override fun close() {
cache.close()
}
}
}
open class IncrementalJvmCachesManager(
@@ -38,8 +38,8 @@ import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
import org.jetbrains.kotlin.incremental.storage.BasicFileToPathConverter
import org.jetbrains.kotlin.incremental.storage.FileLocations
import org.jetbrains.kotlin.incremental.storage.FileToAbsolutePathConverter
import org.jetbrains.kotlin.incremental.util.BufferingMessageCollector
import org.jetbrains.kotlin.incremental.util.ExceptionLocation
import org.jetbrains.kotlin.incremental.util.reportException
@@ -90,8 +90,8 @@ abstract class IncrementalCompilerRunner<
fileLocations: FileLocations?,
transaction: CompilationTransaction,
) = IncrementalCompilationContext(
pathConverterForSourceFiles = fileLocations?.let { it.getRelocatablePathConverterForSourceFiles() } ?: FileToAbsolutePathConverter,
pathConverterForOutputFiles = fileLocations?.let { it.getRelocatablePathConverterForOutputFiles() } ?: FileToAbsolutePathConverter,
pathConverterForSourceFiles = fileLocations?.let { it.getRelocatablePathConverterForSourceFiles() } ?: BasicFileToPathConverter,
pathConverterForOutputFiles = fileLocations?.let { it.getRelocatablePathConverterForOutputFiles() } ?: BasicFileToPathConverter,
transaction = transaction,
reporter = reporter,
trackChangesInLookupCache = shouldTrackChangesInLookupCache,
@@ -52,7 +52,7 @@ class InputsCache(
// generatedFiles can contain multiple entries with the same source file
// for example Kapt3 IC will generate a .java stub and .class stub for each source file
fun registerOutputForSourceFiles(generatedFiles: List<GeneratedFile>) {
val sourceToOutput = MultiMap<File, File>()
val sourceToOutput = MultiMap.createLinked<File, File>()
for (generatedFile in generatedFiles) {
for (source in generatedFile.sourceFiles) {
@@ -61,7 +61,7 @@ class InputsCache(
}
for ((source, outputs) in sourceToOutput.entrySet()) {
sourceToOutputMap[source] = outputs
sourceToOutputMap[source] = outputs.toSet()
}
}
}
@@ -18,41 +18,39 @@ package org.jetbrains.kotlin.incremental.snapshots
import org.jetbrains.kotlin.incremental.ChangedFiles
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
import org.jetbrains.kotlin.incremental.storage.BasicStringMap
import org.jetbrains.kotlin.incremental.storage.PathStringDescriptor
import org.jetbrains.kotlin.incremental.storage.AbstractBasicMap
import java.io.File
import java.util.*
class FileSnapshotMap(
storageFile: File,
icContext: IncrementalCompilationContext,
) : BasicStringMap<FileSnapshot>(storageFile, PathStringDescriptor, FileSnapshotExternalizer, icContext) {
override fun dumpValue(value: FileSnapshot): String =
value.toString()
) : AbstractBasicMap<File, FileSnapshot>(
storageFile,
icContext.fileDescriptorForSourceFiles,
FileSnapshotExternalizer,
icContext
) {
@Synchronized
fun compareAndUpdate(newFiles: Iterable<File>): ChangedFiles.Known {
val snapshotProvider = SimpleFileSnapshotProviderImpl()
val newOrModified = ArrayList<File>()
val removed = ArrayList<File>()
val newPaths = newFiles.mapTo(HashSet(), transform = pathConverter::toPath)
for (oldPath in storage.keys) {
if (oldPath !in newPaths) {
storage.remove(oldPath)
removed.add(pathConverter.toFile(oldPath))
val newFilesSet = newFiles.toSet()
for (oldFile in keys) {
if (oldFile !in newFilesSet) {
remove(oldFile)
removed.add(oldFile)
}
}
for (path in newPaths) {
val file = pathConverter.toFile(path)
val oldSnapshot = storage[path]
for (file in newFilesSet) {
val oldSnapshot = this[file]
val newSnapshot = snapshotProvider[file]
if (oldSnapshot == null || oldSnapshot != newSnapshot) {
newOrModified.add(file)
storage[path] = newSnapshot
this[file] = newSnapshot
}
}
@@ -6,24 +6,21 @@
package org.jetbrains.kotlin.incremental.storage
import org.jetbrains.kotlin.incremental.IncrementalCompilationContext
import org.jetbrains.kotlin.incremental.dumpCollection
import java.io.File
class SourceToOutputFilesMap(
storageFile: File,
icContext: IncrementalCompilationContext,
) : BasicStringMap<Collection<String>>(storageFile, PathStringDescriptor, StringCollectionExternalizer, icContext) {
operator fun set(sourceFile: File, outputFiles: Collection<File>) {
storage[icContext.pathConverterForSourceFiles.toPath(sourceFile)] =
outputFiles.toSet().map(icContext.pathConverterForOutputFiles::toPath)
) : AppendableSetBasicMap<File, File>(
storageFile,
icContext.fileDescriptorForSourceFiles,
icContext.fileDescriptorForOutputFiles,
icContext
) {
@Synchronized
fun getAndRemove(sourceFile: File): Set<File>? {
return get(sourceFile).also {
remove(sourceFile)
}
}
operator fun get(sourceFile: File): Collection<File>? =
storage[icContext.pathConverterForSourceFiles.toPath(sourceFile)]?.map(icContext.pathConverterForOutputFiles::toFile)
override fun dumpValue(value: Collection<String>) =
value.dumpCollection()
fun getAndRemove(file: File): Collection<File>? =
get(file).also { storage.remove(icContext.pathConverterForSourceFiles.toPath(file)) }
}
}
@@ -60,49 +60,53 @@ class SourceToOutputFilesMapTest {
@Test
fun testSetOneGetReturnsOne() {
stofMap[fooDotKt] = listOf(fooDotClass)
stofMap[fooDotKt] = setOf(fooDotClass)
assertEquals(listOf(fooDotClass), stofMap[fooDotKt])
assertEquals(setOf(fooDotClass), stofMap[fooDotKt])
}
@Test
fun testSetDupeGetReturnsUnique() {
stofMap[fooDotKt] = listOf(fooDotClass, fooDotClass)
stofMap.append(fooDotKt, fooDotClass)
stofMap.append(fooDotKt, fooDotClass)
assertEquals(listOf(fooDotClass), stofMap[fooDotKt])
assertEquals(setOf(fooDotClass), stofMap[fooDotKt])
}
@Test
fun testSetOverwriteGetReturnsNew() {
val fooKtDotClass = classesDir.resolve("FooKt.class")
stofMap[fooDotKt] = listOf(fooDotClass)
stofMap[fooDotKt] = listOf(fooKtDotClass)
stofMap[fooDotKt] = setOf(fooDotClass)
stofMap[fooDotKt] = setOf(fooKtDotClass)
assertEquals(listOf(fooKtDotClass), stofMap[fooDotKt])
assertEquals(setOf(fooKtDotClass), stofMap[fooDotKt])
}
@Test
fun testSetRelativeFails() {
assertFailsWith<IllegalArgumentException> {
stofMap[fooDotKt] = listOf(File("relativePath"))
fun testSetRelativePathFails() {
assertFailsWith<IllegalStateException> {
stofMap[fooDotKt] = setOf(File("relativePath"))
}
assertFailsWith<IllegalStateException> {
stofMap[File("relativePath")] = setOf(fooDotClass)
}
}
@Test
fun testGetRelativeFails() {
stofMap[fooDotKt] = listOf(fooDotClass)
fun testGetRelativePathFails() {
stofMap[fooDotKt] = setOf(fooDotClass)
assertFailsWith<IllegalArgumentException> {
stofMap[fooDotKt.relativeTo(srcDir)]
assertFailsWith<IllegalStateException> {
stofMap[File("relativePath")]
}
}
@Test
fun testGetAndRemove() {
stofMap[fooDotKt] = listOf(fooDotClass)
stofMap[fooDotKt] = setOf(fooDotClass)
assertEquals(listOf(fooDotClass), stofMap.getAndRemove(fooDotKt))
assertEquals(setOf(fooDotClass), stofMap.getAndRemove(fooDotKt))
assertNull(stofMap[fooDotKt])
}
}
}