diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/InlineRegistering.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/InlineRegistering.kt index e5f0ea5b815..3fd7f5759c7 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/InlineRegistering.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/components/InlineRegistering.kt @@ -17,5 +17,5 @@ package org.jetbrains.kotlin.load.kotlin.incremental.components interface InlineRegistering { - fun registerInline(fromPath: String, toPath: String) + fun registerInline(fromPath: String, jvmSignature: String, toPath: String) } \ No newline at end of file diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt index a2c4db818c7..e97fd22dc98 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -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() diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt index 21c13627434..e6379540b79 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -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 { - return hasInlineTo.getState(sourceFile.getCanonicalPath()) ?: emptyList() + public fun getFilesToReinline(): Collection { + 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? = - storage[className.internalName]?.let { it.map { path -> File(path) } } + public fun get(className: JvmClassName): Collection = + 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) = 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>>() { + + private val cache = THashMap>>(FileUtil.PATH_HASHING_STRATEGY) + + override fun createMap(): PersistentHashMap>> = 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 { + 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>) = + value.toString() + + private fun getMappingFromCache(sourcePath: String): MutableMap> { + val cachedValue = cache[sourcePath] + if (cachedValue != null) return cachedValue + + val mapping = storage[sourcePath] ?: emptyMap() + val mutableMapping = hashMapOf>() + + 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() { } } +private object StringToPathsMapExternalizer : StringMapExternalizer>() { + override fun readValue(input: DataInput): Collection { + 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) { + output.writeInt(value.size()) + + for (path in value) { + IOUtil.writeUTF(output, path) + } + } +} + private object StringListExternalizer : DataExternalizer> { override fun save(out: DataOutput, value: List) { value.forEach { IOUtil.writeUTF(out, it) } @@ -864,3 +968,6 @@ private object PathCollectionExternalizer : DataExternalizer> private val File.normalizedPath: String get() = FileUtil.toSystemIndependentName(canonicalPath) +private val String.normalizedPath: String + get() = FileUtil.toSystemIndependentName(this) +