Fix incremental compilation for new package parts

This commit is contained in:
Zalim Bashorov
2015-09-04 18:30:04 +03:00
committed by Michael Bogdanov
parent 8e411e7274
commit ec62cccb1a
7 changed files with 85 additions and 28 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -33,6 +34,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.serialization.PackageData import org.jetbrains.kotlin.serialization.PackageData
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedNewPackageMemberScope
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
@@ -40,7 +42,6 @@ import org.jetbrains.kotlin.storage.NotNullLazyValue
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.* import java.util.*
import kotlin.reflect.jvm.*
public class IncrementalPackageFragmentProvider( public class IncrementalPackageFragmentProvider(
sourceFiles: Collection<JetFile>, sourceFiles: Collection<JetFile>,
@@ -101,12 +102,30 @@ public class IncrementalPackageFragmentProvider(
JetScope.Empty JetScope.Empty
} }
else { else {
val packageDataBytes = incrementalCache.getPackageData(fqName.asString()) val moduleMapping = incrementalCache.getModuleMappingData()?.let { ModuleMapping(it) }
if (packageDataBytes == null) {
val actualPackagePartFiles =
moduleMapping?.findPackageParts(fqName.asString())?.let {
val allParts =
if (it.packageFqName.isEmpty()) {
it.parts
}
else {
val packageFqName = it.packageFqName.replace('.', '/')
it.parts.map { packageFqName + "/" + it }
}
allParts.filterNot { it in obsoletePackageParts }
} ?: emptyList<String>()
val dataOfPackageParts = actualPackagePartFiles.map { incrementalCache.getPackagePartData(it) }.filterNotNull()
if (dataOfPackageParts.isEmpty()) {
JetScope.Empty JetScope.Empty
} }
else { else {
DecapitalizedAnnotationScope.wrapIfNeeded(IncrementalPackageScope(JvmProtoBufUtil.readPackageDataFrom(packageDataBytes)), fqName) val scopes = dataOfPackageParts.map { IncrementalPackageScope(JvmProtoBufUtil.readPackageDataFrom(it)) }
DecapitalizedAnnotationScope.wrapIfNeeded(DeserializedNewPackageMemberScope(this, scopes), fqName)
} }
} }
} }
@@ -16,12 +16,12 @@
package org.jetbrains.kotlin.load.kotlin.incremental.components package org.jetbrains.kotlin.load.kotlin.incremental.components
import java.io.File
public interface IncrementalCache { public interface IncrementalCache {
public fun getObsoletePackageParts(): Collection<String> public fun getObsoletePackageParts(): Collection<String>
public fun getPackageData(fqName: String): ByteArray? public fun getPackagePartData(fqName: String): ByteArray?
public fun getModuleMappingData(): ByteArray?
public fun close() public fun close()
} }
@@ -16,8 +16,8 @@
package org.jetbrains.kotlin.rmi.kotlinr package org.jetbrains.kotlin.rmi.kotlinr
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.rmi.CompileService import org.jetbrains.kotlin.rmi.CompileService
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
import java.rmi.server.UnicastRemoteObject import java.rmi.server.UnicastRemoteObject
@@ -29,7 +29,9 @@ public class RemoteIncrementalCacheServer(val cache: IncrementalCache) : Compile
override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts() override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts()
override fun getPackageData(fqName: String): ByteArray? = cache.getPackageData(fqName) override fun getPackagePartData(fqName: String): ByteArray? = cache.getPackagePartData(fqName)
override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData()
override fun close() { override fun close() {
cache.close() cache.close()
@@ -38,4 +40,4 @@ public class RemoteIncrementalCacheServer(val cache: IncrementalCache) : Compile
public fun disconnect() { public fun disconnect() {
UnicastRemoteObject.unexportObject(this, true) UnicastRemoteObject.unexportObject(this, true)
} }
} }
@@ -31,7 +31,10 @@ public interface CompileService : Remote {
public fun getObsoletePackageParts(): Collection<String> public fun getObsoletePackageParts(): Collection<String>
throws(RemoteException::class) throws(RemoteException::class)
public fun getPackageData(fqName: String): ByteArray? public fun getPackagePartData(fqName: String): ByteArray?
throws(RemoteException::class)
public fun getModuleMappingData(): ByteArray?
throws(RemoteException::class) throws(RemoteException::class)
public fun close() public fun close()
@@ -22,7 +22,9 @@ import org.jetbrains.kotlin.rmi.CompileService
public class RemoteIncrementalCacheClient(val cache: CompileService.RemoteIncrementalCache): IncrementalCache { public class RemoteIncrementalCacheClient(val cache: CompileService.RemoteIncrementalCache): IncrementalCache {
override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts() override fun getObsoletePackageParts(): Collection<String> = cache.getObsoletePackageParts()
override fun getPackageData(fqName: String): ByteArray? = cache.getPackageData(fqName) override fun getPackagePartData(fqName: String): ByteArray? = cache.getPackagePartData(fqName)
override fun getModuleMappingData(): ByteArray? = cache.getModuleMappingData()
override fun close(): Unit = cache.close() override fun close(): Unit = cache.close()
} }
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDe
import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_ALL_IN_CHUNK_AND_DEPENDANTS import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_ALL_IN_CHUNK_AND_DEPENDANTS
import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_OTHER_IN_CHUNK_AND_DEPENDANTS import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_OTHER_IN_CHUNK_AND_DEPENDANTS
import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_OTHER_KOTLIN_IN_CHUNK import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_OTHER_KOTLIN_IN_CHUNK
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
@@ -198,7 +199,7 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
} }
else { else {
val generatedClasses = generatedFiles.filterIsInstance<GeneratedJvmClass>() val generatedClasses = generatedFiles.filterIsInstance<GeneratedJvmClass>()
recompilationDecision = updateKotlinIncrementalCache(compilationErrors, incrementalCaches, generatedClasses) recompilationDecision = updateKotlinIncrementalCache(compilationErrors, incrementalCaches, generatedFiles)
updateJavaMappings(chunk, compilationErrors, context, dirtyFilesHolder, filesToCompile, generatedClasses) updateJavaMappings(chunk, compilationErrors, context, dirtyFilesHolder, filesToCompile, generatedClasses)
} }
@@ -410,7 +411,7 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
private fun updateKotlinIncrementalCache( private fun updateKotlinIncrementalCache(
compilationErrors: Boolean, compilationErrors: Boolean,
incrementalCaches: Map<ModuleBuildTarget, IncrementalCacheImpl>, incrementalCaches: Map<ModuleBuildTarget, IncrementalCacheImpl>,
generatedClasses: List<GeneratedJvmClass> generatedFiles: List<GeneratedFile>
): IncrementalCacheImpl.RecompilationDecision { ): IncrementalCacheImpl.RecompilationDecision {
incrementalCaches.values().forEach { it.saveCacheFormatVersion() } incrementalCaches.values().forEach { it.saveCacheFormatVersion() }
@@ -419,8 +420,19 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
} }
var recompilationDecision = DO_NOTHING var recompilationDecision = DO_NOTHING
for (generatedClass in generatedClasses) { for (generatedFile in generatedFiles) {
val newDecision = incrementalCaches[generatedClass.target]!!.saveFileToCache(generatedClass.sourceFiles, generatedClass.outputClass) val ic = incrementalCaches[generatedFile.target]!!
val newDecision =
if (generatedFile is GeneratedJvmClass) {
ic.saveFileToCache(generatedFile.sourceFiles, generatedFile.outputClass)
}
else if (generatedFile.outputFile.isModuleMappingFile()) {
ic.saveModuleMappingToCache(generatedFile.outputFile)
}
else {
continue
}
recompilationDecision = recompilationDecision.merge(newDecision) recompilationDecision = recompilationDecision.merge(newDecision)
} }
@@ -434,6 +446,8 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
return recompilationDecision return recompilationDecision
} }
private fun File.isModuleMappingFile() = extension == ModuleMapping.MAPPING_FILE_EXT && parentFile.name == "META-INF"
// if null is returned, nothing was done // if null is returned, nothing was done
private fun compileToJs(chunk: ModuleChunk, private fun compileToJs(chunk: ModuleChunk,
commonArguments: CommonCompilerArguments, commonArguments: CommonCompilerArguments,
@@ -33,25 +33,22 @@ import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDe
import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_OTHER_KOTLIN_IN_CHUNK import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_OTHER_KOTLIN_IN_CHUNK
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.Flags import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.visibility
import org.jetbrains.kotlin.serialization.jvm.BitEncoding import org.jetbrains.kotlin.serialization.jvm.BitEncoding
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
import org.jetbrains.kotlin.serialization.deserialization.visibility
import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.*
import java.io.* import java.io.*
import java.security.MessageDigest import java.security.MessageDigest
import java.util.ArrayList import java.util.*
import java.util.Arrays
import java.util.HashMap
val INLINE_ANNOTATION_DESC = "Lkotlin/inline;" val INLINE_ANNOTATION_DESC = "Lkotlin/inline;"
@@ -105,6 +102,8 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
val PACKAGE_PARTS = "package-parts.tab" val PACKAGE_PARTS = "package-parts.tab"
val SOURCE_TO_CLASSES = "source-to-classes.tab" val SOURCE_TO_CLASSES = "source-to-classes.tab"
val DIRTY_OUTPUT_CLASSES = "dirty-output-classes.tab" val DIRTY_OUTPUT_CLASSES = "dirty-output-classes.tab"
private val MODULE_MAPPING_FILE_NAME = "." + ModuleMapping.MAPPING_FILE_EXT
} }
private val baseDir = File(targetDataRoot, CACHE_DIRECTORY_NAME) private val baseDir = File(targetDataRoot, CACHE_DIRECTORY_NAME)
@@ -145,6 +144,12 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
cacheFormatVersion.saveIfNeeded() cacheFormatVersion.saveIfNeeded()
} }
public fun saveModuleMappingToCache(file: File): RecompilationDecision {
protoMap.put(JvmClassName.byInternalName(MODULE_MAPPING_FILE_NAME), file.readBytes(), isPackage = false, checkChangesIsOpenPart = false)
dirtyOutputClassesMap.notDirty(MODULE_MAPPING_FILE_NAME)
return DO_NOTHING
}
public fun saveFileToCache(sourceFiles: Collection<File>, kotlinClass: LocalFileKotlinClass): RecompilationDecision { public fun saveFileToCache(sourceFiles: Collection<File>, kotlinClass: LocalFileKotlinClass): RecompilationDecision {
val fileBytes = kotlinClass.getFileContents() val fileBytes = kotlinClass.getFileContents()
val className = JvmClassName.byClassId(kotlinClass.getClassId()) val className = JvmClassName.byClassId(kotlinClass.getClassId())
@@ -160,6 +165,15 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
constantsChanged = false, constantsChanged = false,
inlinesChanged = false inlinesChanged = false
) )
header.isCompatibleFileFacadeKind() -> {
assert(sourceFiles.size() == 1) { "Package part from several source files: $sourceFiles" }
packagePartMap.addPackagePart(className)
getRecompilationDecision(
protoChanged = protoMap.put(className, BitEncoding.decodeBytes(header.annotationData!!), isPackage = true),
constantsChanged = constantsMap.process(className, fileBytes),
inlinesChanged = inlineFunctionsMap.process(className, fileBytes)
)
}
header.isCompatibleClassKind() -> header.isCompatibleClassKind() ->
when (header.classKind!!) { when (header.classKind!!) {
JvmAnnotationNames.KotlinClass.Kind.CLASS -> getRecompilationDecision( JvmAnnotationNames.KotlinClass.Kind.CLASS -> getRecompilationDecision(
@@ -170,7 +184,6 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
JvmAnnotationNames.KotlinClass.Kind.LOCAL_CLASS, JvmAnnotationNames.KotlinClass.Kind.ANONYMOUS_OBJECT -> DO_NOTHING JvmAnnotationNames.KotlinClass.Kind.LOCAL_CLASS, JvmAnnotationNames.KotlinClass.Kind.ANONYMOUS_OBJECT -> DO_NOTHING
} }
header.isCompatibleFileFacadeKind() ||
header.syntheticClassKind == JvmAnnotationNames.KotlinSyntheticClass.Kind.PACKAGE_PART -> { header.syntheticClassKind == JvmAnnotationNames.KotlinSyntheticClass.Kind.PACKAGE_PART -> {
assert(sourceFiles.size() == 1) { "Package part from several source files: $sourceFiles" } assert(sourceFiles.size() == 1) { "Package part from several source files: $sourceFiles" }
@@ -217,15 +230,19 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
return recompilationDecision return recompilationDecision
} }
public override fun getObsoletePackageParts(): Collection<String> { override fun getObsoletePackageParts(): Collection<String> {
val obsoletePackageParts = val obsoletePackageParts =
dirtyOutputClassesMap.getDirtyOutputClasses().filter { packagePartMap.isPackagePart(JvmClassName.byInternalName(it)) } dirtyOutputClassesMap.getDirtyOutputClasses().filter { packagePartMap.isPackagePart(JvmClassName.byInternalName(it)) }
KotlinBuilder.LOG.debug("Obsolete package parts: ${obsoletePackageParts}") KotlinBuilder.LOG.debug("Obsolete package parts: ${obsoletePackageParts}")
return obsoletePackageParts return obsoletePackageParts
} }
public override fun getPackageData(fqName: String): ByteArray? { override fun getPackagePartData(fqName: String): ByteArray? {
return protoMap[JvmClassName.byFqNameWithoutInnerClasses(PackageClassUtils.getPackageClassFqName(FqName(fqName)))] return protoMap[JvmClassName.byInternalName(fqName)]
}
override fun getModuleMappingData(): ByteArray? {
return protoMap[JvmClassName.byInternalName(MODULE_MAPPING_FILE_NAME)]
} }
override fun flush(memoryCachesOnly: Boolean) { override fun flush(memoryCachesOnly: Boolean) {
@@ -306,7 +323,7 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
ByteArrayExternalizer ByteArrayExternalizer
) )
public fun put(className: JvmClassName, data: ByteArray, isPackage: Boolean): Boolean { public fun put(className: JvmClassName, data: ByteArray, isPackage: Boolean, checkChangesIsOpenPart: Boolean = true): Boolean {
val key = className.getInternalName() val key = className.getInternalName()
val oldData = storage[key] val oldData = storage[key]
if (Arrays.equals(data, oldData)) { if (Arrays.equals(data, oldData)) {
@@ -314,7 +331,7 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen
} }
storage.put(key, data) storage.put(key, data)
if (oldData != null && isOpenPartNotChanged(oldData, data, isPackage)) { if (oldData != null && checkChangesIsOpenPart && isOpenPartNotChanged(oldData, data, isPackage)) {
return false return false
} }