Writing/reading constants map fully to avoid hash collisions.
Original commit: e1f6fc55c5
This commit is contained in:
@@ -30,14 +30,13 @@ import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader
|
|||||||
import org.jetbrains.jet.descriptors.serialization.BitEncoding
|
import org.jetbrains.jet.descriptors.serialization.BitEncoding
|
||||||
import org.jetbrains.jet.utils.intellij.*
|
import org.jetbrains.jet.utils.intellij.*
|
||||||
import java.util.Arrays
|
import java.util.Arrays
|
||||||
import com.intellij.util.io.IntInlineKeyDescriptor
|
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames
|
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName
|
import org.jetbrains.jet.lang.resolve.java.JvmClassName
|
||||||
import java.util.TreeMap
|
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalCache
|
import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalCache
|
||||||
|
import java.util.HashMap
|
||||||
|
|
||||||
public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
||||||
class object {
|
class object {
|
||||||
@@ -45,8 +44,8 @@ public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
|||||||
val CONSTANTS_MAP = "constants.tab"
|
val CONSTANTS_MAP = "constants.tab"
|
||||||
val PACKAGE_SOURCES = "package-sources.tab"
|
val PACKAGE_SOURCES = "package-sources.tab"
|
||||||
|
|
||||||
private fun getConstantsHash(bytes: ByteArray): Int {
|
private fun getConstantsMap(bytes: ByteArray): Map<String, Any> {
|
||||||
val result = TreeMap<String, Any>() // keys order should defined to check hash of a map
|
val result = HashMap<String, Any>()
|
||||||
|
|
||||||
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.ASM5) {
|
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.ASM5) {
|
||||||
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
||||||
@@ -57,13 +56,13 @@ public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
|||||||
}
|
}
|
||||||
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
}, ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
|
||||||
|
|
||||||
return result.hashCode()
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val protoData: PersistentMap<ClassOrPackageId, ByteArray>
|
private val protoData: PersistentMap<ClassOrPackageId, ByteArray>
|
||||||
private val constantsData: PersistentHashMap<String, Int>
|
private val constantsData: PersistentHashMap<String, Map<String, Any>>
|
||||||
= PersistentHashMap(File(baseDir, CONSTANTS_MAP), EnumeratorStringDescriptor(), IntInlineKeyDescriptor())
|
= PersistentHashMap(File(baseDir, CONSTANTS_MAP), EnumeratorStringDescriptor(), ConstantsMapExternalizer())
|
||||||
|
|
||||||
// Format of serialization to string: <module id> <path separator> <source file path> --> <package part JVM internal name>
|
// Format of serialization to string: <module id> <path separator> <source file path> --> <package part JVM internal name>
|
||||||
private val packageSourcesData: PersistentHashMap<String, String>
|
private val packageSourcesData: PersistentHashMap<String, String>
|
||||||
@@ -129,7 +128,7 @@ public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
|||||||
if (header.syntheticClassKind == JvmAnnotationNames.KotlinSyntheticClass.Kind.PACKAGE_PART) {
|
if (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" }
|
||||||
putPackagePartSourceData(moduleId, sourceFiles.first(), className)
|
putPackagePartSourceData(moduleId, sourceFiles.first(), className)
|
||||||
return putConstantsData(className, getConstantsHash(fileBytes))
|
return putConstantsData(className, getConstantsMap(fileBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -149,14 +148,14 @@ public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun putConstantsData(packagePartClass: JvmClassName, constantsHash: Int): Boolean {
|
private fun putConstantsData(packagePartClass: JvmClassName, constantsMap: Map<String, Any>): Boolean {
|
||||||
val key = packagePartClass.getInternalName()
|
val key = packagePartClass.getInternalName()
|
||||||
|
|
||||||
val oldHash = constantsData[key]
|
val oldMap = constantsData[key]
|
||||||
if (oldHash == constantsHash) {
|
if (oldMap == constantsMap) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
constantsData.put(key, constantsHash)
|
constantsData.put(key, constantsMap)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,4 +205,62 @@ public class IncrementalCacheImpl(baseDir: File): IncrementalCache {
|
|||||||
|
|
||||||
private data class ClassOrPackageId(val moduleId: String, val fqName: FqName) {
|
private data class ClassOrPackageId(val moduleId: String, val fqName: FqName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ConstantsMapExternalizer: DataExternalizer<Map<String, Any>> {
|
||||||
|
override fun save(out: DataOutput, map: Map<String, Any>?) {
|
||||||
|
out.writeInt(map!!.size)
|
||||||
|
for (name in map.keySet().toSortedList()) {
|
||||||
|
IOUtil.writeString(name, out)
|
||||||
|
val value = map[name]!!
|
||||||
|
when (value) {
|
||||||
|
is Int -> {
|
||||||
|
out.writeByte(Kind.INT.ordinal())
|
||||||
|
out.writeInt(value)
|
||||||
|
}
|
||||||
|
is Float -> {
|
||||||
|
out.writeByte(Kind.FLOAT.ordinal())
|
||||||
|
out.writeFloat(value)
|
||||||
|
}
|
||||||
|
is Long -> {
|
||||||
|
out.writeByte(Kind.LONG.ordinal())
|
||||||
|
out.writeLong(value)
|
||||||
|
}
|
||||||
|
is Double -> {
|
||||||
|
out.writeByte(Kind.DOUBLE.ordinal())
|
||||||
|
out.writeDouble(value)
|
||||||
|
}
|
||||||
|
is String -> {
|
||||||
|
out.writeByte(Kind.STRING.ordinal())
|
||||||
|
IOUtil.writeString(value, out)
|
||||||
|
}
|
||||||
|
else -> throw IllegalStateException("Unexpected constant class: ${value.javaClass}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(`in`: DataInput): Map<String, Any>? {
|
||||||
|
val size = `in`.readInt()
|
||||||
|
val map = HashMap<String, Any>(size)
|
||||||
|
|
||||||
|
for (i in size.indices) {
|
||||||
|
val name = IOUtil.readString(`in`)!!
|
||||||
|
|
||||||
|
val kind = Kind.values()[`in`.readByte().toInt()]
|
||||||
|
val value = when (kind) {
|
||||||
|
Kind.INT -> `in`.readInt()
|
||||||
|
Kind.FLOAT -> `in`.readFloat()
|
||||||
|
Kind.LONG -> `in`.readLong()
|
||||||
|
Kind.DOUBLE -> `in`.readDouble()
|
||||||
|
Kind.STRING -> IOUtil.readString(`in`)!!
|
||||||
|
}
|
||||||
|
map[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum class Kind {
|
||||||
|
INT FLOAT LONG DOUBLE STRING
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
val CONST = "foo"
|
// Old and new constant values are different, but their hashes are the same
|
||||||
|
val CONST = "BF"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
val CONST = "bar"
|
// Old and new constant values are different, but their hashes are the same
|
||||||
|
val CONST = "Ae"
|
||||||
|
|||||||
Reference in New Issue
Block a user