Commonizing klib metadata between native and js

This commit is contained in:
Alexander Gorshenev
2019-07-26 14:45:18 +03:00
committed by alexander-gorshenev
parent f38123e78c
commit c227c13799
98 changed files with 3265 additions and 7848 deletions
@@ -5,9 +5,19 @@ plugins {
dependencies {
// TODO: decouple from backend.common
compile(project(":compiler:frontend"))
compile(project(":compiler:ir.backend.common"))
compile(project(":compiler:ir.tree"))
compile(project(":compiler:serialization"))
compile(project(":kotlin-util-klib"))
compile(project(":kotlin-util-klib-metadata"))
compile(project(":compiler:util"))
compile(project(":compiler:ir.psi2ir"))
compile(project(":compiler:ir.backend.common"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
}
sourceSets {
@@ -14,8 +14,8 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
// This is all information needed to find a descriptor in the
// tree of deserialized descriptors. Think of it as base + offset.
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.descriptors.*
//import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataProtoBuf
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.backend.common.serialization.proto.UniqId as ProtoUniqId
// This is an abstract uniqIdIndex any serialized IR declarations gets.
@@ -35,4 +37,17 @@ interface DescriptorUniqIdAware {
fun DeclarationDescriptor.getUniqId(): Long?
}
//val UniqId.declarationFileName: String get() = "$index${if (isLocal) "L" else "G"}.kjd"
object DeserializedDescriptorUniqIdAware : DescriptorUniqIdAware {
override fun DeclarationDescriptor.getUniqId(): Long? = when (this) {
is DeserializedClassDescriptor -> this.classProto.tryGetExtension(KlibMetadataProtoBuf.classUniqId)
is DeserializedSimpleFunctionDescriptor -> this.proto.tryGetExtension(KlibMetadataProtoBuf.functionUniqId)
is DeserializedPropertyDescriptor -> this.proto.tryGetExtension(KlibMetadataProtoBuf.propertyUniqId)
is DeserializedClassConstructorDescriptor -> this.proto.tryGetExtension(KlibMetadataProtoBuf.constructorUniqId)
is DeserializedTypeParameterDescriptor -> this.proto.tryGetExtension(KlibMetadataProtoBuf.typeParamUniqId)
is DeserializedTypeAliasDescriptor -> this.proto.tryGetExtension(KlibMetadataProtoBuf.typeAliasUniqId)
else -> null
}?.index
}
fun newDescriptorUniqId(index: Long): KlibMetadataProtoBuf.DescriptorUniqId =
KlibMetadataProtoBuf.DescriptorUniqId.newBuilder().setIndex(index).build()
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2019 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.backend.common.serialization.metadata
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker
import org.jetbrains.kotlin.types.createDynamicType
import org.jetbrains.kotlin.types.typeUtil.builtIns
object DynamicTypeDeserializer : FlexibleTypeDeserializer {
const val id = "kotlin.DynamicType"
override fun create(proto: ProtoBuf.Type, flexibleId: String, lowerBound: SimpleType, upperBound: SimpleType): KotlinType {
if (flexibleId != id) return ErrorUtils.createErrorType("Unexpected id: $flexibleId. ($lowerBound..$upperBound)")
return if (StrictEqualityTypeChecker.strictEqualTypes(lowerBound, lowerBound.builtIns.nothingType) &&
StrictEqualityTypeChecker.strictEqualTypes(upperBound, upperBound.builtIns.nullableAnyType)
) {
createDynamicType(lowerBound.builtIns)
} else {
ErrorUtils.createErrorType("Illegal type range for dynamic type: $lowerBound..$upperBound")
}
}
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2019 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.ir.backend.js.lower.serialization.metadata
import org.jetbrains.kotlin.library.metadata.KlibMetadataPackageFragment
import org.jetbrains.kotlin.psi.KtFile
sealed class KlibFileMetadata
data class KotlinPsiFileMetadata(val ktFile: KtFile) : KlibFileMetadata()
data class KotlinDeserializedFileMetadata(
val packageFragment: KlibMetadataPackageFragment,
val fileId: Int
) : KlibFileMetadata()
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2019 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.ir.backend.js.lower.serialization.metadata
import org.jetbrains.kotlin.backend.common.serialization.metadata.extractFileId
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.library.metadata.KlibMetadataPackageFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
class KlibMetadataFileRegistry {
private val fileIdsImpl = mutableMapOf<KlibFileMetadata, Int>()
fun lookup(file: KlibFileMetadata) = fileIdsImpl.getOrPut(file) { fileIdsImpl.size }
val fileIds: Map<KlibFileMetadata, Int>
get() = fileIdsImpl
fun getFileId(descriptor: DeclarationDescriptor): Int? {
if (!DescriptorUtils.isTopLevelDeclaration(descriptor) || descriptor !is DeclarationDescriptorWithSource) return null
val fileId = descriptor.extractFileId()
if (fileId != null) {
(descriptor.containingDeclaration as? KlibMetadataPackageFragment)?.let { packageFragment ->
return this.lookup(KotlinDeserializedFileMetadata(packageFragment, fileId))
}
}
val file = descriptor.source.containingFile as? PsiSourceFile ?: return null
val psiFile = file.psiFile
return (psiFile as? KtFile)?.let { this.lookup(KotlinPsiFileMetadata(it)) }
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 2010-2019 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.ir.backend.js.lower.serialization.metadata
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.isExpectMember
import org.jetbrains.kotlin.backend.common.serialization.isSerializableExpectClass
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataSerializer
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.DescriptorSerializer
// TODO: need a refactoring between IncrementalSerializer and MonolithicSerializer.
class KlibMetadataIncrementalSerializer(
languageVersionSettings: LanguageVersionSettings,
metadataVersion: BinaryVersion,
descriptorTable: DescriptorTable
) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, descriptorTable) {
fun serializePackageFragment(
bindingContext: BindingContext,
module: ModuleDescriptor,
scope: Collection<DeclarationDescriptor>,
fqName: FqName
): ProtoBuf.PackageFragment {
val allDescriptors = scope.filter {
it.module == module
}
val classifierDescriptors = allDescriptors
.filterIsInstance<ClassifierDescriptor>()
.filter { !it.isExpectMember || it.isSerializableExpectClass }
.sortedBy { it.fqNameSafe.asString() }
val topLevelDescriptors = DescriptorSerializer.sort(
allDescriptors
.filterIsInstance<CallableDescriptor>()
.filter { !it.isExpectMember }
)
// TODO: For now, in the incremental serializer, we assume
// there is only a single package fragment per file.
// This is no always the case, actually.
// But marrying split package fragments with incremental compilation is an endeavour.
// See monolithic serializer for details.
return serializeDescriptors(fqName, classifierDescriptors, topLevelDescriptors, bindingContext).single()
}
fun serializedMetadata(
fragments: Map<String, List<ByteArray>>,
header: ByteArray
): SerializedMetadata {
val fragmentNames = mutableListOf<String>()
val fragmentParts = mutableListOf<List<ByteArray>>()
for ((fqName, fragment) in fragments.entries.sortedBy { it.key }) {
fragmentNames += fqName
fragmentParts += fragment
}
return SerializedMetadata(header, fragmentParts, fragmentNames)
}
// TODO: For now, in the incremental serializer, we assume
// there is only a single package fragment per file.
// This is no always the case, actually.
// But marrying split package fragments with incremental compilation is an endeavour.
// See monolithic serializer for details.
override val TOP_LEVEL_DECLARATION_COUNT_PER_FILE = null
override val TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE = null
}
@@ -0,0 +1,86 @@
package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.isExpectMember
import org.jetbrains.kotlin.backend.common.serialization.isSerializableExpectClass
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.serialization.DescriptorSerializer
// TODO: need a refactoring between IncrementalSerializer and MonolithicSerializer.
class KlibMetadataMonolithicSerializer(
languageVersionSettings: LanguageVersionSettings,
metadataVersion: BinaryVersion,
descriptorTable: DescriptorTable,
val bindingContext: BindingContext
) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, descriptorTable) {
protected fun serializePackageFragment(fqName: FqName,
module: ModuleDescriptor,
bindingContext: BindingContext
):
List<ProtoBuf.PackageFragment> {
// TODO: ModuleDescriptor should be able to return
// the package only with the contents of that module, without dependencies
val fragments = module.getPackage(fqName).fragments.filter { it.module == module }
if (fragments.isEmpty()) return emptyList()
val classifierDescriptors = DescriptorSerializer.sort(
fragments.flatMap {
it.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.CLASSIFIERS)
}.filter { !it.isExpectMember || it.isSerializableExpectClass }
)
val topLevelDescriptors = DescriptorSerializer.sort(
fragments.flatMap { fragment ->
fragment.getMemberScope().getDescriptorsFiltered(DescriptorKindFilter.CALLABLES)
}.filter { !it.isExpectMember }
)
return serializeDescriptors(fqName, classifierDescriptors, topLevelDescriptors, bindingContext)
}
fun serializeModule(moduleDescriptor: ModuleDescriptor): SerializedMetadata {
val fragments = mutableListOf<List<ByteArray>>()
val fragmentNames = mutableListOf<String>()
val emptyPackages = mutableListOf<String>()
for (packageFqName in getPackagesFqNames(moduleDescriptor)) {
val packageProtos =
serializePackageFragment(packageFqName, moduleDescriptor, bindingContext)
if (packageProtos.isEmpty()) continue
val packageFqNameStr = packageFqName.asString()
if (packageProtos.all { it.getExtension(KlibMetadataProtoBuf.isEmpty)}) {
emptyPackages.add(packageFqNameStr)
}
fragments.add(packageProtos.map { it.toByteArray() })
fragmentNames.add(packageFqNameStr)
}
val header = serializeHeader(moduleDescriptor, fragmentNames, emptyPackages)
val libraryAsByteArray = header.toByteArray()
return SerializedMetadata(libraryAsByteArray, fragments, fragmentNames)
}
// For platform libraries we get HUGE files.
// Indexing them in IDEA takes ages.
// So we split them into chunks.
override val TOP_LEVEL_DECLARATION_COUNT_PER_FILE = 128
override val TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE = 64
}
@@ -0,0 +1,314 @@
/*
* Copyright 2010-2019 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.backend.common.serialization.metadata
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.newDescriptorUniqId
import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KlibMetadataFileRegistry
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KotlinPsiFileMetadata
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.filterOutSourceAnnotations
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.AnnotationSerializer
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.StringTableImpl
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
internal fun <T, R> Iterable<T>.maybeChunked(size: Int?, transform: (List<T>) -> R): List<R>
= size?.let { this.chunked(size, transform) } ?: listOf(transform(this.toList()))
abstract class KlibMetadataSerializer(
val languageVersionSettings: LanguageVersionSettings,
val metadataVersion: BinaryVersion,
val descriptorTable: DescriptorTable
) {
val fileRegistry = KlibMetadataFileRegistry()
lateinit var serializerContext: SerializerContext
data class SerializerContext(
val serializerExtension: KlibMetadataSerializerExtension,
val topSerializer: DescriptorSerializer,
var classSerializer: DescriptorSerializer = topSerializer
)
fun declarationTableHandler(declarationDescriptor: DeclarationDescriptor): KlibMetadataProtoBuf.DescriptorUniqId {
val index = descriptorTable.get(declarationDescriptor) ?: error("No descriptor ID found for $declarationDescriptor")
return index.let { newDescriptorUniqId(it) }
}
protected fun createNewContext(): SerializerContext {
val extension = KlibMetadataSerializerExtension(
languageVersionSettings,
metadataVersion,
::declarationTableHandler,
{descriptor -> fileRegistry.getFileId(descriptor) } ,
KlibMetadataStringTable()
)
return SerializerContext(
extension,
DescriptorSerializer.createTopLevel(extension)
)
}
protected inline fun <T> withNewContext(crossinline block: SerializerContext.() -> T): T {
serializerContext = createNewContext()
return with(serializerContext, block)
}
private fun SerializerContext.buildFragment(
packageProto: ProtoBuf.Package,
classesProto: List<Pair<ProtoBuf.Class, Int>>,
fqName: FqName,
isEmpty: Boolean,
bindingContext: BindingContext
): ProtoBuf.PackageFragment {
val (stringTableProto, nameTableProto) = serializerExtension.stringTable.buildProto()
// TODO: we place files table to each and every fragment.
// Need to refactor it out sonehow.
val files = serializeFiles(fileRegistry, bindingContext, AnnotationSerializer(serializerExtension.stringTable))
return ProtoBuf.PackageFragment.newBuilder()
.setPackage(packageProto)
.addAllClass_(classesProto.map { it.first })
.setStrings(stringTableProto)
.setQualifiedNames(nameTableProto)
.also { packageFragment ->
classesProto.forEach {
packageFragment.addExtension(KlibMetadataProtoBuf.className, it.second )
}
packageFragment.setExtension(KlibMetadataProtoBuf.packageFragmentFiles, files)
packageFragment.setExtension(KlibMetadataProtoBuf.isEmpty, isEmpty)
packageFragment.setExtension(KlibMetadataProtoBuf.fqName, fqName.asString())
}
.build()
}
private fun serializeClass(packageName: FqName,
classDescriptor: ClassDescriptor): List<Pair<ProtoBuf.Class, Int>> {
with(serializerContext) {
val previousSerializer = classSerializer
classSerializer = DescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer)
val classProto = classSerializer.classProto(classDescriptor).build() ?: error("Class not serialized: $classDescriptor")
//builder.addClass(classProto)
val index = classSerializer.stringTable.getFqNameIndex(classDescriptor)
//builder.addExtension(KlibMetadataProtoBuf.className, index)
val classes = serializeClasses(packageName/*, builder*/,
classDescriptor.unsubstitutedInnerClassesScope
.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS))
classSerializer = previousSerializer
return classes + Pair(classProto, index)
}
}
protected fun serializeClasses(packageName: FqName,
//builder: ProtoBuf.PackageFragment.Builder,
descriptors: Collection<DeclarationDescriptor>): List<Pair<ProtoBuf.Class, Int>> {
return descriptors.filterIsInstance<ClassDescriptor>().flatMap {
serializeClass(packageName, /*builder, */it)
}
}
private fun emptyPackageProto(): ProtoBuf.Package = ProtoBuf.Package.newBuilder().build()
private fun SerializerContext.buildPackageProto(
fqName: FqName,
descriptors: List<DeclarationDescriptor>) = topSerializer.packagePartProto(fqName, descriptors).build()
?: error("Package fragments not serialized: for $descriptors")
protected fun serializeDescriptors(
fqName: FqName,
classifierDescriptors: List<DeclarationDescriptor>,
topLevelDescriptors: List<DeclarationDescriptor>,
bindingContext: BindingContext
): List<ProtoBuf.PackageFragment> {
if (TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE == null &&
TOP_LEVEL_DECLARATION_COUNT_PER_FILE == null) {
val typeAliases = classifierDescriptors.filterIsInstance<TypeAliasDescriptor>()
val nonCassDescriptors = topLevelDescriptors+typeAliases
return listOf(withNewContext {
val packageProto = if (nonCassDescriptors.isEmpty())
emptyPackageProto()
else
buildPackageProto(fqName, nonCassDescriptors)
buildFragment(
packageProto,
serializeClasses(fqName, classifierDescriptors),
fqName,
topLevelDescriptors.isEmpty() && classifierDescriptors.isEmpty(),
bindingContext
)
}
)
}
val result = mutableListOf<ProtoBuf.PackageFragment>()
result += classifierDescriptors.maybeChunked(TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE) { descriptors ->
withNewContext {
//val classesProto = buildClassesProto { classesBuilder ->
// serializeClasses(fqName, classesBuilder, descriptors)
//}
val classesProto = serializeClasses(fqName, descriptors)
val typeAliases = descriptors.filterIsInstance<TypeAliasDescriptor>()
val packageProto =
if (typeAliases.isNotEmpty()) buildPackageProto(fqName, typeAliases)
else emptyPackageProto()
buildFragment(
packageProto,
classesProto,
fqName,
descriptors.isEmpty(),
bindingContext
)
}
}
result += topLevelDescriptors.maybeChunked(TOP_LEVEL_DECLARATION_COUNT_PER_FILE) { descriptors ->
withNewContext {
buildFragment(
buildPackageProto(fqName, descriptors),
emptyList(),
fqName,
descriptors.isEmpty(),
bindingContext
)
}
}
if (result.isEmpty()) {
result += withNewContext {
buildFragment(
emptyPackageProto(),
emptyList(),
fqName,
true,
bindingContext
)
}
}
return result
}
private fun serializeFiles(
fileRegistry: KlibMetadataFileRegistry,
bindingContext: BindingContext,
serializer: AnnotationSerializer
): KlibMetadataProtoBuf.Files {
val filesProto = KlibMetadataProtoBuf.Files.newBuilder()
for ((file, id) in fileRegistry.fileIds.entries.sortedBy { it.value }) {
val fileProto = KlibMetadataProtoBuf.File.newBuilder()
if (id != filesProto.fileCount) {
fileProto.id = id
}
val annotations = when (file) {
is KotlinPsiFileMetadata -> file.ktFile.annotationEntries.map { bindingContext[BindingContext.ANNOTATION, it]!! }
//is KotlinDeserializedFileMetadata -> file.packageFragment.fileMap[file.fileId]!!.annotations
else -> TODO("support other file types")
}
for (annotation in annotations.filterOutSourceAnnotations()) {
fileProto.addAnnotation(serializer.serializeAnnotation(annotation))
}
val name = when (file) {
is KotlinPsiFileMetadata -> file.ktFile.getName()
else -> TODO("support other file types")
}
fileProto.name = name
filesProto.addFile(fileProto)
}
return filesProto.build()
}
protected fun getPackagesFqNames(module: ModuleDescriptor): Set<FqName> {
val result = mutableSetOf<FqName>()
fun getSubPackages(fqName: FqName) {
result.add(fqName)
module.getSubPackagesOf(fqName) { true }.forEach { getSubPackages(it) }
}
getSubPackages(FqName.ROOT)
return result
}
fun serializeHeader(
moduleDescriptor: ModuleDescriptor,
fragmentNames: List<String>,
emptyPackages: List<String> = emptyList()
): KlibMetadataProtoBuf.Header {
val header = KlibMetadataProtoBuf.Header.newBuilder()
header.moduleName = moduleDescriptor.name.asString()
if (languageVersionSettings.isPreRelease()) {
header.flags = 1
}
val experimentalAnnotationFqNames = languageVersionSettings.getFlag(AnalysisFlags.experimental)
if (experimentalAnnotationFqNames.isNotEmpty()) {
val stringTable = StringTableImpl()
for (fqName in experimentalAnnotationFqNames) {
val descriptor = moduleDescriptor.resolveClassByFqName(FqName(fqName), NoLookupLocation.FOR_ALREADY_TRACKED) ?: continue
header.addAnnotation(ProtoBuf.Annotation.newBuilder().apply {
id = stringTable.getFqNameIndex(descriptor)
})
}
val (strings, qualifiedNames) = stringTable.buildProto()
header.strings = strings
header.qualifiedNames = qualifiedNames
}
fragmentNames.forEach {
header.addPackageFragmentName(it)
}
emptyPackages.forEach {
header.addEmptyPackage(it)
}
return header.build()
}
// For platform libraries we get HUGE files.
// Indexing them in IDEA takes ages.
// So we split them into chunks.
abstract protected val TOP_LEVEL_DECLARATION_COUNT_PER_FILE: Int?
abstract protected val TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE: Int?
}
fun DeclarationDescriptor.extractFileId(): Int? = when (this) {
is DeserializedClassDescriptor -> classProto.getExtension(KlibMetadataProtoBuf.classFile)
is DeserializedSimpleFunctionDescriptor -> proto.getExtension(KlibMetadataProtoBuf.functionFile)
is DeserializedPropertyDescriptor -> proto.getExtension(KlibMetadataProtoBuf.propertyFile)
else -> null
}
@@ -0,0 +1,96 @@
/*
* Copyright 2010-2019 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.backend.common.serialization.metadata
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase
import org.jetbrains.kotlin.serialization.StringTableImpl
import org.jetbrains.kotlin.types.FlexibleType
class KlibMetadataSerializerExtension(
private val languageVersionSettings: LanguageVersionSettings,
override val metadataVersion: BinaryVersion,
val declarationTableHandler: (DeclarationDescriptor) -> KlibMetadataProtoBuf.DescriptorUniqId?,
val descriptorFileId: (DeclarationDescriptor) -> Int?,
override val stringTable: StringTableImpl
) : KotlinSerializerExtensionBase(KlibMetadataSerializerProtocol) {
override fun shouldUseTypeTable(): Boolean = true
override fun serializeFlexibleType(flexibleType: FlexibleType, lowerProto: ProtoBuf.Type.Builder, upperProto: ProtoBuf.Type.Builder) {
lowerProto.flexibleTypeCapabilitiesId = stringTable.getStringIndex(DynamicTypeDeserializer.id)
}
private fun uniqId(descriptor: DeclarationDescriptor): KlibMetadataProtoBuf.DescriptorUniqId? {
return declarationTableHandler(descriptor)
}
override fun serializeTypeParameter(typeParameter: TypeParameterDescriptor, proto: ProtoBuf.TypeParameter.Builder) {
uniqId(typeParameter)?.let { proto.setExtension(KlibMetadataProtoBuf.typeParamUniqId, it) }
super.serializeTypeParameter(typeParameter, proto)
}
override fun serializeTypeAlias(typeAlias: TypeAliasDescriptor, proto: ProtoBuf.TypeAlias.Builder) {
uniqId(typeAlias)?.let { proto.setExtension(KlibMetadataProtoBuf.typeAliasUniqId, it) }
super.serializeTypeAlias(typeAlias, proto)
}
override fun serializeEnumEntry(descriptor: ClassDescriptor, proto: ProtoBuf.EnumEntry.Builder) {
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.enumEntryUniqId, it) }
super.serializeEnumEntry(descriptor, proto)
}
override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.constructorUniqId, it) }
super.serializeConstructor(descriptor, proto, childSerializer)
}
override fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.classUniqId, it) }
descriptorFileId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.classFile, it) }
super.serializeClass(descriptor, proto, versionRequirementTable, childSerializer)
childSerializer.typeTable.serialize()?.let { proto.mergeTypeTable(it) }
}
override fun serializeProperty(
descriptor: PropertyDescriptor,
proto: ProtoBuf.Property.Builder,
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.propertyUniqId, it) }
descriptorFileId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.propertyFile, it) }
super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer)
}
override fun serializeFunction(
descriptor: FunctionDescriptor,
proto: ProtoBuf.Function.Builder,
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.functionUniqId, it) }
descriptorFileId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.functionFile, it) }
super.serializeFunction(descriptor, proto, versionRequirementTable, childSerializer)
}
override fun releaseCoroutines() =
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
}