Commonizing klib metadata between native and js
This commit is contained in:
committed by
alexander-gorshenev
parent
f38123e78c
commit
c227c13799
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
+18
-3
@@ -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()
|
||||
+31
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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()
|
||||
+41
@@ -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)) }
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -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
|
||||
}
|
||||
+86
@@ -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
|
||||
|
||||
}
|
||||
+314
@@ -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
|
||||
}
|
||||
+96
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user