[K/N] Rely on file fqName & path instead of unstable index

This commit is contained in:
Igor Chevdar
2023-01-11 22:42:19 +02:00
committed by Space Team
parent f90db20512
commit 281296fc2a
@@ -70,6 +70,8 @@ private val unsafe = with(Unsafe::class.java.getDeclaredField("theUnsafe")) {
} }
private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong() private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong()
private val charArrayBaseOffset = unsafe.arrayBaseOffset(CharArray::class.java).toLong()
private val intArrayBaseOffset = unsafe.arrayBaseOffset(IntArray::class.java).toLong()
internal class ByteArrayStream(val buf: ByteArray) { internal class ByteArrayStream(val buf: ByteArray) {
private var offset = 0 private var offset = 0
@@ -86,12 +88,93 @@ internal class ByteArrayStream(val buf: ByteArray) {
unsafe.putInt(buf, byteArrayBaseOffset + offset, value).also { offset += Int.SIZE_BYTES } unsafe.putInt(buf, byteArrayBaseOffset + offset, value).also { offset += Int.SIZE_BYTES }
} }
fun readString(length: Int): String {
checkSize(offset + Char.SIZE_BYTES * length) {
"Can't read a string of length $length at $offset, size = ${buf.size}"
}
val chars = CharArray(length)
unsafe.copyMemory(buf, byteArrayBaseOffset + offset, chars, charArrayBaseOffset, length * Char.SIZE_BYTES.toLong())
offset += length * Char.SIZE_BYTES
return String(chars)
}
fun writeString(string: String) {
checkSize(offset + Char.SIZE_BYTES * string.length) {
"Can't write a string of length ${string.length} at $offset, size = ${buf.size}"
}
unsafe.copyMemory(string.toCharArray(), charArrayBaseOffset, buf, byteArrayBaseOffset + offset, string.length * Char.SIZE_BYTES.toLong())
offset += string.length * Char.SIZE_BYTES
}
fun readIntArray(): IntArray {
val size = readInt()
checkSize(offset + Int.SIZE_BYTES * size) {
"Can't read an int array of size $size at $offset, size = ${buf.size}"
}
val array = IntArray(size)
unsafe.copyMemory(buf, byteArrayBaseOffset + offset, array, intArrayBaseOffset, size * Int.SIZE_BYTES.toLong())
offset += size * Int.SIZE_BYTES
return array
}
fun writeIntArray(array: IntArray) {
checkSize(offset + Int.SIZE_BYTES + Int.SIZE_BYTES * array.size) {
"Can't write an int array of size ${array.size} at $offset, size = ${buf.size}"
}
unsafe.putInt(buf, byteArrayBaseOffset + offset, array.size).also { offset += Int.SIZE_BYTES }
unsafe.copyMemory(array, intArrayBaseOffset, buf, byteArrayBaseOffset + offset, array.size * Int.SIZE_BYTES.toLong())
offset += array.size * Int.SIZE_BYTES
}
private fun checkSize(at: Int, messageBuilder: () -> String) { private fun checkSize(at: Int, messageBuilder: () -> String) {
if (at > buf.size) error(messageBuilder()) if (at > buf.size) error(messageBuilder())
} }
} }
class SerializedInlineFunctionReference(val file: Int, val functionSignature: Int, val body: Int, data class SerializedFileReference(val fqName: String, val path: String) {
constructor(irFile: IrFile) : this(irFile.fqName.asString(), irFile.path)
}
private class StringTableBuilder {
private val indices = mutableMapOf<String, Int>()
private var index = 0
operator fun String.unaryPlus() {
this@StringTableBuilder.indices.getOrPut(this) { index++ }
}
fun build() = StringTable(indices)
}
private inline fun buildStringTable(block: StringTableBuilder.() -> Unit): StringTable {
val builder = StringTableBuilder()
builder.block()
return builder.build()
}
private class StringTable(val indices: Map<String, Int>) {
val sizeBytes: Int get() = Int.SIZE_BYTES + indices.keys.sumOf { Int.SIZE_BYTES + it.length * Char.SIZE_BYTES }
fun serialize(stream: ByteArrayStream) {
val lengths = IntArray(indices.size)
val strings = Array(indices.size) { "" }
indices.forEach { (string, index) ->
lengths[index] = string.length
strings[index] = string
}
stream.writeIntArray(lengths)
strings.forEach { stream.writeString(it) }
}
companion object {
fun deserialize(stream: ByteArrayStream): Array<String> {
val lengths = stream.readIntArray()
return Array(lengths.size) { stream.readString(lengths[it]) }
}
}
}
class SerializedInlineFunctionReference(val file: SerializedFileReference, val functionSignature: Int, val body: Int,
val startOffset: Int, val endOffset: Int, val startOffset: Int, val endOffset: Int,
val extensionReceiverSig: Int, val dispatchReceiverSig: Int, val outerReceiverSigs: IntArray, val extensionReceiverSig: Int, val dispatchReceiverSig: Int, val outerReceiverSigs: IntArray,
val valueParameterSigs: IntArray, val typeParameterSigs: IntArray, val valueParameterSigs: IntArray, val typeParameterSigs: IntArray,
@@ -99,50 +182,55 @@ class SerializedInlineFunctionReference(val file: Int, val functionSignature: In
internal object InlineFunctionBodyReferenceSerializer { internal object InlineFunctionBodyReferenceSerializer {
fun serialize(bodies: List<SerializedInlineFunctionReference>): ByteArray { fun serialize(bodies: List<SerializedInlineFunctionReference>): ByteArray {
val size = bodies.sumOf { val stringTable = buildStringTable {
Int.SIZE_BYTES * (11 + it.outerReceiverSigs.size + it.valueParameterSigs.size + it.typeParameterSigs.size + it.defaultValues.size) bodies.forEach {
+it.file.fqName
+it.file.path
}
}
val size = stringTable.sizeBytes + bodies.sumOf {
Int.SIZE_BYTES * (12 + it.outerReceiverSigs.size + it.valueParameterSigs.size + it.typeParameterSigs.size + it.defaultValues.size)
} }
val stream = ByteArrayStream(ByteArray(size)) val stream = ByteArrayStream(ByteArray(size))
stringTable.serialize(stream)
bodies.forEach { bodies.forEach {
stream.writeInt(it.file) stream.writeInt(stringTable.indices[it.file.fqName]!!)
stream.writeInt(stringTable.indices[it.file.path]!!)
stream.writeInt(it.functionSignature) stream.writeInt(it.functionSignature)
stream.writeInt(it.body) stream.writeInt(it.body)
stream.writeInt(it.startOffset) stream.writeInt(it.startOffset)
stream.writeInt(it.endOffset) stream.writeInt(it.endOffset)
stream.writeInt(it.extensionReceiverSig) stream.writeInt(it.extensionReceiverSig)
stream.writeInt(it.dispatchReceiverSig) stream.writeInt(it.dispatchReceiverSig)
stream.writeInt(it.outerReceiverSigs.size) stream.writeIntArray(it.outerReceiverSigs)
it.outerReceiverSigs.forEach { sig -> stream.writeInt(sig) } stream.writeIntArray(it.valueParameterSigs)
stream.writeInt(it.valueParameterSigs.size) stream.writeIntArray(it.typeParameterSigs)
it.valueParameterSigs.forEach { sig -> stream.writeInt(sig) } stream.writeIntArray(it.defaultValues)
stream.writeInt(it.typeParameterSigs.size)
it.typeParameterSigs.forEach { sig -> stream.writeInt(sig) }
stream.writeInt(it.defaultValues.size)
it.defaultValues.forEach { stream.writeInt(it) }
} }
return stream.buf return stream.buf
} }
fun deserializeTo(data: ByteArray, result: MutableList<SerializedInlineFunctionReference>) { fun deserializeTo(data: ByteArray, result: MutableList<SerializedInlineFunctionReference>) {
val stream = ByteArrayStream(data) val stream = ByteArrayStream(data)
val stringTable = StringTable.deserialize(stream)
while (stream.hasData()) { while (stream.hasData()) {
val file = stream.readInt() val fileFqName = stringTable[stream.readInt()]
val filePath = stringTable[stream.readInt()]
val functionSignature = stream.readInt() val functionSignature = stream.readInt()
val body = stream.readInt() val body = stream.readInt()
val startOffset = stream.readInt() val startOffset = stream.readInt()
val endOffset = stream.readInt() val endOffset = stream.readInt()
val extensionReceiverSig = stream.readInt() val extensionReceiverSig = stream.readInt()
val dispatchReceiverSig = stream.readInt() val dispatchReceiverSig = stream.readInt()
val outerReceiverSigsCount = stream.readInt() val outerReceiverSigs = stream.readIntArray()
val outerReceiverSigs = IntArray(outerReceiverSigsCount) { stream.readInt() } val valueParameterSigs = stream.readIntArray()
val valueParameterSigsCount = stream.readInt() val typeParameterSigs = stream.readIntArray()
val valueParameterSigs = IntArray(valueParameterSigsCount) { stream.readInt() } val defaultValues = stream.readIntArray()
val typeParameterSigsCount = stream.readInt() result.add(SerializedInlineFunctionReference(
val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() } SerializedFileReference(fileFqName, filePath), functionSignature, body, startOffset, endOffset,
val defaultValuesCount = stream.readInt() extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs, valueParameterSigs,
val defaultValues = IntArray(defaultValuesCount) { stream.readInt() } typeParameterSigs, defaultValues)
result.add(SerializedInlineFunctionReference(file, functionSignature, body, startOffset, endOffset, )
extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs, valueParameterSigs, typeParameterSigs, defaultValues))
} }
} }
} }
@@ -155,18 +243,25 @@ class SerializedClassFieldInfo(val name: Int, val binaryType: Int, val type: Int
} }
} }
class SerializedClassFields(val file: Int, val classSignature: Int, val typeParameterSigs: IntArray, class SerializedClassFields(val file: SerializedFileReference, val classSignature: Int, val typeParameterSigs: IntArray,
val outerThisIndex: Int, val fields: Array<SerializedClassFieldInfo>) val outerThisIndex: Int, val fields: Array<SerializedClassFieldInfo>)
internal object ClassFieldsSerializer { internal object ClassFieldsSerializer {
fun serialize(classFields: List<SerializedClassFields>): ByteArray { fun serialize(classFields: List<SerializedClassFields>): ByteArray {
val size = classFields.sumOf { Int.SIZE_BYTES * (5 + it.typeParameterSigs.size + it.fields.size * 5) } val stringTable = buildStringTable {
classFields.forEach {
+it.file.fqName
+it.file.path
}
}
val size = stringTable.sizeBytes + classFields.sumOf { Int.SIZE_BYTES * (6 + it.typeParameterSigs.size + it.fields.size * 5) }
val stream = ByteArrayStream(ByteArray(size)) val stream = ByteArrayStream(ByteArray(size))
stringTable.serialize(stream)
classFields.forEach { classFields.forEach {
stream.writeInt(it.file) stream.writeInt(stringTable.indices[it.file.fqName]!!)
stream.writeInt(stringTable.indices[it.file.path]!!)
stream.writeInt(it.classSignature) stream.writeInt(it.classSignature)
stream.writeInt(it.typeParameterSigs.size) stream.writeIntArray(it.typeParameterSigs)
it.typeParameterSigs.forEach { stream.writeInt(it) }
stream.writeInt(it.outerThisIndex) stream.writeInt(it.outerThisIndex)
stream.writeInt(it.fields.size) stream.writeInt(it.fields.size)
it.fields.forEach { field -> it.fields.forEach { field ->
@@ -182,11 +277,12 @@ internal object ClassFieldsSerializer {
fun deserializeTo(data: ByteArray, result: MutableList<SerializedClassFields>) { fun deserializeTo(data: ByteArray, result: MutableList<SerializedClassFields>) {
val stream = ByteArrayStream(data) val stream = ByteArrayStream(data)
val stringTable = StringTable.deserialize(stream)
while (stream.hasData()) { while (stream.hasData()) {
val file = stream.readInt() val fileFqName = stringTable[stream.readInt()]
val filePath = stringTable[stream.readInt()]
val classSignature = stream.readInt() val classSignature = stream.readInt()
val typeParameterSigsCount = stream.readInt() val typeParameterSigs = stream.readIntArray()
val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() }
val outerThisIndex = stream.readInt() val outerThisIndex = stream.readInt()
val fieldsCount = stream.readInt() val fieldsCount = stream.readInt()
val fields = Array(fieldsCount) { val fields = Array(fieldsCount) {
@@ -197,28 +293,40 @@ internal object ClassFieldsSerializer {
val alignment = stream.readInt() val alignment = stream.readInt()
SerializedClassFieldInfo(name, binaryType, type, flags, alignment) SerializedClassFieldInfo(name, binaryType, type, flags, alignment)
} }
result.add(SerializedClassFields(file, classSignature, typeParameterSigs, outerThisIndex, fields)) result.add(SerializedClassFields(
SerializedFileReference(fileFqName, filePath), classSignature, typeParameterSigs, outerThisIndex, fields)
)
} }
} }
} }
class SerializedEagerInitializedFile(val file: Int) class SerializedEagerInitializedFile(val file: SerializedFileReference)
internal object EagerInitializedPropertySerializer { internal object EagerInitializedPropertySerializer {
fun serialize(properties: List<SerializedEagerInitializedFile>): ByteArray { fun serialize(properties: List<SerializedEagerInitializedFile>): ByteArray {
val size = properties.sumOf { Int.SIZE_BYTES } val stringTable = buildStringTable {
properties.forEach {
+it.file.fqName
+it.file.path
}
}
val size = stringTable.sizeBytes + properties.sumOf { Int.SIZE_BYTES * 2 }
val stream = ByteArrayStream(ByteArray(size)) val stream = ByteArrayStream(ByteArray(size))
stringTable.serialize(stream)
properties.forEach { properties.forEach {
stream.writeInt(it.file) stream.writeInt(stringTable.indices[it.file.fqName]!!)
stream.writeInt(stringTable.indices[it.file.path]!!)
} }
return stream.buf return stream.buf
} }
fun deserializeTo(data: ByteArray, result: MutableList<SerializedEagerInitializedFile>) { fun deserializeTo(data: ByteArray, result: MutableList<SerializedEagerInitializedFile>) {
val stream = ByteArrayStream(data) val stream = ByteArrayStream(data)
val stringTable = StringTable.deserialize(stream)
while (stream.hasData()) { while (stream.hasData()) {
val file = stream.readInt() val fileFqName = stringTable[stream.readInt()]
result.add(SerializedEagerInitializedFile(file)) val filePath = stringTable[stream.readInt()]
result.add(SerializedEagerInitializedFile(SerializedFileReference(fileFqName, filePath)))
} }
} }
} }
@@ -488,6 +596,13 @@ internal class KonanIrLinker(
} }
} }
private val fileReferenceToFileDeserializationState by lazy {
fileDeserializationStates.associateBy { SerializedFileReference(it.file.fqName.asString(), it.file.path) }
}
private val SerializedFileReference.deserializationState
get() = fileReferenceToFileDeserializationState[this] ?: error("Unknown file $this")
fun getFileNameOf(declaration: IrDeclaration): String { fun getFileNameOf(declaration: IrDeclaration): String {
fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor] fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor]
@@ -562,8 +677,9 @@ internal class KonanIrLinker(
BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId
} ?: InvalidIndex } ?: InvalidIndex
return SerializedInlineFunctionReference(fileDeserializationState.fileIndex, functionSignature, protoFunction.base.body, return SerializedInlineFunctionReference(SerializedFileReference(fileDeserializationState.file),
irFunction.startOffset, irFunction.endOffset, extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(), functionSignature, protoFunction.base.body, irFunction.startOffset, irFunction.endOffset,
extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(),
valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray()) valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray())
} }
@@ -623,7 +739,7 @@ internal class KonanIrLinker(
val outerThisIndex = fields.indexOfFirst { it.irField?.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS } val outerThisIndex = fields.indexOfFirst { it.irField?.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS }
val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures
return SerializedClassFields( return SerializedClassFields(
fileDeserializationState.fileIndex, SerializedFileReference(fileDeserializationState.file),
BinarySymbolData.decode(protoClass.base.symbol).signatureId, BinarySymbolData.decode(protoClass.base.symbol).signatureId,
typeParameterSigs.toIntArray(), typeParameterSigs.toIntArray(),
outerThisIndex, outerThisIndex,
@@ -660,11 +776,8 @@ internal class KonanIrLinker(
}) })
} }
fun buildEagerInitializedFile(irFile: IrFile): SerializedEagerInitializedFile { fun buildEagerInitializedFile(irFile: IrFile) =
val fileDeserializationState = fileToFileDeserializationState[irFile] SerializedEagerInitializedFile(SerializedFileReference(irFile))
?: error("No file deserializer for ${irFile.render()}")
return SerializedEagerInitializedFile(fileDeserializationState.fileIndex)
}
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl( private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl(
moduleDescriptor, KonanManglerDesc, moduleDescriptor, KonanManglerDesc,
@@ -712,7 +825,7 @@ internal class KonanIrLinker(
private val inlineFunctionReferences by lazy { private val inlineFunctionReferences by lazy {
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
cache.serializedInlineFunctionBodies.associateBy { cache.serializedInlineFunctionBodies.associateBy {
fileDeserializationStates[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature) it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature)
} }
} }
@@ -742,7 +855,7 @@ internal class KonanIrLinker(
?: error("No signature for ${function.render()}") ?: error("No signature for ${function.render()}")
val inlineFunctionReference = inlineFunctionReferences[signature] val inlineFunctionReference = inlineFunctionReferences[signature]
?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}") ?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}")
val fileDeserializationState = fileDeserializationStates[inlineFunctionReference.file] val fileDeserializationState = inlineFunctionReference.file.deserializationState
val declarationDeserializer = fileDeserializationState.declarationDeserializer val declarationDeserializer = fileDeserializationState.declarationDeserializer
val symbolDeserializer = declarationDeserializer.symbolDeserializer val symbolDeserializer = declarationDeserializer.symbolDeserializer
@@ -815,7 +928,7 @@ internal class KonanIrLinker(
private val classesFields by lazy { private val classesFields by lazy {
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
cache.serializedClassFields.associateBy { cache.serializedClassFields.associateBy {
fileDeserializationStates[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature) it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature)
} }
} }
@@ -828,7 +941,7 @@ internal class KonanIrLinker(
?: error("No signature for ${irClass.render()}") ?: error("No signature for ${irClass.render()}")
val serializedClassFields = classesFields[signature] val serializedClassFields = classesFields[signature]
?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}") ?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}")
val fileDeserializationState = fileDeserializationStates[serializedClassFields.file] val fileDeserializationState = serializedClassFields.file.deserializationState
val declarationDeserializer = fileDeserializationState.declarationDeserializer val declarationDeserializer = fileDeserializationState.declarationDeserializer
val symbolDeserializer = declarationDeserializer.symbolDeserializer val symbolDeserializer = declarationDeserializer.symbolDeserializer
@@ -891,7 +1004,7 @@ internal class KonanIrLinker(
val eagerInitializedFiles by lazy { val eagerInitializedFiles by lazy {
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668 val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
cache.serializedEagerInitializedFiles cache.serializedEagerInitializedFiles
.map { fileDeserializationStates[it.file].file } .map { it.file.deserializationState.file }
.distinct() .distinct()
} }