[Commonizer] Serialize commonized metadata for KLIB writer

- introduce EmptyDescriptorTable
- wipe out unused BindingContext from KlibMetadataSerializer
This commit is contained in:
Dmitriy Dolovov
2019-12-10 12:46:20 +03:00
parent ce376f49fd
commit 18117ed1f3
7 changed files with 77 additions and 66 deletions
@@ -13,13 +13,21 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.KotlinMangler import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.UniqId import org.jetbrains.kotlin.ir.util.UniqId
class DescriptorTable { interface DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>() fun put(descriptor: DeclarationDescriptor, uniqId: UniqId)
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) { fun get(descriptor: DeclarationDescriptor): Long?
descriptors.getOrPut(descriptor) { uniqId.index }
}
fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor] companion object {
fun createDefault() = object : DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
override fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
descriptors.getOrPut(descriptor) { uniqId.index }
}
override fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor]
}
}
} }
interface UniqIdClashTracker { interface UniqIdClashTracker {
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.isExpectMember import org.jetbrains.kotlin.backend.common.serialization.isExpectMember
import org.jetbrains.kotlin.backend.common.serialization.isSerializableExpectClass import org.jetbrains.kotlin.backend.common.serialization.isSerializableExpectClass
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataSerializer import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataSerializer
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
@@ -19,7 +18,6 @@ import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName 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.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer
@@ -32,7 +30,6 @@ class KlibMetadataIncrementalSerializer(
) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, descriptorTable) { ) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, descriptorTable) {
fun serializePackageFragment( fun serializePackageFragment(
bindingContext: BindingContext,
module: ModuleDescriptor, module: ModuleDescriptor,
scope: Collection<DeclarationDescriptor>, scope: Collection<DeclarationDescriptor>,
fqName: FqName fqName: FqName
@@ -58,7 +55,7 @@ class KlibMetadataIncrementalSerializer(
// This is no always the case, actually. // This is no always the case, actually.
// But marrying split package fragments with incremental compilation is an endeavour. // But marrying split package fragments with incremental compilation is an endeavour.
// See monolithic serializer for details. // See monolithic serializer for details.
return serializeDescriptors(fqName, classifierDescriptors, topLevelDescriptors, bindingContext).single() return serializeDescriptors(fqName, classifierDescriptors, topLevelDescriptors).single()
} }
fun serializedMetadata( fun serializedMetadata(
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
@@ -20,15 +19,10 @@ import org.jetbrains.kotlin.serialization.DescriptorSerializer
class KlibMetadataMonolithicSerializer( class KlibMetadataMonolithicSerializer(
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
metadataVersion: BinaryVersion, metadataVersion: BinaryVersion,
descriptorTable: DescriptorTable, descriptorTable: DescriptorTable
val bindingContext: BindingContext
) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, descriptorTable) { ) : KlibMetadataSerializer(languageVersionSettings, metadataVersion, descriptorTable) {
protected fun serializePackageFragment(fqName: FqName, private fun serializePackageFragment(fqName: FqName, module: ModuleDescriptor): List<ProtoBuf.PackageFragment> {
module: ModuleDescriptor,
bindingContext: BindingContext
):
List<ProtoBuf.PackageFragment> {
// TODO: ModuleDescriptor should be able to return // TODO: ModuleDescriptor should be able to return
// the package only with the contents of that module, without dependencies // the package only with the contents of that module, without dependencies
@@ -48,7 +42,7 @@ class KlibMetadataMonolithicSerializer(
}.filter { !it.isExpectMember } }.filter { !it.isExpectMember }
) )
return serializeDescriptors(fqName, classifierDescriptors, topLevelDescriptors, bindingContext) return serializeDescriptors(fqName, classifierDescriptors, topLevelDescriptors)
} }
fun serializeModule(moduleDescriptor: ModuleDescriptor): SerializedMetadata { fun serializeModule(moduleDescriptor: ModuleDescriptor): SerializedMetadata {
@@ -59,7 +53,7 @@ class KlibMetadataMonolithicSerializer(
for (packageFqName in getPackagesFqNames(moduleDescriptor)) { for (packageFqName in getPackagesFqNames(moduleDescriptor)) {
val packageProtos = val packageProtos =
serializePackageFragment(packageFqName, moduleDescriptor, bindingContext) serializePackageFragment(packageFqName, moduleDescriptor)
if (packageProtos.isEmpty()) continue if (packageProtos.isEmpty()) continue
val packageFqNameStr = packageFqName.asString() val packageFqNameStr = packageFqName.asString()
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.StringTableImpl import org.jetbrains.kotlin.serialization.StringTableImpl
@@ -69,8 +68,7 @@ abstract class KlibMetadataSerializer(
packageProto: ProtoBuf.Package, packageProto: ProtoBuf.Package,
classesProto: List<Pair<ProtoBuf.Class, Int>>, classesProto: List<Pair<ProtoBuf.Class, Int>>,
fqName: FqName, fqName: FqName,
isEmpty: Boolean, isEmpty: Boolean
bindingContext: BindingContext
): ProtoBuf.PackageFragment { ): ProtoBuf.PackageFragment {
val (stringTableProto, nameTableProto) = serializerExtension.stringTable.buildProto() val (stringTableProto, nameTableProto) = serializerExtension.stringTable.buildProto()
@@ -130,8 +128,7 @@ abstract class KlibMetadataSerializer(
protected fun serializeDescriptors( protected fun serializeDescriptors(
fqName: FqName, fqName: FqName,
classifierDescriptors: List<DeclarationDescriptor>, classifierDescriptors: List<DeclarationDescriptor>,
topLevelDescriptors: List<DeclarationDescriptor>, topLevelDescriptors: List<DeclarationDescriptor>
bindingContext: BindingContext
): List<ProtoBuf.PackageFragment> { ): List<ProtoBuf.PackageFragment> {
if (TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE == null && if (TOP_LEVEL_CLASS_DECLARATION_COUNT_PER_FILE == null &&
@@ -151,8 +148,7 @@ abstract class KlibMetadataSerializer(
packageProto, packageProto,
serializeClasses(fqName, classifierDescriptors), serializeClasses(fqName, classifierDescriptors),
fqName, fqName,
topLevelDescriptors.isEmpty() && classifierDescriptors.isEmpty(), topLevelDescriptors.isEmpty() && classifierDescriptors.isEmpty()
bindingContext
) )
} }
) )
@@ -178,8 +174,7 @@ abstract class KlibMetadataSerializer(
packageProto, packageProto,
classesProto, classesProto,
fqName, fqName,
descriptors.isEmpty(), descriptors.isEmpty()
bindingContext
) )
} }
} }
@@ -190,8 +185,7 @@ abstract class KlibMetadataSerializer(
buildPackageProto(fqName, descriptors), buildPackageProto(fqName, descriptors),
emptyList(), emptyList(),
fqName, fqName,
descriptors.isEmpty(), descriptors.isEmpty()
bindingContext
) )
} }
} }
@@ -202,8 +196,7 @@ abstract class KlibMetadataSerializer(
emptyPackageProto(), emptyPackageProto(),
emptyList(), emptyList(),
fqName, fqName,
true, true
bindingContext
) )
} }
} }
@@ -345,7 +345,7 @@ fun serializeModuleIntoKlib(
) { ) {
assert(files.size == moduleFragment.files.size) assert(files.size == moduleFragment.files.size)
val descriptorTable = DescriptorTable() val descriptorTable = DescriptorTable.createDefault()
val serializedIr = val serializedIr =
JsIrModuleSerializer(emptyLoggingContext, moduleFragment.irBuiltins, descriptorTable).serializedIrModule(moduleFragment) JsIrModuleSerializer(emptyLoggingContext, moduleFragment.irBuiltins, descriptorTable).serializedIrModule(moduleFragment)
@@ -361,7 +361,6 @@ fun serializeModuleIntoKlib(
fun serializeScope(fqName: FqName, memberScope: Collection<DeclarationDescriptor>): ByteArray { fun serializeScope(fqName: FqName, memberScope: Collection<DeclarationDescriptor>): ByteArray {
return metadataSerializer.serializePackageFragment( return metadataSerializer.serializePackageFragment(
bindingContext,
moduleDescriptor, moduleDescriptor,
memberScope, memberScope,
fqName fqName
+2 -1
View File
@@ -15,7 +15,8 @@ val mavenCompileScope by configurations.creating {
description = "Kotlin/Native library commonizer" description = "Kotlin/Native library commonizer"
dependencies { dependencies {
compileOnly(project(":compiler:frontend")) { isTransitive = true } compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:ir.serialization.common"))
// This dependency is necessary to keep the right dependency record inside of POM file: // This dependency is necessary to keep the right dependency record inside of POM file:
mavenCompileScope(project(":kotlin-compiler")) mavenCompileScope(project(":kotlin-compiler"))
@@ -5,10 +5,15 @@
package org.jetbrains.kotlin.descriptors.commonizer package org.jetbrains.kotlin.descriptors.commonizer
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.commonizer.ModuleForCommonization.DeserializedModule import org.jetbrains.kotlin.descriptors.commonizer.ModuleForCommonization.DeserializedModule
import org.jetbrains.kotlin.descriptors.commonizer.ModuleForCommonization.SyntheticModule import org.jetbrains.kotlin.descriptors.commonizer.ModuleForCommonization.SyntheticModule
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.ir.util.UniqId
import org.jetbrains.kotlin.konan.library.* import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.library.KonanFactories.DefaultDeserializedDescriptorFactory import org.jetbrains.kotlin.konan.library.KonanFactories.DefaultDeserializedDescriptorFactory
import org.jetbrains.kotlin.konan.properties.propertyList import org.jetbrains.kotlin.konan.properties.propertyList
@@ -188,30 +193,45 @@ private fun saveModules(
.associate { it.module.name to it.data } .associate { it.module.name to it.data }
} }
val serializer = KlibMetadataMonolithicSerializer(
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
metadataVersion = KlibMetadataVersion.INSTANCE,
descriptorTable = EmptyDescriptorTable
)
val stdlibName = Name.special("<$KONAN_STDLIB_NAME>") val stdlibName = Name.special("<$KONAN_STDLIB_NAME>")
result.concreteTargets.forEach { target -> fun serializeTarget(target: Target) {
val konanTarget = target.konanTarget!! val libsDestination: File
val targetLibsDestination = destination.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(konanTarget.name) val newModulesManifestData: Map<Name, SensitiveManifestData>
when (target) {
is InputTarget -> {
libsDestination = destination.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.konanTarget!!.name)
newModulesManifestData = originalModulesManifestData.getValue(target)
}
is OutputTarget -> {
libsDestination = destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
newModulesManifestData = originalModulesManifestData.values.first() // just take the first one
}
}
val newModulesManifestData = originalModulesManifestData.getValue(target)
val newModules = result.modulesByTargets.getValue(target) val newModules = result.modulesByTargets.getValue(target)
for (newModule in newModules) { for (newModule in newModules) {
val libraryName = newModule.name val libraryName = newModule.name
if (libraryName == stdlibName || libraryName == FORWARD_DECLARATIONS_MODULE_NAME) continue if (libraryName == stdlibName || libraryName == FORWARD_DECLARATIONS_MODULE_NAME) continue
// TODO: obtain serialization data val metadata = serializer.serializeModule(newModule)
// val metadata = TODO()
val manifestData = newModulesManifestData.getValue(newModule.name) val manifestData = newModulesManifestData.getValue(newModule.name)
val libraryDestination = targetLibsDestination.resolve(libraryName.asString().trimStart('<').trimEnd('>')) val libraryDestination = libsDestination.resolve(libraryName.asString().trimStart('<').trimEnd('>'))
// writeLibrary(metadata, manifestData, libraryDestination) writeLibrary(metadata, manifestData, libraryDestination)
println("$manifestData - $libraryDestination")
} }
} }
TODO("serialize common target") result.concreteTargets.forEach(::serializeTarget)
result.commonTarget.let(::serializeTarget)
} }
private sealed class ModuleForCommonization(val module: ModuleDescriptorImpl) { private sealed class ModuleForCommonization(val module: ModuleDescriptorImpl) {
@@ -237,26 +257,18 @@ private data class SensitiveManifestData(
// note: versions can't be added here // note: versions can't be added here
if (dependencies.isNotEmpty()) fun addOptionalProperty(name: String, condition: Boolean, value: () -> String) =
library.manifestProperties[KLIB_PROPERTY_DEPENDS] = dependencies.joinToString(separator = " ") if (condition)
else library.manifestProperties[name] = value()
library.manifestProperties.remove(KLIB_PROPERTY_DEPENDS) else
library.manifestProperties.remove(name)
if (isInterop) addOptionalProperty(KLIB_PROPERTY_DEPENDS, dependencies.isNotEmpty()) { dependencies.joinToString(separator = " ") }
library.manifestProperties[KLIB_PROPERTY_INTEROP] = "true" addOptionalProperty(KLIB_PROPERTY_INTEROP, isInterop) { "true" }
else addOptionalProperty(KLIB_PROPERTY_PACKAGE, packageFqName != null) { packageFqName!! }
library.manifestProperties.remove(KLIB_PROPERTY_INTEROP) addOptionalProperty(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS, exportForwardDeclarations.isNotEmpty()) {
exportForwardDeclarations.joinToString(separator = " ")
if (packageFqName != null) }
library.manifestProperties[KLIB_PROPERTY_PACKAGE] = packageFqName
else
library.manifestProperties.remove(KLIB_PROPERTY_PACKAGE)
if (exportForwardDeclarations.isNotEmpty())
library.manifestProperties[KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS] =
exportForwardDeclarations.joinToString(separator = " ")
else
library.manifestProperties.remove(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS)
} }
companion object { companion object {
@@ -271,12 +283,19 @@ private data class SensitiveManifestData(
} }
} }
private object EmptyDescriptorTable : DescriptorTable {
private const val DEFAULT_UNIQ_ID_INDEX = 0L
override fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) = error("unsupported")
override fun get(descriptor: DeclarationDescriptor): Long = DEFAULT_UNIQ_ID_INDEX
}
private fun writeLibrary( private fun writeLibrary(
metadata: SerializedMetadata, metadata: SerializedMetadata,
manifestData: SensitiveManifestData, manifestData: SensitiveManifestData,
destination: File destination: File
) { ) {
val library = KoltinLibraryWriterImpl(KFile(destination.path), manifestData.uniqueName, manifestData.versions, nopack = false) val library = KoltinLibraryWriterImpl(KFile(destination.path), manifestData.uniqueName, manifestData.versions, nopack = true)
library.addMetadata(metadata) library.addMetadata(metadata)
manifestData.applyTo(library.base as BaseWriterImpl) manifestData.applyTo(library.base as BaseWriterImpl)
library.commit() library.commit()