IC: Small cleanup in KotlinClassInfo.kt
This is to address the not-yet-resolved comments in https://github.com/JetBrains/kotlin/pull/5127, plus a few other small (non-functional) changes. ^KT-58986: In progress
This commit is contained in:
+3
-1
@@ -42,5 +42,7 @@ class ClassFileWithContents(
|
||||
@Suppress("unused") val classFile: ClassFile,
|
||||
val contents: ByteArray
|
||||
) {
|
||||
val classInfo: BasicClassInfo = BasicClassInfo.compute(contents)
|
||||
val classInfo: BasicClassInfo by lazy {
|
||||
BasicClassInfo.compute(contents)
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -248,17 +248,20 @@ object ClasspathChangesComputer {
|
||||
|
||||
// IncrementalJvmCache currently doesn't use the `KotlinClassInfo.extraInfo.classSnapshotExcludingMembers` info when comparing
|
||||
// classes, so we need to do it here.
|
||||
// TODO(KT-58289): Ensure IncrementalJvmCache uses that info when comparing classes.
|
||||
// TODO(KT-59292): Ensure IncrementalJvmCache uses that info when comparing classes, so we can remove this code.
|
||||
val currentClassSnapshotsExcludingMembers = currentClassSnapshots
|
||||
.associate { it.classId to it.classMemberLevelSnapshot!!.extraInfo.classSnapshotExcludingMembers }
|
||||
.filter { it.value != null }
|
||||
val previousClassSnapshotsExcludingMembers = previousClassSnapshots
|
||||
.associate { it.classId to it.classMemberLevelSnapshot!!.extraInfo.classSnapshotExcludingMembers }
|
||||
.filter { it.value != null }
|
||||
previousClassSnapshotsExcludingMembers.keys.intersect(currentClassSnapshotsExcludingMembers.keys).forEach {
|
||||
if (previousClassSnapshotsExcludingMembers[it]!! != currentClassSnapshotsExcludingMembers[it]!!) {
|
||||
previousClassSnapshots.forEach { previousClassSnapshot ->
|
||||
val classId = previousClassSnapshot.classId
|
||||
val currentClassSnapshotExcludingMember = currentClassSnapshotsExcludingMembers[classId]
|
||||
val previousClassSnapshotExcludingMembers =
|
||||
previousClassSnapshot.classMemberLevelSnapshot!!.extraInfo.classSnapshotExcludingMembers
|
||||
if (currentClassSnapshotExcludingMember != null && previousClassSnapshotExcludingMembers != null
|
||||
&& currentClassSnapshotExcludingMember != previousClassSnapshotExcludingMembers
|
||||
) {
|
||||
// `areSubclassesAffected = false` as we don't need to compute impacted symbols at this step
|
||||
changesCollector.collectSignature(fqName = it.asSingleFqName(), areSubclassesAffected = false)
|
||||
changesCollector.collectSignature(fqName = classId.asSingleFqName(), areSubclassesAffected = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ internal object KotlinClassInfoExternalizer : DataExternalizer<KotlinClassInfo>
|
||||
}
|
||||
}
|
||||
|
||||
internal object ExtraInfoExternalizer : DataExternalizer<KotlinClassInfo.ExtraInfo> {
|
||||
private object ExtraInfoExternalizer : DataExternalizer<KotlinClassInfo.ExtraInfo> {
|
||||
|
||||
override fun save(output: DataOutput, info: KotlinClassInfo.ExtraInfo) {
|
||||
NullableValueExternalizer(LongExternalizer).save(output, info.classSnapshotExcludingMembers)
|
||||
|
||||
+21
-13
@@ -17,18 +17,18 @@ import org.jetbrains.kotlin.incremental.ClassNodeSnapshotter.sortClassMembers
|
||||
import org.jetbrains.kotlin.incremental.DifferenceCalculatorForPackageFacade.Companion.getNonPrivateMembers
|
||||
import org.jetbrains.kotlin.incremental.KotlinClassInfo
|
||||
import org.jetbrains.kotlin.incremental.PackagePartProtoData
|
||||
import org.jetbrains.kotlin.incremental.SelectiveClassVisitor
|
||||
import org.jetbrains.kotlin.incremental.classpathDiff.ClassSnapshotGranularity.CLASS_MEMBER_LEVEL
|
||||
import org.jetbrains.kotlin.incremental.hashToLong
|
||||
import org.jetbrains.kotlin.incremental.storage.toByteArray
|
||||
import org.jetbrains.kotlin.konan.file.use
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.Kind.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMemberSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.ClassNode
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
/** Computes a [ClasspathEntrySnapshot] of a classpath entry (directory or jar). */
|
||||
@@ -163,23 +163,30 @@ object ClassSnapshotter {
|
||||
// 2. Remove non-ABI info from the full class
|
||||
// Note that for incremental compilation to be correct, all ABI info must be collected exhaustively (now and in the future when
|
||||
// there are updates to Java/ASM), whereas it is acceptable if non-ABI info is not removed completely.
|
||||
// In the following, we will use the second approach as it is safer and easier.
|
||||
// Therefore, we will use the second approach as it is safer and easier.
|
||||
|
||||
// 1. Create a ClassNode that will contain ABI info of the class
|
||||
val classNode = ClassNode()
|
||||
val classReader = ClassReader(classFile.contents)
|
||||
|
||||
// 2. Load the class's contents into the ClassNode, removing non-ABI info:
|
||||
// - Remove private fields and methods
|
||||
// - Remove method bodies
|
||||
// - [Not yet implemented] Ignore fields' values except for constants
|
||||
// Note the `parsingOptions` passed to `classReader`:
|
||||
// - Pass SKIP_CODE as method bodies are not important
|
||||
// - Do not pass SKIP_DEBUG as debug info (e.g., method parameter names) may be important
|
||||
classReader.accept(classNode, ClassReader.SKIP_CODE)
|
||||
// - Pass SKIP_CODE as we want to remove method bodies
|
||||
// - Do not pass SKIP_DEBUG as debug info (e.g., method parameter names) may be important
|
||||
val classReader = ClassReader(classFile.contents)
|
||||
val selectiveClassVisitor = SelectiveClassVisitor(
|
||||
classNode,
|
||||
shouldVisitField = { _: JvmMemberSignature.Field, isPrivate: Boolean, _: Boolean -> !isPrivate },
|
||||
shouldVisitMethod = { _: JvmMemberSignature.Method, isPrivate: Boolean -> !isPrivate }
|
||||
)
|
||||
classReader.accept(selectiveClassVisitor, ClassReader.SKIP_CODE)
|
||||
|
||||
// 3. Sort fields and methods as their order is not important
|
||||
sortClassMembers(classNode)
|
||||
|
||||
// Remove private fields and methods
|
||||
fun Int.isPrivate() = (this and Opcodes.ACC_PRIVATE) != 0
|
||||
classNode.fields.removeIf { it.access.isPrivate() }
|
||||
classNode.methods.removeIf { it.access.isPrivate() }
|
||||
|
||||
// Snapshot the class
|
||||
// 4. Snapshot the class
|
||||
val classMemberLevelSnapshot = if (granularity == CLASS_MEMBER_LEVEL) {
|
||||
JavaClassMemberLevelSnapshot(
|
||||
classAbiExcludingMembers = JavaElementSnapshot(classNode.name, snapshotClassExcludingMembers(classNode)),
|
||||
@@ -190,6 +197,7 @@ object ClassSnapshotter {
|
||||
null
|
||||
}
|
||||
val classAbiHash = if (granularity == CLASS_MEMBER_LEVEL) {
|
||||
// We already have the class-member-level snapshot, so we can just hash it instead of snapshotting the class again
|
||||
JavaClassMemberLevelSnapshotExternalizer.toByteArray(classMemberLevelSnapshot!!).hashToLong()
|
||||
} else {
|
||||
snapshotClass(classNode)
|
||||
|
||||
Reference in New Issue
Block a user