Recompile only files that call changed inline functions

Original commit: e0419f956e
This commit is contained in:
Alexey Tsvetkov
2015-07-24 23:37:34 +03:00
parent 6a7f1bc7fe
commit eb10544231
2 changed files with 126 additions and 24 deletions
@@ -212,21 +212,16 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
}
if (IncrementalCompilation.ENABLED) {
val inlines = THashSet(FileUtil.PATH_HASHING_STRATEGY)
val caches = filesToCompile.keySet().map { incrementalCaches[it]!! }
for ((target, files) in filesToCompile.entrySet()) {
val cacheImpl = incrementalCaches[target]
files.forEach {
cacheImpl?.getInlineDependencies(it)?.let {
inlines.addAll(it)
}
for (cache in caches) {
val filesToReinline = cache.getFilesToReinline()
filesToReinline.forEach {
FSOperations.markDirty(context, CompilationRound.NEXT, it)
}
}
inlines.forEach {
FSOperations.markDirty(context, CompilationRound.NEXT, File(it))
}
when (recompilationDecision) {
RECOMPILE_ALL_IN_CHUNK_AND_DEPENDANTS -> {
allCompiledFiles.clear()
@@ -18,13 +18,13 @@ package org.jetbrains.kotlin.jps.incremental
import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.io.*
import gnu.trove.THashMap
import gnu.trove.THashSet
import org.jetbrains.annotations.TestOnly
import org.jetbrains.jps.builders.BuildTarget
import org.jetbrains.jps.builders.storage.BuildDataPaths
import org.jetbrains.jps.builders.storage.StorageProvider
import org.jetbrains.jps.incremental.storage.BuildDataManager
import org.jetbrains.jps.incremental.storage.OneToManyPathsMapping
import org.jetbrains.jps.incremental.storage.PathStringDescriptor
import org.jetbrains.jps.incremental.storage.StorageOwner
import org.jetbrains.kotlin.config.IncrementalCompilation
@@ -122,15 +122,21 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
private val classToSourcesMap = ClassToSourcesMap()
private val dirtyOutputClassesMap = DirtyOutputClassesMap()
private val dirtyInlineFunctionsMap = DirtyInlineFunctionsMap()
private val hasInlineTo = OneToManyPathsMapping(File(baseDir, HAS_INLINE_TO))
private val hasInlineTo = InlineFunctionsFilesMap()
private val maps = listOf(protoMap, constantsMap, inlineFunctionsMap, packagePartMap, sourceToClassesMap, dirtyOutputClassesMap)
private val maps = listOf(protoMap,
constantsMap,
inlineFunctionsMap,
packagePartMap,
sourceToClassesMap,
dirtyOutputClassesMap,
hasInlineTo)
private val cacheFormatVersion = CacheFormatVersion(targetDataRoot)
private val inlineRegistering = object : InlineRegistering {
override fun registerInline(fromPath: String, toPath: String) {
hasInlineTo.appendData(fromPath, toPath)
override fun registerInline(fromPath: String, jvmSignature: String, toPath: String) {
hasInlineTo.add(fromPath, jvmSignature, toPath)
}
}
@@ -153,8 +159,20 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
}
}
public fun getInlineDependencies(sourceFile: File): Collection<String> {
return hasInlineTo.getState(sourceFile.getCanonicalPath()) ?: emptyList()
public fun getFilesToReinline(): Collection<File> {
val result = THashSet(FileUtil.PATH_HASHING_STRATEGY)
for ((className, functions) in dirtyInlineFunctionsMap.getEntries()) {
val sourceFiles = classToSourcesMap[className]
for (sourceFile in sourceFiles) {
val targetFiles = functions.flatMap { hasInlineTo[sourceFile, it] }
result.addAll(targetFiles)
}
}
dirtyInlineFunctionsMap.clean()
return result.map { File(it) }
}
private fun getRecompilationDecision(protoChanged: Boolean, constantsChanged: Boolean, inlinesChanged: Boolean) =
@@ -256,7 +274,6 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
inlineFunctionsMap.remove(className)
}
dirtyOutputClassesMap.clean()
dirtyInlineFunctionsMap.clean()
return recompilationDecision
}
@@ -295,7 +312,7 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
public fun contains(key: String): Boolean = storage.containsMapping(key)
public fun clean() {
public open fun clean() {
try {
storage.close()
}
@@ -310,7 +327,7 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
}
}
public fun flush(memoryCachesOnly: Boolean) {
public open fun flush(memoryCachesOnly: Boolean) {
if (memoryCachesOnly) {
if (storage.isDirty()) {
storage.dropMemoryCaches()
@@ -688,12 +705,12 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
PathCollectionExternalizer
)
public fun get(className: JvmClassName): Collection<File>? =
storage[className.internalName]?.let { it.map { path -> File(path) } }
public fun get(className: JvmClassName): Collection<String> =
storage[className.internalName] ?: emptySet()
public fun add(className: JvmClassName, sourceFile: File) {
storage.appendData(className.internalName) { out ->
IOUtil.writeUTF(out, FileUtil.normalize(sourceFile.normalizedPath))
IOUtil.writeUTF(out, sourceFile.normalizedPath)
}
}
@@ -745,6 +762,72 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
override fun dumpValue(value: List<String>) = value.toString()
}
/**
* Mapping: sourceFile->{inlineFunction->...targetFiles}
*
* Where:
* * sourceFile - path to some kotlin source
* * inlineFunction - jvmSignature of some inline function in source file
* * target files - collection of files inlineFunction has been inlined to
*/
private inner class InlineFunctionsFilesMap : BasicMap<Map<String, Collection<String>>>() {
private val cache = THashMap<String, MutableMap<String, MutableCollection<String>>>(FileUtil.PATH_HASHING_STRATEGY)
override fun createMap(): PersistentHashMap<String, Map<String, Collection<String>>> = PersistentHashMap(
File(baseDir, HAS_INLINE_TO),
PathStringDescriptor(),
StringToPathsMapExternalizer
)
public fun add(sourcePath: String, jvmSignature: String, targetPath: String) {
val mapping = getMappingFromCache(sourcePath.normalizedPath)
val paths = mapping.getOrPut(jvmSignature) { THashSet(FileUtil.PATH_HASHING_STRATEGY) }
paths.add(targetPath.normalizedPath)
}
public fun get(sourceFile: String, jvmSignature: String): Collection<String> {
val normalizedPath = sourceFile.normalizedPath
if (normalizedPath !in cache && !storage.containsMapping(normalizedPath)) return emptySet()
val mapping = getMappingFromCache(normalizedPath)
return mapping[jvmSignature] ?: emptySet()
}
override fun clean() {
cache.clear()
super.clean()
}
override fun flush(memoryCachesOnly: Boolean) {
for ((k, v) in cache) {
storage.put(k, v)
}
super.flush(memoryCachesOnly)
}
// TODO: fix
override fun dumpValue(value: Map<String, Collection<String>>) =
value.toString()
private fun getMappingFromCache(sourcePath: String): MutableMap<String, MutableCollection<String>> {
val cachedValue = cache[sourcePath]
if (cachedValue != null) return cachedValue
val mapping = storage[sourcePath] ?: emptyMap()
val mutableMapping = hashMapOf<String, MutableCollection<String>>()
for ((k, v) in mapping) {
val paths = THashSet(v, FileUtil.PATH_HASHING_STRATEGY)
mutableMapping[k] = paths
}
cache[sourcePath] = mutableMapping
return mutableMapping
}
}
enum class RecompilationDecision {
DO_NOTHING,
RECOMPILE_OTHER_KOTLIN_IN_CHUNK,
@@ -829,6 +912,27 @@ private object StringToLongMapExternalizer : StringMapExternalizer<Long>() {
}
}
private object StringToPathsMapExternalizer : StringMapExternalizer<Collection<String>>() {
override fun readValue(input: DataInput): Collection<String> {
val size = input.readInt()
val paths = THashSet(size, FileUtil.PATH_HASHING_STRATEGY)
repeat(size) {
paths.add(IOUtil.readUTF(input))
}
return paths
}
override fun writeValue(output: DataOutput, value: Collection<String>) {
output.writeInt(value.size())
for (path in value) {
IOUtil.writeUTF(output, path)
}
}
}
private object StringListExternalizer : DataExternalizer<List<String>> {
override fun save(out: DataOutput, value: List<String>) {
value.forEach { IOUtil.writeUTF(out, it) }
@@ -864,3 +968,6 @@ private object PathCollectionExternalizer : DataExternalizer<Collection<String>>
private val File.normalizedPath: String
get() = FileUtil.toSystemIndependentName(canonicalPath)
private val String.normalizedPath: String
get() = FileUtil.toSystemIndependentName(this)