From b3659486d90c7a72eb5033728b10a81af632fdff Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Thu, 23 Jul 2015 00:00:01 +0300 Subject: [PATCH] IncrementalCacheImpl: do not recompile other files if all changes are private --- .../jps/incremental/IncrementalCacheImpl.kt | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) 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 834c67f3ff4..ed13a80f55b 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/incremental/IncrementalCacheImpl.kt @@ -25,6 +25,7 @@ import org.jetbrains.jps.incremental.storage.BuildDataManager import org.jetbrains.jps.incremental.storage.PathStringDescriptor import org.jetbrains.jps.incremental.storage.StorageOwner import org.jetbrains.kotlin.config.IncrementalCompilation +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.jps.build.KotlinBuilder import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.DO_NOTHING import org.jetbrains.kotlin.jps.incremental.IncrementalCacheImpl.RecompilationDecision.RECOMPILE_ALL_IN_CHUNK_AND_DEPENDANTS @@ -38,7 +39,11 @@ import org.jetbrains.kotlin.load.kotlin.header.isCompatiblePackageFacadeKind 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.serialization.Flags +import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.jvm.BitEncoding +import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil +import org.jetbrains.kotlin.serialization.deserialization.visibility import org.jetbrains.kotlin.utils.Printer import org.jetbrains.org.objectweb.asm.* import java.io.* @@ -150,14 +155,14 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen val decision = when { header.isCompatiblePackageFacadeKind() -> getRecompilationDecision( - protoChanged = protoMap.put(className, BitEncoding.decodeBytes(header.annotationData!!)), + protoChanged = protoMap.put(className, BitEncoding.decodeBytes(header.annotationData!!), isPackage = true), constantsChanged = false, inlinesChanged = false ) header.isCompatibleClassKind() -> when (header.classKind!!) { JvmAnnotationNames.KotlinClass.Kind.CLASS -> getRecompilationDecision( - protoChanged = protoMap.put(className, BitEncoding.decodeBytes(header.annotationData!!)), + protoChanged = protoMap.put(className, BitEncoding.decodeBytes(header.annotationData!!), isPackage = false), constantsChanged = constantsMap.process(className, fileBytes), inlinesChanged = inlineFunctionsMap.process(className, fileBytes) ) @@ -299,13 +304,18 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen ByteArrayExternalizer ) - public fun put(className: JvmClassName, data: ByteArray): Boolean { + public fun put(className: JvmClassName, data: ByteArray, isPackage: Boolean): Boolean { val key = className.getInternalName() val oldData = storage[key] if (Arrays.equals(data, oldData)) { return false } storage.put(key, data) + + if (oldData != null && isOpenPartNotChanged(oldData, data, isPackage)) { + return false + } + return true } @@ -320,6 +330,53 @@ public class IncrementalCacheImpl(targetDataRoot: File) : StorageOwner, Incremen override fun dumpValue(value: ByteArray): String { return java.lang.Long.toHexString(value.md5()) } + + private fun isOpenPartNotChanged(oldData: ByteArray, newData: ByteArray, isPackageFacade: Boolean): Boolean { + if (isPackageFacade) { + return isPackageFacadeOpenPartNotChanged(oldData, newData) + } + else { + return isClassOpenPartNotChanged(oldData, newData) + } + } + + private fun isPackageFacadeOpenPartNotChanged(oldData: ByteArray, newData: ByteArray): Boolean { + val oldPackageData = JvmProtoBufUtil.readPackageDataFrom(oldData) + val newPackageData = JvmProtoBufUtil.readPackageDataFrom(newData) + + val compareObject = ProtoCompareGenerated(oldPackageData.nameResolver, newPackageData.nameResolver) + return compareObject.checkEquals(oldPackageData.packageProto, newPackageData.packageProto) + } + + private fun isClassOpenPartNotChanged(oldData: ByteArray, newData: ByteArray): Boolean { + val oldClassData = JvmProtoBufUtil.readClassDataFrom(oldData) + val newClassData = JvmProtoBufUtil.readClassDataFrom(newData) + + val compareObject = object : ProtoCompareGenerated(oldClassData.nameResolver, newClassData.nameResolver) { + override fun checkEqualsClassMember(old: ProtoBuf.Class, new: ProtoBuf.Class): Boolean = + checkEquals(old.memberList, new.memberList) + + override fun checkEqualsClassSecondaryConstructor(old: ProtoBuf.Class, new: ProtoBuf.Class): Boolean = + checkEquals(old.secondaryConstructorList, new.secondaryConstructorList) + + private fun checkEquals(oldList: List, newList: List): Boolean { + val oldListFiltered = oldList.filter { !it.isPrivate() } + val newListFiltered = newList.filter { !it.isPrivate() } + + if (oldListFiltered.size() != newListFiltered.size()) return false + + for (i in oldListFiltered.indices) { + if (!checkEquals(oldListFiltered[i], newListFiltered[i])) return false + } + + return true + } + + private fun ProtoBuf.Callable.isPrivate(): Boolean = Visibilities.isPrivate(visibility(Flags.VISIBILITY.get(flags))) + } + + return compareObject.checkEquals(oldClassData.classProto, newClassData.classProto) + } } private inner class ConstantsMap : BasicMap>() {