Refactor metadata serialization for using after frontend
for "tight" IC cycle
This commit is contained in:
+15
-102
@@ -5,116 +5,29 @@
|
||||
|
||||
package org.jetbrains.kotlin.metadata.jvm.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.*
|
||||
|
||||
class JvmNameResolver(
|
||||
val types: JvmProtoBuf.StringTableTypes,
|
||||
val strings: Array<String>
|
||||
) : NameResolver {
|
||||
private val localNameIndices = types.localNameList.run { if (isEmpty()) emptySet() else toSet() }
|
||||
strings: Array<String>
|
||||
) : JvmNameResolverBase(
|
||||
strings,
|
||||
types.localNameList.run { if (isEmpty()) emptySet() else toSet() },
|
||||
types.recordList.toExpandedRecordsList()
|
||||
)
|
||||
|
||||
// Here we expand the 'range' field of the Record message for simplicity to a list of records
|
||||
// Note that as an optimization, range of each expanded record is equal to the original range, not 1. If correct ranges are needed,
|
||||
// please use the original record representation in [types.recordList].
|
||||
private val records: List<Record> = ArrayList<Record>().apply {
|
||||
val records = types.recordList
|
||||
this.ensureCapacity(records.size)
|
||||
for (record in records) {
|
||||
// Here we expand the 'range' field of the Record message for simplicity to a list of records
|
||||
// Note that as an optimization, range of each expanded record is equal to the original range, not 1. If correct ranges are needed,
|
||||
// please use the original record representation in [types.recordList].
|
||||
fun List<Record>.toExpandedRecordsList(): List<Record> =
|
||||
ArrayList<Record>().also { list ->
|
||||
list.ensureCapacity(size)
|
||||
for (record in this) {
|
||||
repeat(record.range) {
|
||||
this.add(record)
|
||||
list.add(record)
|
||||
}
|
||||
}
|
||||
this.trimToSize()
|
||||
list.trimToSize()
|
||||
}
|
||||
|
||||
override fun getString(index: Int): String {
|
||||
val record = records[index]
|
||||
|
||||
var string = when {
|
||||
record.hasString() -> record.string
|
||||
record.hasPredefinedIndex() && record.predefinedIndex in PREDEFINED_STRINGS.indices ->
|
||||
PREDEFINED_STRINGS[record.predefinedIndex]
|
||||
else -> strings[index]
|
||||
}
|
||||
|
||||
if (record.substringIndexCount >= 2) {
|
||||
val (begin, end) = record.substringIndexList
|
||||
if (0 <= begin && begin <= end && end <= string.length) {
|
||||
string = string.substring(begin, end)
|
||||
}
|
||||
}
|
||||
|
||||
if (record.replaceCharCount >= 2) {
|
||||
val (from, to) = record.replaceCharList
|
||||
string = string.replace(from.toChar(), to.toChar())
|
||||
}
|
||||
|
||||
when (record.operation ?: NONE) {
|
||||
NONE -> {
|
||||
// Do nothing
|
||||
}
|
||||
INTERNAL_TO_CLASS_ID -> {
|
||||
string = string.replace('$', '.')
|
||||
}
|
||||
DESC_TO_CLASS_ID -> {
|
||||
if (string.length >= 2) {
|
||||
string = string.substring(1, string.length - 1)
|
||||
}
|
||||
string = string.replace('$', '.')
|
||||
}
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
|
||||
override fun getQualifiedClassName(index: Int): String =
|
||||
getString(index)
|
||||
|
||||
override fun isLocalClassName(index: Int): Boolean =
|
||||
index in localNameIndices
|
||||
|
||||
companion object {
|
||||
// Simply "kotlin", but to avoid being renamed by namespace relocation (e.g., Shadow.relocate gradle plugin)
|
||||
private val kotlin = listOf('k', 'o', 't', 'l', 'i', 'n').joinToString(separator = "")
|
||||
|
||||
val PREDEFINED_STRINGS = listOf(
|
||||
"$kotlin/Any",
|
||||
"$kotlin/Nothing",
|
||||
"$kotlin/Unit",
|
||||
"$kotlin/Throwable",
|
||||
"$kotlin/Number",
|
||||
|
||||
"$kotlin/Byte", "$kotlin/Double", "$kotlin/Float", "$kotlin/Int",
|
||||
"$kotlin/Long", "$kotlin/Short", "$kotlin/Boolean", "$kotlin/Char",
|
||||
|
||||
"$kotlin/CharSequence",
|
||||
"$kotlin/String",
|
||||
"$kotlin/Comparable",
|
||||
"$kotlin/Enum",
|
||||
|
||||
"$kotlin/Array",
|
||||
"$kotlin/ByteArray", "$kotlin/DoubleArray", "$kotlin/FloatArray", "$kotlin/IntArray",
|
||||
"$kotlin/LongArray", "$kotlin/ShortArray", "$kotlin/BooleanArray", "$kotlin/CharArray",
|
||||
|
||||
"$kotlin/Cloneable",
|
||||
"$kotlin/Annotation",
|
||||
|
||||
"$kotlin/collections/Iterable", "$kotlin/collections/MutableIterable",
|
||||
"$kotlin/collections/Collection", "$kotlin/collections/MutableCollection",
|
||||
"$kotlin/collections/List", "$kotlin/collections/MutableList",
|
||||
"$kotlin/collections/Set", "$kotlin/collections/MutableSet",
|
||||
"$kotlin/collections/Map", "$kotlin/collections/MutableMap",
|
||||
"$kotlin/collections/Map.Entry", "$kotlin/collections/MutableMap.MutableEntry",
|
||||
|
||||
"$kotlin/collections/Iterator", "$kotlin/collections/MutableIterator",
|
||||
"$kotlin/collections/ListIterator", "$kotlin/collections/MutableListIterator"
|
||||
)
|
||||
|
||||
private val PREDEFINED_STRINGS_MAP = PREDEFINED_STRINGS.withIndex().associateBy({ it.value }, { it.index })
|
||||
|
||||
fun getPredefinedStringIndex(string: String): Int? = PREDEFINED_STRINGS_MAP[string]
|
||||
}
|
||||
}
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.metadata.jvm.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record.Operation.*
|
||||
|
||||
open class JvmNameResolverBase(
|
||||
val strings: Array<String>,
|
||||
private val localNameIndices: Set<Int>,
|
||||
private val records: List<Record>
|
||||
) : NameResolver {
|
||||
|
||||
override fun getString(index: Int): String {
|
||||
val record = records[index]
|
||||
|
||||
var string = when {
|
||||
record.hasString() -> record.string
|
||||
record.hasPredefinedIndex() && record.predefinedIndex in PREDEFINED_STRINGS.indices ->
|
||||
PREDEFINED_STRINGS[record.predefinedIndex]
|
||||
else -> strings[index]
|
||||
}
|
||||
|
||||
if (record.substringIndexCount >= 2) {
|
||||
val (begin, end) = record.substringIndexList
|
||||
if (0 <= begin && begin <= end && end <= string.length) {
|
||||
string = string.substring(begin, end)
|
||||
}
|
||||
}
|
||||
|
||||
if (record.replaceCharCount >= 2) {
|
||||
val (from, to) = record.replaceCharList
|
||||
string = string.replace(from.toChar(), to.toChar())
|
||||
}
|
||||
|
||||
when (record.operation ?: NONE) {
|
||||
NONE -> {
|
||||
// Do nothing
|
||||
}
|
||||
INTERNAL_TO_CLASS_ID -> {
|
||||
string = string.replace('$', '.')
|
||||
}
|
||||
DESC_TO_CLASS_ID -> {
|
||||
if (string.length >= 2) {
|
||||
string = string.substring(1, string.length - 1)
|
||||
}
|
||||
string = string.replace('$', '.')
|
||||
}
|
||||
}
|
||||
|
||||
return string
|
||||
}
|
||||
|
||||
override fun getQualifiedClassName(index: Int): String =
|
||||
getString(index)
|
||||
|
||||
override fun isLocalClassName(index: Int): Boolean =
|
||||
index in localNameIndices
|
||||
|
||||
companion object {
|
||||
// Simply "kotlin", but to avoid being renamed by namespace relocation (e.g., Shadow.relocate gradle plugin)
|
||||
private val kotlin = listOf('k', 'o', 't', 'l', 'i', 'n').joinToString(separator = "")
|
||||
|
||||
val PREDEFINED_STRINGS = listOf(
|
||||
"$kotlin/Any",
|
||||
"$kotlin/Nothing",
|
||||
"$kotlin/Unit",
|
||||
"$kotlin/Throwable",
|
||||
"$kotlin/Number",
|
||||
|
||||
"$kotlin/Byte", "$kotlin/Double", "$kotlin/Float", "$kotlin/Int",
|
||||
"$kotlin/Long", "$kotlin/Short", "$kotlin/Boolean", "$kotlin/Char",
|
||||
|
||||
"$kotlin/CharSequence",
|
||||
"$kotlin/String",
|
||||
"$kotlin/Comparable",
|
||||
"$kotlin/Enum",
|
||||
|
||||
"$kotlin/Array",
|
||||
"$kotlin/ByteArray", "$kotlin/DoubleArray", "$kotlin/FloatArray", "$kotlin/IntArray",
|
||||
"$kotlin/LongArray", "$kotlin/ShortArray", "$kotlin/BooleanArray", "$kotlin/CharArray",
|
||||
|
||||
"$kotlin/Cloneable",
|
||||
"$kotlin/Annotation",
|
||||
|
||||
"$kotlin/collections/Iterable", "$kotlin/collections/MutableIterable",
|
||||
"$kotlin/collections/Collection", "$kotlin/collections/MutableCollection",
|
||||
"$kotlin/collections/List", "$kotlin/collections/MutableList",
|
||||
"$kotlin/collections/Set", "$kotlin/collections/MutableSet",
|
||||
"$kotlin/collections/Map", "$kotlin/collections/MutableMap",
|
||||
"$kotlin/collections/Map.Entry", "$kotlin/collections/MutableMap.MutableEntry",
|
||||
|
||||
"$kotlin/collections/Iterator", "$kotlin/collections/MutableIterator",
|
||||
"$kotlin/collections/ListIterator", "$kotlin/collections/MutableListIterator"
|
||||
)
|
||||
|
||||
private val PREDEFINED_STRINGS_MAP = PREDEFINED_STRINGS.withIndex().associateBy({ it.value }, { it.index })
|
||||
|
||||
fun getPredefinedStringIndex(string: String): Int? = PREDEFINED_STRINGS_MAP[string]
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -5,9 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.metadata.jvm.serialization
|
||||
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.StringTableTypes.Record
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolver
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmNameResolverBase
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.toExpandedRecordsList
|
||||
import org.jetbrains.kotlin.metadata.serialization.StringTable
|
||||
import java.io.OutputStream
|
||||
|
||||
@@ -73,7 +76,7 @@ open class JvmStringTable(nameResolver: JvmNameResolver? = null) : StringTable {
|
||||
if (isLocal || '$' in className) {
|
||||
strings.add(className)
|
||||
} else {
|
||||
val predefinedIndex = JvmNameResolver.getPredefinedStringIndex(className)
|
||||
val predefinedIndex = JvmNameResolverBase.getPredefinedStringIndex(className)
|
||||
if (predefinedIndex != null) {
|
||||
record.predefinedIndex = predefinedIndex
|
||||
// TODO: move all records with predefined names to the end and do not write associated strings for them (since they are ignored)
|
||||
@@ -98,4 +101,11 @@ open class JvmStringTable(nameResolver: JvmNameResolver? = null) : StringTable {
|
||||
build().writeDelimitedTo(output)
|
||||
}
|
||||
}
|
||||
|
||||
fun toNameResolver(): NameResolver =
|
||||
JvmNameResolverBase(
|
||||
strings.toTypedArray(),
|
||||
localNames,
|
||||
records.map { it.build() }.toExpandedRecordsList()
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user