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
@@ -33,7 +33,11 @@ import org.jetbrains.kotlin.js.config.EcmaVersion
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding
import org.jetbrains.kotlin.library.resolver.impl.libraryResolver
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.KotlinLibrarySearchPathResolver
import org.jetbrains.kotlin.library.UnresolvedLibrary
import org.jetbrains.kotlin.library.toUnresolvedLibraries
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind
@@ -138,20 +142,21 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
// TODO: Handle non-empty main call arguments
val mainCallArguments = if (K2JsArgumentConstants.NO_CALL == arguments.main) null else emptyList<String>()
val loadedLibrariesNames = mutableSetOf<String>()
val dependencies = mutableListOf<KotlinLibrary>()
val friendDependencies = mutableListOf<KotlinLibrary>()
for (library in libraries) {
val irLib = loadKlib(library)
if (irLib.moduleName !in loadedLibrariesNames) {
dependencies.add(irLib)
loadedLibrariesNames.add(irLib.moduleName)
if (library in friendLibraries) {
friendDependencies.add(irLib)
}
val unresolvedLibraries = libraries.toUnresolvedLibraries
// Configure resolver to only understands absolute path libraries.
val libraryResolver = KotlinLibrarySearchPathResolver<KotlinLibrary>(
repositories = emptyList(),
directLibs = libraries,
distributionKlib = null,
localKotlinDir = null,
skipCurrentDir = true
// TODO: pass logger attached to message collector here.
).libraryResolver()
val resolvedLibraries = libraryResolver.resolveWithDependencies(unresolvedLibraries, true, true, true)
val friendDependencies = resolvedLibraries.getFullList()
.filter {
it.moduleName in friendLibraries
}
}
val produceKind = produceMap[arguments.irProduceOnly]
if (produceKind == null) {
@@ -169,7 +174,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
project = config.project,
files = sourcesFiles,
configuration = config.configuration,
allDependencies = dependencies,
allDependencies = resolvedLibraries,
friendDependencies = friendDependencies,
outputKlibPath = outputKlibPath,
nopack = arguments.irLegacyGradlePluginCompatibility
@@ -184,7 +189,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
sourcesFiles,
configuration,
phaseConfig,
allDependencies = dependencies,
allDependencies = resolvedLibraries,
friendDependencies = friendDependencies,
mainArguments = mainCallArguments
)
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.config.CompilerConfiguration
@@ -28,7 +29,7 @@ fun compile(
files: List<KtFile>,
configuration: CompilerConfiguration,
phaseConfig: PhaseConfig,
allDependencies: List<KotlinLibrary>,
allDependencies: KotlinLibraryResolveResult,
friendDependencies: List<KotlinLibrary>,
mainArguments: List<String>?,
exportedDeclarations: Set<FqName> = emptySet()
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.wasm
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.backend.wasm.codegen.IrModuleToWasm
@@ -24,7 +25,7 @@ fun compileWasm(
files: List<KtFile>,
configuration: CompilerConfiguration,
phaseConfig: PhaseConfig,
allDependencies: List<KotlinLibrary>,
allDependencies: KotlinLibraryResolveResult,
friendDependencies: List<KotlinLibrary>,
exportedDeclarations: Set<FqName> = emptySet()
): WasmCompilerResult {
@@ -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()
@@ -3,7 +3,7 @@
* 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
package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
@@ -5,13 +5,14 @@
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 JsKlibFileMetadata
sealed class KlibFileMetadata
data class KotlinPsiFileMetadata(val ktFile: KtFile) : JsKlibFileMetadata()
data class KotlinPsiFileMetadata(val ktFile: KtFile) : KlibFileMetadata()
data class KotlinDeserializedFileMetadata(
val packageFragment: JsKlibMetadataPackageFragment,
val packageFragment: KlibMetadataPackageFragment,
val fileId: Int
) : JsKlibFileMetadata()
) : 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
}
@@ -3,56 +3,57 @@
* 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
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.psi.KtFile
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
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 JsKlibMetadataSerializerExtension(
private val fileRegistry: JsKlibMetadataFileRegistry,
class KlibMetadataSerializerExtension(
private val languageVersionSettings: LanguageVersionSettings,
override val metadataVersion: BinaryVersion,
val declarationTableHandler: ((DeclarationDescriptor) -> JsKlibMetadataProtoBuf.DescriptorUniqId?)
) : KotlinSerializerExtensionBase(JsKlibMetadataSerializerProtocol) {
override val stringTable = JsKlibMetadataStringTable()
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): JsKlibMetadataProtoBuf.DescriptorUniqId? {
private fun uniqId(descriptor: DeclarationDescriptor): KlibMetadataProtoBuf.DescriptorUniqId? {
return declarationTableHandler(descriptor)
}
override fun serializeTypeParameter(typeParameter: TypeParameterDescriptor, proto: ProtoBuf.TypeParameter.Builder) {
uniqId(typeParameter)?.let { proto.setExtension(JsKlibMetadataProtoBuf.typeParamUniqId, it) }
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(JsKlibMetadataProtoBuf.typeAliasUniqId, it) }
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(JsKlibMetadataProtoBuf.enumEntryUniqId, it) }
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(JsKlibMetadataProtoBuf.constructorUniqId, it) }
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.constructorUniqId, it) }
super.serializeConstructor(descriptor, proto, childSerializer)
}
@@ -62,12 +63,10 @@ class JsKlibMetadataSerializerExtension(
versionRequirementTable: MutableVersionRequirementTable,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(JsKlibMetadataProtoBuf.classUniqId, it) }
val id = getFileId(descriptor)
if (id != null) {
proto.setExtension(JsKlibMetadataProtoBuf.classContainingFileId, id)
}
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(
@@ -76,11 +75,8 @@ class JsKlibMetadataSerializerExtension(
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(JsKlibMetadataProtoBuf.propertyUniqId, it) }
val id = getFileId(descriptor)
if (id != null) {
proto.setExtension(JsKlibMetadataProtoBuf.propertyContainingFileId, id)
}
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.propertyUniqId, it) }
descriptorFileId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.propertyFile, it) }
super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer)
}
@@ -90,29 +86,11 @@ class JsKlibMetadataSerializerExtension(
versionRequirementTable: MutableVersionRequirementTable?,
childSerializer: DescriptorSerializer
) {
uniqId(descriptor)?.let { proto.setExtension(JsKlibMetadataProtoBuf.functionUniqId, it) }
val id = getFileId(descriptor)
if (id != null) {
proto.setExtension(JsKlibMetadataProtoBuf.functionContainingFileId, id)
}
uniqId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.functionUniqId, it) }
descriptorFileId(descriptor)?.let { proto.setExtension(KlibMetadataProtoBuf.functionFile, it) }
super.serializeFunction(descriptor, proto, versionRequirementTable, childSerializer)
}
private fun getFileId(descriptor: DeclarationDescriptor): Int? {
if (!DescriptorUtils.isTopLevelDeclaration(descriptor) || descriptor !is DeclarationDescriptorWithSource) return null
val fileId = descriptor.extractFileId()
if (fileId != null) {
(descriptor.containingDeclaration as? JsKlibMetadataPackageFragment)?.let { packageFragment ->
return fileRegistry.lookup(KotlinDeserializedFileMetadata(packageFragment, fileId))
}
}
val file = descriptor.source.containingFile as? PsiSourceFile ?: return null
val psiFile = file.psiFile
return (psiFile as? KtFile)?.let { fileRegistry.lookup(KotlinPsiFileMetadata(it)) }
}
override fun releaseCoroutines() = languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
override fun releaseCoroutines() =
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
}
-127
View File
@@ -1,127 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata;
import "core/metadata/src/metadata.proto";
option java_outer_classname = "JsKlibMetadataProtoBuf";
option optimize_for = LITE_RUNTIME;
message Header {
/*
preRelease
*/
optional int32 flags = 1;
// (patch << 16) + (minor << 8) + major
optional int32 js_code_binary_version = 2 [default = 1];
optional string package_fq_name = 3;
optional org.jetbrains.kotlin.metadata.StringTable strings = 4;
optional org.jetbrains.kotlin.metadata.QualifiedNameTable qualified_names = 5;
// Annotations on the whole module
repeated org.jetbrains.kotlin.metadata.Annotation annotation = 6;
}
message File {
// If absent, id is the index of the file in the Files.file list
optional int32 id = 1;
repeated org.jetbrains.kotlin.metadata.Annotation annotation = 2;
}
message Files {
repeated File file = 1;
}
message DescriptorUniqId {
required int64 index = 1;
}
extend org.jetbrains.kotlin.metadata.Package {
optional int32 package_fq_name = 131;
}
extend org.jetbrains.kotlin.metadata.Class {
repeated org.jetbrains.kotlin.metadata.Annotation class_annotation = 130;
optional int32 class_containing_file_id = 135;
optional DescriptorUniqId class_uniq_id = 136;
}
extend org.jetbrains.kotlin.metadata.Constructor {
repeated org.jetbrains.kotlin.metadata.Annotation constructor_annotation = 130;
optional DescriptorUniqId constructor_uniq_id = 131;
}
extend org.jetbrains.kotlin.metadata.Function {
repeated org.jetbrains.kotlin.metadata.Annotation function_annotation = 130;
optional int32 function_containing_file_id = 135;
optional DescriptorUniqId function_uniq_id = 136;
}
extend org.jetbrains.kotlin.metadata.Property {
repeated org.jetbrains.kotlin.metadata.Annotation property_annotation = 130;
repeated org.jetbrains.kotlin.metadata.Annotation property_getter_annotation = 132;
repeated org.jetbrains.kotlin.metadata.Annotation property_setter_annotation = 133;
optional org.jetbrains.kotlin.metadata.Annotation.Argument.Value compile_time_value = 131;
optional int32 property_containing_file_id = 135;
optional DescriptorUniqId property_uniq_id = 136;
}
extend org.jetbrains.kotlin.metadata.EnumEntry {
repeated org.jetbrains.kotlin.metadata.Annotation enum_entry_annotation = 130;
optional DescriptorUniqId enum_entry_uniq_id = 131;
}
extend org.jetbrains.kotlin.metadata.ValueParameter {
repeated org.jetbrains.kotlin.metadata.Annotation parameter_annotation = 130;
optional DescriptorUniqId value_param_uniq_id = 131;
}
extend org.jetbrains.kotlin.metadata.Type {
repeated org.jetbrains.kotlin.metadata.Annotation type_annotation = 130;
}
extend org.jetbrains.kotlin.metadata.TypeParameter {
repeated org.jetbrains.kotlin.metadata.Annotation type_parameter_annotation = 130;
optional DescriptorUniqId type_param_uniq_id = 131;
}
extend org.jetbrains.kotlin.metadata.PackageFragment {
optional Files package_fragment_files = 130;
}
extend org.jetbrains.kotlin.metadata.TypeAlias {
// TODO repeated org.jetbrains.kotlin.metadata.Annotation type_alias_annotation = 130;
optional DescriptorUniqId type_alias_uniq_id = 131;
}
message Classes {
// id in StringTable
repeated int32 class_name = 1 [packed = true];
}
message Library {
repeated org.jetbrains.kotlin.metadata.PackageFragment package_fragment = 2;
repeated string imported_module = 3;
}
@@ -10,22 +10,20 @@ import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.common.serialization.metadata.DynamicTypeDeserializer
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsMangler
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.newJsDescriptorUniqId
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.*
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataVersion
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.KlibMetadataIncrementalSerializer
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
@@ -37,11 +35,13 @@ import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.konan.KonanVersionImpl
import org.jetbrains.kotlin.konan.MetaVersion
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.library.impl.buildKoltinLibrary
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
@@ -49,8 +49,8 @@ import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.DFS
import java.io.File
import org.jetbrains.kotlin.konan.file.File as KFile
@@ -69,8 +69,6 @@ val KotlinLibrary.isBuiltIns: Boolean
fun loadKlib(klibPath: String) =
createKotlinLibrary(KFile(KFile(klibPath).absolutePath))
internal val JS_KLIBRARY_CAPABILITY = ModuleDescriptor.Capability<KotlinLibrary>("JS KLIBRARY")
private val emptyLoggingContext = object : LoggingContext {
override var inVerbosePhase = false
@@ -86,7 +84,7 @@ fun generateKLib(
project: Project,
files: List<KtFile>,
configuration: CompilerConfiguration,
allDependencies: List<KotlinLibrary>,
allDependencies: KotlinLibraryResolveResult,
friendDependencies: List<KotlinLibrary>,
outputKlibPath: String,
nopack: Boolean
@@ -136,7 +134,7 @@ fun generateKLib(
psi2IrContext.bindingContext,
files,
outputKlibPath,
allDependencies,
allDependencies.getFullList(),
moduleFragment,
icData,
nopack
@@ -164,7 +162,7 @@ fun loadIr(
project: Project,
files: List<KtFile>,
configuration: CompilerConfiguration,
allDependencies: List<KotlinLibrary>,
allDependencies: KotlinLibraryResolveResult,
friendDependencies: List<KotlinLibrary>
): IrModuleInfo {
val depsDescriptors = ModulesStructure(project, files, configuration, allDependencies, friendDependencies)
@@ -177,7 +175,7 @@ fun loadIr(
val deserializer = JsIrLinker(moduleDescriptor, JsMangler, emptyLoggingContext, irBuiltIns, symbolTable)
val deserializedModuleFragments = sortDependencies(allDependencies, depsDescriptors.descriptors).map {
val deserializedModuleFragments = sortDependencies(allDependencies.getFullList(), depsDescriptors.descriptors).map {
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
}
@@ -203,70 +201,29 @@ private fun GeneratorContext.generateModuleFragment(files: List<KtFile>, deseria
Psi2IrTranslator(languageVersionSettings, configuration).generateModuleFragment(this, files, deserializer)
private fun loadKlibMetadataParts(
moduleId: KotlinLibrary
): JsKlibMetadataParts {
return JsKlibMetadataSerializationUtil.readModuleAsProto(moduleId.moduleHeaderData)
}
val ModuleDescriptor.kotlinLibrary get() = this.getCapability(JS_KLIBRARY_CAPABILITY)!!
private fun loadKlibMetadata(
parts: JsKlibMetadataParts,
moduleId: KotlinLibrary,
isBuiltIn: Boolean,
lookupTracker: LookupTracker,
storageManager: LockBasedStorageManager,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
builtinsModule: ModuleDescriptorImpl?,
dependencies: List<ModuleDescriptorImpl>
): ModuleDescriptorImpl {
assert(isBuiltIn == (builtinsModule === null))
val builtIns = builtinsModule?.builtIns ?: object : KotlinBuiltIns(storageManager) {}
val md = ModuleDescriptorImpl(
Name.special("<${moduleId.moduleName}>"),
storageManager,
builtIns,
capabilities = mapOf(JS_KLIBRARY_CAPABILITY to moduleId)
)
if (isBuiltIn) builtIns.builtInsModule = md
val currentModuleFragmentProvider = createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(languageVersionSettings),
lookupTracker
)
val packageFragmentProvider = if (isBuiltIn) {
val functionFragmentProvider = functionInterfacePackageFragmentProvider(storageManager, md)
CompositePackageFragmentProvider(listOf(functionFragmentProvider, currentModuleFragmentProvider))
} else currentModuleFragmentProvider
md.initialize(packageFragmentProvider)
md.setDependencies(listOf(md) + dependencies)
return md
}
private fun createBuiltIns(storageManager: StorageManager) = object : KotlinBuiltIns(storageManager) {}
val JsFactories = KlibMetadataFactories(::createBuiltIns, DynamicTypeDeserializer)
private class ModulesStructure(
private val project: Project,
private val files: List<KtFile>,
val compilerConfiguration: CompilerConfiguration,
private val allDependencies: List<KotlinLibrary>,
val allDependencies: KotlinLibraryResolveResult,
private val friendDependencies: List<KotlinLibrary>
) {
private val deserializedModuleParts: Map<KotlinLibrary, JsKlibMetadataParts> =
allDependencies.associateWith { loadKlibMetadataParts(it) }
val moduleDependencies: Map<KotlinLibrary, List<KotlinLibrary>> = {
val result = mutableMapOf<KotlinLibrary, List<KotlinLibrary>>()
fun findModuleByName(name: String): KotlinLibrary =
allDependencies.find { it.moduleName == name } ?: error("Module is not found: $name")
val moduleDependencies: Map<KotlinLibrary, List<KotlinLibrary>> =
deserializedModuleParts.mapValues { (_, parts) ->
parts.importedModules.map(::findModuleByName)
allDependencies.forEach { klib, _ ->
val dependencies = allDependencies.filterRoots {
it.library == klib
}.getFullList(TopologicalLibraryOrder)
result.put(klib, dependencies.minus(klib))
}
result
}()
val builtInsDep = allDependencies.find { it.isBuiltIns }
val builtInsDep = allDependencies.getFullList().find { it.isBuiltIns }
fun runAnalysis(): JsAnalysisResult {
val analysisResult =
@@ -274,7 +231,7 @@ private class ModulesStructure(
files,
project,
compilerConfiguration,
allDependencies.map { getModuleDescriptor(it) },
allDependencies.getFullList().map { getModuleDescriptor(it) },
friendModuleDescriptors = friendDependencies.map { getModuleDescriptor(it) },
thisIsBuiltInsModule = builtInModuleDescriptor == null,
customBuiltInsModule = builtInModuleDescriptor
@@ -286,31 +243,29 @@ private class ModulesStructure(
return analysisResult
}
private val lookupTracker: LookupTracker = LookupTracker.DO_NOTHING
private val metadataVersion: JsKlibMetadataVersion = compilerConfiguration.metadataVersion
private val languageVersionSettings: LanguageVersionSettings = compilerConfiguration.languageVersionSettings
private val storageManager: LockBasedStorageManager = LockBasedStorageManager("ModulesStructure")
private var runtimeModule: ModuleDescriptorImpl? = null
// TODO: these are roughly equivalent to KlibResolvedModuleDescriptorsFactoryImpl. Refactor me.
val descriptors = mutableMapOf<KotlinLibrary, ModuleDescriptorImpl>()
fun getModuleDescriptor(current: KotlinLibrary): ModuleDescriptorImpl = descriptors.getOrPut(current) {
val parts = loadKlibMetadataParts(current)
val isBuiltIns = parts.importedModules.isEmpty()
loadKlibMetadata(
parts,
val isBuiltIns = current.unresolvedDependencies.isEmpty()
val md = JsFactories.DefaultDeserializedDescriptorFactory.createDescriptorOptionalBuiltIns(
current,
isBuiltIns,
lookupTracker,
storageManager,
metadataVersion,
languageVersionSettings,
runtimeModule,
moduleDependencies.getValue(current).map { getModuleDescriptor(it) }
).also {
if (isBuiltIns) runtimeModule = it
}
storageManager,
runtimeModule?.builtIns,
packageAccessHandler = null // TODO: This is a speed optimization used by Native. Don't bother for now.
)
if (isBuiltIns) runtimeModule = md
val dependencies = moduleDependencies.getValue(current).map { getModuleDescriptor(it) }
md.setDependencies(listOf(md) + dependencies)
md
}
val builtInModuleDescriptor =
@@ -318,6 +273,7 @@ private class ModulesStructure(
getModuleDescriptor(builtInsDep)
else
null // null in case compiling builtInModule itself
}
private fun getDescriptorForElement(
@@ -344,23 +300,20 @@ fun serializeModuleIntoKlib(
val moduleDescriptor = moduleFragment.descriptor
val descriptorSelector = { declarationDescriptor: DeclarationDescriptor ->
val index = descriptorTable.get(declarationDescriptor) ?: error("No descriptor ID found for $declarationDescriptor")
newJsDescriptorUniqId(index)
}
val metadataVersion = configuration.metadataVersion
val languageVersionSettings = configuration.languageVersionSettings
val metadataSerializer = KlibMetadataIncrementalSerializer(
languageVersionSettings,
metadataVersion,
descriptorTable)
fun serializeScope(fqName: FqName, memberScope: Collection<DeclarationDescriptor>): ByteArray {
return JsKlibMetadataSerializationUtil.serializeDescriptors(
return metadataSerializer.serializePackageFragment(
bindingContext,
moduleDescriptor,
memberScope,
fqName,
languageVersionSettings,
metadataVersion,
descriptorSelector
fqName
).toByteArray()
}
@@ -393,25 +346,28 @@ fun serializeModuleIntoKlib(
processCompiledFileData(VfsUtilCore.virtualToIoFile(ktFile.virtualFile), compiledKotlinFile)
}
incrementalResultsConsumer?.run {
processHeader(JsKlibMetadataSerializationUtil.serializeHeader(moduleDescriptor, null, languageVersionSettings).toByteArray())
}
val compiledKotlinFiles = cleanFiles + additionalFiles
val header = metadataSerializer.serializeHeader(
moduleDescriptor,
compiledKotlinFiles.map { it.irData.fqName }.distinct()
).toByteArray()
incrementalResultsConsumer?.run {
processHeader(header)
}
val serializedMetadata =
JsKlibMetadataSerializationUtil.serializedMetadata(
moduleDescriptor,
languageVersionSettings,
dependencies.map { it.moduleName },
compiledKotlinFiles.groupBy { it.irData.fqName }.map { (fqn, data) -> fqn to data.sortedBy { it.irData.path }.map { it.metadata } }.toMap()
metadataSerializer.serializedMetadata(
compiledKotlinFiles.groupBy { it.irData.fqName }.map { (fqn, data) -> fqn to data.sortedBy { it.irData.path }.map { it.metadata } }.toMap(),
header
)
val fullSerializedIr = SerializedIrModule(compiledKotlinFiles.map { it.irData })
val abiVersion = KotlinAbiVersion.CURRENT
// DO NOT PUSH. Commonize me.
val compilerVersion = KonanVersionImpl(MetaVersion.DEV, 1, 3, 0, -1)
val libraryVersion = "JSIR"
val libraryVersion = null
val versions = KonanLibraryVersioning(abiVersion = abiVersion, libraryVersion = libraryVersion, compilerVersion = compilerVersion)
@@ -6,16 +6,15 @@
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.backend.common.serialization.DescriptorReferenceDeserializer
import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.DeserializedDescriptorUniqIdAware
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.name.FqName
class JsDescriptorReferenceDeserializer(
currentModule: ModuleDescriptor,
mangler: KotlinMangler,
builtIns: IrBuiltIns
) : DescriptorReferenceDeserializer(currentModule, mangler, builtIns, mutableMapOf()),
DescriptorUniqIdAware by JsDescriptorUniqIdAware
DescriptorUniqIdAware by DeserializedDescriptorUniqIdAware
@@ -1,27 +0,0 @@
/*
* 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.ir
import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.tryGetExtension
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
object JsDescriptorUniqIdAware: DescriptorUniqIdAware {
override fun DeclarationDescriptor.getUniqId(): Long? = when (this) {
is DeserializedClassDescriptor -> this.classProto.tryGetExtension(JsKlibMetadataProtoBuf.classUniqId)
is DeserializedSimpleFunctionDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.functionUniqId)
is DeserializedPropertyDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.propertyUniqId)
is DeserializedClassConstructorDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.constructorUniqId)
is DeserializedTypeParameterDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.typeParamUniqId)
is DeserializedTypeAliasDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.typeAliasUniqId)
else -> null
}?.index
}
fun newJsDescriptorUniqId(index: Long): JsKlibMetadataProtoBuf.DescriptorUniqId =
JsKlibMetadataProtoBuf.DescriptorUniqId.newBuilder().setIndex(index).build()
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.backend.js.kotlinLibrary
import org.jetbrains.kotlin.descriptors.konan.kotlinLibrary
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.resolve.descriptorUtil.isPublishedApi
@@ -23,7 +23,7 @@ class JsIrLinker(
builtIns: IrBuiltIns,
symbolTable: SymbolTable
) : KotlinIrLinker(logger, builtIns, symbolTable, emptyList(), null, PUBLIC_LOCAL_UNIQ_ID_EDGE),
DescriptorUniqIdAware by JsDescriptorUniqIdAware {
DescriptorUniqIdAware by DeserializedDescriptorUniqIdAware {
override val descriptorReferenceDeserializer =
JsDescriptorReferenceDeserializer(currentModule, mangler, builtIns)
@@ -1,16 +0,0 @@
/*
* 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
class JsKlibMetadataFileRegistry {
private val fileIdsImpl = mutableMapOf<JsKlibFileMetadata, Int>()
fun lookup(file: JsKlibFileMetadata) = fileIdsImpl.getOrPut(file) { fileIdsImpl.size }
val fileIds: Map<JsKlibFileMetadata, Int>
get() = fileIdsImpl
}
@@ -1,86 +0,0 @@
/*
* 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.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.parentOrNull
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.storage.StorageManager
fun createJsKlibMetadataPackageFragmentProvider(
storageManager: StorageManager,
module: ModuleDescriptor,
header: JsKlibMetadataProtoBuf.Header,
packageFragmentProtos: List<ProtoBuf.PackageFragment>,
metadataVersion: JsKlibMetadataVersion,
configuration: DeserializationConfiguration,
lookupTracker: LookupTracker
): PackageFragmentProvider {
val packageFragments: MutableList<PackageFragmentDescriptor> = packageFragmentProtos.mapNotNullTo(mutableListOf()) { proto ->
proto.fqName?.let { fqName ->
JsKlibMetadataPackageFragment(fqName, storageManager, module, proto, header, metadataVersion, configuration)
}
}
// Generate empty PackageFragmentDescriptor instances for packages that aren't mentioned in compilation units directly.
// For example, if there's `package foo.bar` directive, we'll get only PackageFragmentDescriptor for `foo.bar`, but
// none for `foo`. Various descriptor/scope code relies on presence of such package fragments, and currently we
// don't know if it's possible to fix this.
// TODO: think about fixing issues in descriptors/scopes
val packageFqNames = packageFragmentProtos.mapNotNullTo(mutableSetOf()) { it.fqName }
for (packageFqName in packageFqNames.mapNotNull { it.parentOrNull() }) {
var ancestorFqName = packageFqName
while (!ancestorFqName.isRoot && packageFqNames.add(ancestorFqName)) {
packageFragments += EmptyPackageFragmentDescriptor(module, ancestorFqName)
ancestorFqName = ancestorFqName.parent()
}
}
val provider = PackageFragmentProviderImpl(packageFragments)
val notFoundClasses = NotFoundClasses(storageManager, module)
val components = DeserializationComponents(
storageManager,
module,
configuration,
DeserializedClassDataFinder(provider),
AnnotationAndConstantLoaderImpl(module, notFoundClasses, JsKlibMetadataSerializerProtocol),
provider,
LocalClassifierTypeSettings.Default,
ErrorReporter.DO_NOTHING,
lookupTracker,
DynamicTypeDeserializer,
emptyList(),
notFoundClasses,
ContractDeserializerImpl(configuration, storageManager),
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.All,
extensionRegistryLite = JsKlibMetadataSerializerProtocol.extensionRegistry
)
for (packageFragment in packageFragments.filterIsInstance<JsKlibMetadataPackageFragment>()) {
packageFragment.initialize(components)
}
return provider
}
private val ProtoBuf.PackageFragment.fqName: FqName?
get() {
val nameResolver = NameResolverImpl(strings, qualifiedNames)
return when {
hasPackage() -> FqName(nameResolver.getPackageFqName(`package`.getExtension(JsKlibMetadataProtoBuf.packageFqName)))
class_Count > 0 -> nameResolver.getClassId(class_OrBuilderList.first().fqName).packageFqName
else -> null
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.name.ClassId
@@ -22,14 +23,14 @@ class JsKlibMetadataPackageFragment(
storageManager: StorageManager,
module: ModuleDescriptor,
proto: ProtoBuf.PackageFragment,
header: JsKlibMetadataProtoBuf.Header,
header: KlibMetadataProtoBuf.Header,
metadataVersion: JsKlibMetadataVersion,
configuration: DeserializationConfiguration
) : DeserializedPackageFragmentImpl(
fqName, storageManager, module, proto, metadataVersion, JsContainerSource(fqName, header, configuration)
) {
val fileMap: Map<Int, FileHolder> =
proto.getExtension(JsKlibMetadataProtoBuf.packageFragmentFiles).fileList.withIndex().associate { (index, file) ->
proto.getExtension(KlibMetadataProtoBuf.packageFragmentFiles).fileList.withIndex().associate { (index, file) ->
(if (file.hasId()) file.id else index) to FileHolder(file.annotationList)
}
@@ -48,7 +49,7 @@ class JsKlibMetadataPackageFragment(
class JsContainerSource(
private val fqName: FqName,
header: JsKlibMetadataProtoBuf.Header,
header: KlibMetadataProtoBuf.Header,
configuration: DeserializationConfiguration
) : DeserializedContainerSource {
val annotations: List<ClassId> =
@@ -1,220 +0,0 @@
/*
* 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.config.AnalysisFlags
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
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.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.filterOutSourceAnnotations
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
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
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.OutputStream
object JsKlibMetadataSerializationUtil {
fun serializedMetadata(
module: ModuleDescriptor,
settings: LanguageVersionSettings,
importedModules: List<String>,
fragments: Map<String, List<ByteArray>>
): SerializedMetadata {
val fragmentNames = mutableListOf<String>()
val fragmentParts = mutableListOf<List<ByteArray>>()
for ((fqName, fragment) in fragments.entries.sortedBy { it.key }) {
fragmentNames += fqName
fragmentParts += fragment
}
val stream = ByteArrayOutputStream()
serializeHeader(module, null, settings).writeDelimitedTo(stream)
asLibrary().writeTo(stream)
stream.appendPackageFragments(fragments)
importedModules.forEach {
stream.writeProto(JsKlibMetadataProtoBuf.Library.IMPORTED_MODULE_FIELD_NUMBER, it.toByteArray())
}
val moduleLibrary = stream.toByteArray()
return SerializedMetadata(moduleLibrary, fragmentParts, fragmentNames)
}
private fun asLibrary(): JsKlibMetadataProtoBuf.Library {
return JsKlibMetadataProtoBuf.Library.newBuilder().build()
}
private fun OutputStream.writeProto(fieldNumber: Int, content: ByteArray) {
// Message header
write((fieldNumber shl 3) or 2)
// Size varint
var size = content.size
while (size > 0x7F) {
write(0x80 or (size and 0x7F))
size = size ushr 7
}
write(size)
// Fragment itself
write(content)
}
private fun OutputStream.appendPackageFragments(serializedFragments: Map<String, List<ByteArray>>) {
for ((_, fragments) in serializedFragments.entries.sortedBy { it.key }) {
for (fragment in fragments) {
writeProto(JsKlibMetadataProtoBuf.Library.PACKAGE_FRAGMENT_FIELD_NUMBER, fragment)
}
}
}
fun serializeHeader(
module: ModuleDescriptor, packageFqName: FqName?, languageVersionSettings: LanguageVersionSettings
): JsKlibMetadataProtoBuf.Header {
val header = JsKlibMetadataProtoBuf.Header.newBuilder()
if (packageFqName != null) {
header.packageFqName = packageFqName.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 = module.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
}
// TODO: write JS code binary version
return header.build()
}
fun serializeDescriptors(
bindingContext: BindingContext,
module: ModuleDescriptor,
scope: Collection<DeclarationDescriptor>,
fqName: FqName,
languageVersionSettings: LanguageVersionSettings,
metadataVersion: BinaryVersion,
declarationTableHandler: ((DeclarationDescriptor) -> JsKlibMetadataProtoBuf.DescriptorUniqId?)
): ProtoBuf.PackageFragment {
val builder = ProtoBuf.PackageFragment.newBuilder()
val skip = fun(descriptor: DeclarationDescriptor): Boolean {
// TODO: ModuleDescriptor should be able to return the package only with the contents of that module, without dependencies
if (descriptor.module != module) return true
if (descriptor is MemberDescriptor && descriptor.isExpect) {
return !(descriptor is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))
}
return false
}
val fileRegistry = JsKlibMetadataFileRegistry()
val extension = JsKlibMetadataSerializerExtension(fileRegistry, languageVersionSettings, metadataVersion, declarationTableHandler)
val classDescriptors = scope.filterIsInstance<ClassDescriptor>().sortedBy { it.fqNameSafe.asString() }
fun serializeClasses(descriptors: Collection<DeclarationDescriptor>, parentSerializer: DescriptorSerializer) {
for (descriptor in descriptors) {
if (descriptor !is ClassDescriptor || skip(descriptor)) continue
val serializer = DescriptorSerializer.create(descriptor, extension, parentSerializer)
serializeClasses(descriptor.unsubstitutedInnerClassesScope.getContributedDescriptors(), serializer)
val classProto = serializer.classProto(descriptor).build() ?: error("Class not serialized: $descriptor")
builder.addClass_(classProto)
}
}
val serializer = DescriptorSerializer.createTopLevel(extension)
serializeClasses(classDescriptors, serializer)
val stringTable = extension.stringTable
val members = scope.filterNot(skip)
builder.`package` = serializer.packagePartProto(fqName, members).build()
builder.setExtension(
JsKlibMetadataProtoBuf.packageFragmentFiles,
serializeFiles(fileRegistry, bindingContext, AnnotationSerializer(stringTable))
)
val (strings, qualifiedNames) = stringTable.buildProto()
builder.strings = strings
builder.qualifiedNames = qualifiedNames
return builder.build()
}
private fun serializeFiles(
fileRegistry: JsKlibMetadataFileRegistry,
bindingContext: BindingContext,
serializer: AnnotationSerializer
): JsKlibMetadataProtoBuf.Files {
val filesProto = JsKlibMetadataProtoBuf.Files.newBuilder()
for ((file, id) in fileRegistry.fileIds.entries.sortedBy { it.value }) {
val fileProto = JsKlibMetadataProtoBuf.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
}
for (annotation in annotations.filterOutSourceAnnotations()) {
fileProto.addAnnotation(serializer.serializeAnnotation(annotation))
}
filesProto.addFile(fileProto)
}
return filesProto.build()
}
@JvmStatic
fun readModuleAsProto(metadata: ByteArray): JsKlibMetadataParts {
val inputStream = ByteArrayInputStream(metadata)
val header = JsKlibMetadataProtoBuf.Header.parseDelimitedFrom(inputStream, JsKlibMetadataSerializerProtocol.extensionRegistry)
val content = JsKlibMetadataProtoBuf.Library.parseFrom(inputStream, JsKlibMetadataSerializerProtocol.extensionRegistry)
return JsKlibMetadataParts(header, content.packageFragmentList, content.importedModuleList)
}
}
data class JsKlibMetadataParts(
val header: JsKlibMetadataProtoBuf.Header,
val body: List<ProtoBuf.PackageFragment>,
val importedModules: List<String>
)
internal fun DeclarationDescriptor.extractFileId(): Int? = when (this) {
is DeserializedClassDescriptor -> classProto.getExtension(JsKlibMetadataProtoBuf.classContainingFileId)
is DeserializedSimpleFunctionDescriptor -> proto.getExtension(JsKlibMetadataProtoBuf.functionContainingFileId)
is DeserializedPropertyDescriptor -> proto.getExtension(JsKlibMetadataProtoBuf.propertyContainingFileId)
else -> null
}
@@ -1,25 +0,0 @@
/*
* 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.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
object JsKlibMetadataSerializerProtocol : SerializerExtensionProtocol(
ExtensionRegistryLite.newInstance().apply(JsKlibMetadataProtoBuf::registerAllExtensions),
JsKlibMetadataProtoBuf.packageFqName,
JsKlibMetadataProtoBuf.constructorAnnotation,
JsKlibMetadataProtoBuf.classAnnotation,
JsKlibMetadataProtoBuf.functionAnnotation,
JsKlibMetadataProtoBuf.propertyAnnotation,
JsKlibMetadataProtoBuf.propertyGetterAnnotation,
JsKlibMetadataProtoBuf.propertySetterAnnotation,
JsKlibMetadataProtoBuf.enumEntryAnnotation,
JsKlibMetadataProtoBuf.compileTimeValue,
JsKlibMetadataProtoBuf.parameterAnnotation,
JsKlibMetadataProtoBuf.typeAnnotation,
JsKlibMetadataProtoBuf.typeParameterAnnotation
)
@@ -14,6 +14,10 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.KotlinLibrarySearchPathResolver
import org.jetbrains.kotlin.library.UnresolvedLibrary
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.library.resolver.impl.libraryResolver
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
import org.jetbrains.kotlin.serialization.js.ModuleKind
@@ -59,7 +63,7 @@ fun buildKLib(
moduleName: String,
sources: List<String>,
outputPath: String,
dependencies: List<KotlinLibrary>,
allDependencies: KotlinLibraryResolveResult,
commonSources: List<String>
) {
generateKLib(
@@ -72,7 +76,7 @@ fun buildKLib(
file
},
configuration = buildConfiguration(environment, moduleName),
allDependencies = dependencies,
allDependencies = allDependencies,
friendDependencies = emptyList(),
outputKlibPath = outputPath,
nopack = true
@@ -113,12 +117,18 @@ fun main(args: Array<String>) {
error("Please set path to .klm file: `-o some/dir/module-name.klm`")
}
val name = outputPath.takeLastWhile { it != '/' }
val dependencyAbsolutePaths = dependencies.map{ File(it).absolutePath }
val unresolvedLibraries = dependencies.map { UnresolvedLibrary(it, null) }
// Configure the resolver to only understand absolute path libraries.
val libraryResolver = KotlinLibrarySearchPathResolver<KotlinLibrary>(
repositories = emptyList(),
directLibs = dependencyAbsolutePaths,
distributionKlib = null,
localKotlinDir = null,
skipCurrentDir = true
// TODO: pass logger attached to message collector here.
).libraryResolver()
val resolvedLibraries = libraryResolver.resolveWithDependencies(unresolvedLibraries, true, true, true)
val dependencyKLibs = dependencies.map {
val file = File(it)
loadKlib(file.path)
}
buildKLib(name.dropLast(4), listOfKtFilesFrom(inputFiles), outputPath, dependencyKLibs, listOfKtFilesFrom(commonSources))
buildKLib(File(outputPath).absolutePath, listOfKtFilesFrom(inputFiles), outputPath, resolvedLibraries, listOfKtFilesFrom(commonSources))
}
@@ -5,13 +5,12 @@
package org.jetbrains.kotlin.konan.file
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
import org.jetbrains.kotlin.util.removeSuffixIfPresent
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.RandomAccessFile
import java.lang.Exception
import java.net.URI
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
import java.nio.file.*
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.konan.properties
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.util.parseSpaceSeparatedArgs
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
import java.io.ByteArrayOutputStream
typealias Properties = java.util.Properties
@@ -3,7 +3,7 @@
* 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.konan.util
package org.jetbrains.kotlin.util
import kotlin.system.measureTimeMillis
import org.jetbrains.kotlin.konan.file.*
@@ -20,7 +20,8 @@ fun <T> printMillisec(message: String, body: () -> T): T {
fun profile(message: String, body: () -> Unit) = profileIf(
System.getProperty("konan.profile")?.equals("true") ?: false,
message, body)
message, body
)
fun profileIf(condition: Boolean, message: String, body: () -> Unit) =
if (condition) printMillisec(message, body) else body()
@@ -0,0 +1,24 @@
package org.jetbrains.kotlin.util
import kotlin.system.exitProcess
interface Logger {
fun log(message: String)
fun error(message: String)
fun warning(message: String)
fun fatal(message: String): Nothing
}
interface WithLogger {
val logger: Logger
}
object DummyLogger : Logger {
override fun log(message: String) = println(message)
override fun error(message: String) = println("e: $message")
override fun warning(message: String) = println("w: $message")
override fun fatal(message: String): Nothing {
println("e: $message")
exitProcess(1)
}
}
@@ -0,0 +1,24 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
description = "Common klib metadata reader and writer"
dependencies {
compile(kotlinStdlib())
compile(project(":compiler:frontend"))
compile(project(":core:deserialization"))
compile(project(":compiler:serialization"))
compile(project(":kotlin-util-io"))
compile(project(":kotlin-util-klib"))
}
sourceSets {
"main" { projectDefault() }
"test" { none() }
}
publish()
standardPublicJars()
@@ -14,37 +14,38 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata;
package org.jetbrains.kotlin.library.metadata;
import "core/metadata/src/metadata.proto";
option java_outer_classname = "JsKlibMetadataProtoBuf";
option java_outer_classname = "KlibMetadataProtoBuf";
option optimize_for = LITE_RUNTIME;
message Header {
required string module_name = 1;
/*
preRelease
0x1 = preRelease
*/
optional int32 flags = 1;
// (patch << 16) + (minor << 8) + major
optional int32 js_code_binary_version = 2 [default = 1];
optional string package_fq_name = 3;
optional int32 flags = 2;
optional org.jetbrains.kotlin.metadata.StringTable strings = 4;
optional org.jetbrains.kotlin.metadata.QualifiedNameTable qualified_names = 5;
// Annotations on the whole module
repeated org.jetbrains.kotlin.metadata.Annotation annotation = 6;
repeated string package_fragment_name = 7;
repeated string empty_package = 8;
// TODO: Unused.
// TODO: We need to have backend specific extension for versionings.
// (patch << 16) + (minor << 8) + major
// optional int32 js_code_binary_version = 3 [default = 1];
}
message File {
// If absent, id is the index of the file in the Files.file list
optional int32 id = 1;
repeated org.jetbrains.kotlin.metadata.Annotation annotation = 2;
required string name = 2;
repeated org.jetbrains.kotlin.metadata.Annotation annotation = 3;
}
message Files {
@@ -55,73 +56,60 @@ message DescriptorUniqId {
required int64 index = 1;
}
extend org.jetbrains.kotlin.metadata.Package {
optional int32 package_fq_name = 131;
optional int32 package_fq_name = 171;
}
extend org.jetbrains.kotlin.metadata.Class {
repeated org.jetbrains.kotlin.metadata.Annotation class_annotation = 130;
optional int32 class_containing_file_id = 135;
optional DescriptorUniqId class_uniq_id = 136;
repeated org.jetbrains.kotlin.metadata.Annotation class_annotation = 170;
optional int32 class_file = 175;
optional DescriptorUniqId class_uniq_id = 171;
}
extend org.jetbrains.kotlin.metadata.Constructor {
repeated org.jetbrains.kotlin.metadata.Annotation constructor_annotation = 130;
optional DescriptorUniqId constructor_uniq_id = 131;
repeated org.jetbrains.kotlin.metadata.Annotation constructor_annotation = 170;
optional DescriptorUniqId constructor_uniq_id = 172;
}
extend org.jetbrains.kotlin.metadata.Function {
repeated org.jetbrains.kotlin.metadata.Annotation function_annotation = 130;
optional int32 function_containing_file_id = 135;
optional DescriptorUniqId function_uniq_id = 136;
repeated org.jetbrains.kotlin.metadata.Annotation function_annotation = 170;
optional int32 function_file = 172;
optional DescriptorUniqId function_uniq_id = 173;
}
extend org.jetbrains.kotlin.metadata.Property {
repeated org.jetbrains.kotlin.metadata.Annotation property_annotation = 130;
repeated org.jetbrains.kotlin.metadata.Annotation property_getter_annotation = 132;
repeated org.jetbrains.kotlin.metadata.Annotation property_setter_annotation = 133;
optional org.jetbrains.kotlin.metadata.Annotation.Argument.Value compile_time_value = 131;
optional int32 property_containing_file_id = 135;
optional DescriptorUniqId property_uniq_id = 136;
repeated org.jetbrains.kotlin.metadata.Annotation property_annotation = 170;
repeated org.jetbrains.kotlin.metadata.Annotation property_getter_annotation = 177;
repeated org.jetbrains.kotlin.metadata.Annotation property_setter_annotation = 178;
optional org.jetbrains.kotlin.metadata.Annotation.Argument.Value compile_time_value = 173;
optional int32 property_file = 176;
optional DescriptorUniqId property_uniq_id = 179;
}
extend org.jetbrains.kotlin.metadata.EnumEntry {
repeated org.jetbrains.kotlin.metadata.Annotation enum_entry_annotation = 130;
optional DescriptorUniqId enum_entry_uniq_id = 131;
}
extend org.jetbrains.kotlin.metadata.ValueParameter {
repeated org.jetbrains.kotlin.metadata.Annotation parameter_annotation = 130;
optional DescriptorUniqId value_param_uniq_id = 131;
repeated org.jetbrains.kotlin.metadata.Annotation enum_entry_annotation = 170;
optional int32 enum_entry_ordinal = 171;
optional DescriptorUniqId enum_entry_uniq_id = 172;
}
extend org.jetbrains.kotlin.metadata.Type {
repeated org.jetbrains.kotlin.metadata.Annotation type_annotation = 130;
repeated org.jetbrains.kotlin.metadata.Annotation type_annotation = 170;
}
extend org.jetbrains.kotlin.metadata.TypeParameter {
repeated org.jetbrains.kotlin.metadata.Annotation type_parameter_annotation = 130;
optional DescriptorUniqId type_param_uniq_id = 131;
repeated org.jetbrains.kotlin.metadata.Annotation type_parameter_annotation = 170;
optional DescriptorUniqId type_param_uniq_id = 171;
}
extend org.jetbrains.kotlin.metadata.PackageFragment {
optional Files package_fragment_files = 130;
optional Files package_fragment_files = 170;
optional bool is_empty = 172;
optional string fq_name = 173;
// id in StringTable
repeated int32 class_name = 174 [packed = true];
}
extend org.jetbrains.kotlin.metadata.TypeAlias {
// TODO repeated org.jetbrains.kotlin.metadata.Annotation type_alias_annotation = 130;
optional DescriptorUniqId type_alias_uniq_id = 131;
}
message Classes {
// id in StringTable
repeated int32 class_name = 1 [packed = true];
}
message Library {
repeated org.jetbrains.kotlin.metadata.PackageFragment package_fragment = 2;
repeated string imported_module = 3;
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2018 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.library.metadata
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.deserialization.ClassData
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.getClassId
class KlibMetadataClassDataFinder(
private val fragment: org.jetbrains.kotlin.metadata.ProtoBuf.PackageFragment,
private val nameResolver: NameResolver
) : ClassDataFinder {
val nameList = fragment.getExtension(KlibMetadataProtoBuf.className).orEmpty()
override fun findClassData(classId: ClassId): ClassData? {
val index = nameList.indexOfFirst { nameResolver.getClassId(it) == classId }
if (index == -1) {
return null
}
val foundClass = fragment.getClass_(index) ?: error("Could not find data for serialized class $classId")
/* TODO: binary version supposed to be read from protobuf. */
return ClassData(nameResolver, foundClass, KlibMetadataVersion.INSTANCE, SourceElement.NO_SOURCE)
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2018 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.library.metadata
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.metadata.ProtoBuf
fun parsePackageFragment(packageMetadata: ByteArray): ProtoBuf.PackageFragment =
ProtoBuf.PackageFragment.parseFrom(packageMetadata, KlibMetadataSerializerProtocol.extensionRegistry)
fun parseModuleHeader(libraryMetadata: ByteArray): KlibMetadataProtoBuf.Header =
KlibMetadataProtoBuf.Header.parseFrom(libraryMetadata, KlibMetadataSerializerProtocol.extensionRegistry)
interface PackageAccessHandler {
fun loadModuleHeader(
library: KotlinLibrary
): KlibMetadataProtoBuf.Header = parseModuleHeader(library.moduleHeaderData)
fun loadPackageFragment(
library: KotlinLibrary,
packageFqName: String,
partName: String
): ProtoBuf.PackageFragment = parsePackageFragment(library.packageMetadata(packageFqName, partName))
}
object SimplePackageAccessHandler : PackageAccessHandler
@@ -0,0 +1,24 @@
package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.KlibMetadataPackageFragment
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
import org.jetbrains.kotlin.storage.StorageManager
interface KlibMetadataDeserializedPackageFragmentsFactory {
fun createDeserializedPackageFragments(
library: KotlinLibrary,
packageFragmentNames: List<String>,
moduleDescriptor: ModuleDescriptor,
packageAccessedHandler: PackageAccessHandler?,
storageManager: StorageManager
): List<KlibMetadataPackageFragment>
fun createSyntheticPackageFragments(
library: KotlinLibrary,
deserializedPackageFragments: List<KlibMetadataPackageFragment>,
moduleDescriptor: ModuleDescriptor
): List<PackageFragmentDescriptor>
}
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2018 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.konan.util
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataDeserializedPackageFragmentsFactory
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataModuleDescriptorFactory
import org.jetbrains.kotlin.backend.common.serialization.metadata.impl.KlibMetadataDeserializedPackageFragmentsFactoryImpl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.konan.KlibModuleDescriptorFactory
import org.jetbrains.kotlin.descriptors.konan.impl.KlibModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
import org.jetbrains.kotlin.serialization.konan.KlibResolvedModuleDescriptorsFactory
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.serialization.konan.impl.KlibResolvedModuleDescriptorsFactoryImpl
import org.jetbrains.kotlin.storage.StorageManager
/**
* The default Kotlin/Native factories.
*/
open class KlibMetadataFactories(
createBuiltIns:(StorageManager) -> KotlinBuiltIns,
val flexibleTypeDeserializer: FlexibleTypeDeserializer
) {
/**
* The default [KlibModuleDescriptorFactory] factory instance.
*/
val DefaultDescriptorFactory: KlibModuleDescriptorFactory = KlibModuleDescriptorFactoryImpl(createBuiltIns)
/**
* The default [KlibMetadataDeserializedPackageFragmentsFactory] factory instance.
*/
val DefaultPackageFragmentsFactory: KlibMetadataDeserializedPackageFragmentsFactory =
KlibMetadataDeserializedPackageFragmentsFactoryImpl()
/**
* The default [KlibMetadataModuleDescriptorFactory] factory instance.
*/
val DefaultDeserializedDescriptorFactory: KlibMetadataModuleDescriptorFactory =
createDefaultKonanDeserializedModuleDescriptorFactory(
DefaultDescriptorFactory, DefaultPackageFragmentsFactory
)
/**
* The default [KlibResolvedModuleDescriptorsFactory] factory instance.
*/
val DefaultResolvedDescriptorsFactory: KlibResolvedModuleDescriptorsFactory =
createDefaultKonanResolvedModuleDescriptorsFactory(DefaultDeserializedDescriptorFactory)
fun createDefaultKonanDeserializedModuleDescriptorFactory(
descriptorFactory: KlibModuleDescriptorFactory,
packageFragmentsFactory: KlibMetadataDeserializedPackageFragmentsFactory
): KlibMetadataModuleDescriptorFactory =
KlibMetadataModuleDescriptorFactoryImpl(descriptorFactory, packageFragmentsFactory, flexibleTypeDeserializer)
fun createDefaultKonanResolvedModuleDescriptorsFactory(
moduleDescriptorFactory: KlibMetadataModuleDescriptorFactory
): KlibResolvedModuleDescriptorsFactory = KlibResolvedModuleDescriptorsFactoryImpl(moduleDescriptorFactory)
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2018 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.deserialization.BinaryVersion
class KlibMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
override fun isCompatible(): Boolean = this.major == 1 && this.minor == 0
companion object {
@JvmField
val INSTANCE = KlibMetadataVersion(1, 0, 0)
@JvmField
val INVALID_VERSION = KlibMetadataVersion()
}
}
@@ -0,0 +1,59 @@
package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.KlibModuleDescriptorFactory
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
import org.jetbrains.kotlin.storage.StorageManager
interface KlibMetadataModuleDescriptorFactory {
val descriptorFactory: KlibModuleDescriptorFactory
val packageFragmentsFactory: KlibMetadataDeserializedPackageFragmentsFactory
val flexibleTypeDeserializer: FlexibleTypeDeserializer
fun createDescriptor(
library: KotlinLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
packageAccessHandler: PackageAccessHandler?
) = createDescriptorOptionalBuiltIns(
library,
languageVersionSettings,
storageManager,
builtIns,
packageAccessHandler
)
fun createDescriptorAndNewBuiltIns(
library: KotlinLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
packageAccessHandler: PackageAccessHandler?
) = createDescriptorOptionalBuiltIns(library, languageVersionSettings, storageManager, null, packageAccessHandler)
fun createDescriptorOptionalBuiltIns(
library: KotlinLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
packageAccessHandler: PackageAccessHandler?
): ModuleDescriptorImpl
fun createPackageFragmentProvider(
library: KotlinLibrary,
packageAccessHandler: PackageAccessHandler?,
packageFragmentNames: List<String>,
storageManager: StorageManager,
moduleDescriptor: ModuleDescriptor,
configuration: DeserializationConfiguration,
compositePackageFragmentAddend: PackageFragmentProvider?
): PackageFragmentProvider
}
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2018 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.library.metadata
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.storage.StorageManager
class KlibMetadataPackageFragment(
fqName: FqName,
private val library: KotlinLibrary,
private val packageAccessHandler: PackageAccessHandler?,
storageManager: StorageManager,
module: ModuleDescriptor,
private val partName: String
) : DeserializedPackageFragment(fqName, storageManager, module) {
lateinit var components: DeserializationComponents
override fun initialize(components: DeserializationComponents) {
this.components = components
}
// The proto field is lazy so that we can load only needed
// packages from the library.
private val protoForNames: ProtoBuf.PackageFragment by lazy {
(packageAccessHandler ?: SimplePackageAccessHandler).loadPackageFragment(library, fqName.asString(), partName)
}
// TODO: Do we really need both 'protoForNames' and 'proto' today?
val proto: ProtoBuf.PackageFragment
get() = protoForNames
private val nameResolver by lazy {
NameResolverImpl(protoForNames.strings, protoForNames.qualifiedNames)
}
override val classDataFinder by lazy {
KlibMetadataClassDataFinder(proto, nameResolver)
}
private val _memberScope by lazy {
/* TODO: we fake proto binary versioning for now. */
DeserializedPackageMemberScope(
this,
proto.getPackage(),
nameResolver,
KlibMetadataVersion.INSTANCE,
/* containerSource = */ null,
components
) {
loadClassNames()
}
}
override fun getMemberScope(): DeserializedPackageMemberScope = _memberScope
private val classifierNames: Set<Name> by lazy {
val result = mutableSetOf<Name>()
result.addAll(loadClassNames())
protoForNames.getPackage().typeAliasList.mapTo(result) { nameResolver.getName(it.name) }
result
}
fun hasTopLevelClassifier(name: Name): Boolean = name in classifierNames
private fun loadClassNames(): Collection<Name> {
val classNameList = protoForNames.getExtension(KlibMetadataProtoBuf.className).orEmpty()
val names = classNameList.mapNotNull {
val classId = nameResolver.getClassId(it)
val shortName = classId.shortClassName
if (!classId.isNestedClass) shortName else null
}
return names
}
}
@@ -0,0 +1,25 @@
/*
* 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.library.metadata
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
object KlibMetadataSerializerProtocol : SerializerExtensionProtocol(
ExtensionRegistryLite.newInstance().apply(KlibMetadataProtoBuf::registerAllExtensions),
KlibMetadataProtoBuf.packageFqName,
KlibMetadataProtoBuf.constructorAnnotation,
KlibMetadataProtoBuf.classAnnotation,
KlibMetadataProtoBuf.functionAnnotation,
KlibMetadataProtoBuf.propertyAnnotation,
KlibMetadataProtoBuf.propertyGetterAnnotation,
KlibMetadataProtoBuf.propertySetterAnnotation,
KlibMetadataProtoBuf.enumEntryAnnotation,
KlibMetadataProtoBuf.compileTimeValue,
KlibMetadataProtoBuf.parameterAnnotation,
KlibMetadataProtoBuf.typeAnnotation,
KlibMetadataProtoBuf.typeParameterAnnotation
)
@@ -3,7 +3,7 @@
* 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
package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.serialization.StringTableImpl
class JsKlibMetadataStringTable : StringTableImpl() {
class KlibMetadataStringTable : StringTableImpl() {
override fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? {
return if (descriptor.containingDeclaration is CallableMemberDescriptor) {
val superClassifiers = descriptor.getAllSuperClassifiers()
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2018 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.descriptors.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.StorageManager
interface KlibModuleDescriptorFactory {
/**
* Base method for creation of any Kotlin/Native [ModuleDescriptor].
*/
fun createDescriptor(
name: Name,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
origin: KlibModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
): ModuleDescriptorImpl
/**
* Please use this method with care: As far as it creates an instance of [KotlinBuiltIns] it should be
* normally used for creation of the very first (e.g. "stdlib") module in the set of created modules.
*/
fun createDescriptorAndNewBuiltIns(
name: Name,
storageManager: StorageManager,
origin: KlibModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
): ModuleDescriptorImpl
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 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.descriptors.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.isInterop
sealed class KlibModuleOrigin {
companion object {
val CAPABILITY = ModuleDescriptor.Capability<KlibModuleOrigin>("KlibModuleOrigin")
}
}
sealed class CompiledKlibModuleOrigin: KlibModuleOrigin()
class DeserializedKlibModuleOrigin(val library: KotlinLibrary) : CompiledKlibModuleOrigin()
object CurrentKlibModuleOrigin: CompiledKlibModuleOrigin()
object SyntheticModulesOrigin : KlibModuleOrigin()
internal fun KlibModuleOrigin.isInteropLibrary(): Boolean = when (this) {
is DeserializedKlibModuleOrigin -> this.library.isInterop
CurrentKlibModuleOrigin, SyntheticModulesOrigin -> false
}
val ModuleDescriptor.klibModuleOrigin get() = this.getCapability(KlibModuleOrigin.CAPABILITY)!!
val ModuleDescriptor.kotlinLibrary get() =
(this.klibModuleOrigin as DeserializedKlibModuleOrigin)
.library
@@ -0,0 +1,50 @@
package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataModuleDescriptorFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.storage.StorageManager
interface KlibResolvedModuleDescriptorsFactory {
val moduleDescriptorFactory: KlibMetadataModuleDescriptorFactory
/**
* Given the [resolvedLibraries] creates the list of [ModuleDescriptorImpl]s with properly installed
* inter-dependencies. The result of this method is returned in a form of [KlibResolvedModuleDescriptors] instance.
*
* Please use this method with care: Unless this method accepts `null` for [builtIns], it is not recommended to
* invoke it this way. If you are compiling a source module, please supply the non-null [builtIns] from the
* source module, so that all modules created in your compilation session will share the same built-ins instance.
*
* Otherwise (if `null` was supplied), a new instance of [KotlinBuiltIns] will be created. The created built-ins
* instance will be shared by all modules created in this method. But this instance will have no connection
* with probably existing built-ins instance of your source module(s).
*/
fun createResolved(
resolvedLibraries: KotlinLibraryResolveResult,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
languageVersionSettings: LanguageVersionSettings,
customAction: ((KotlinLibrary, ModuleDescriptorImpl) -> Unit)? = null
): KotlinResolvedModuleDescriptors
}
class KotlinResolvedModuleDescriptors(
/**
* The list of modules each representing an individual Kotlin/Native library. All modules
* in this list have properly installed dependencies, i.e. module has all necessary dependencies
* on other modules plus a dependency on the [forwardDeclarationsModule].
*/
val resolvedDescriptors: List<ModuleDescriptorImpl>,
/**
* This is a module which "contains" forward declarations.
* Note: this module should be unique per compilation and should always be the last dependency of any module.
*/
val forwardDeclarationsModule: ModuleDescriptorImpl
)
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2018 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.serialization.konan
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
import org.jetbrains.kotlin.types.SimpleType
object NullFlexibleTypeDeserializer : FlexibleTypeDeserializer {
override fun create(
proto: ProtoBuf.Type,
flexibleId: String,
lowerBound: SimpleType,
upperBound: SimpleType
) = error("Illegal use of flexible type deserializer.")
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.common.serialization.metadata
import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.library.KotlinLibrary
private class DeserializedSourceFile(
val name_: String, val index: Int, val library: KotlinLibrary) : SourceFile {
override fun getName(): String? = name_
override fun equals(other: Any?): Boolean {
return other is DeserializedSourceFile && library == other.library && index == other.index
}
override fun hashCode(): Int {
return library.hashCode() xor index
}
}
class SourceFileMap {
private val sourceToIndex = mutableMapOf<SourceFile, Int>()
private val indexToSource = mutableMapOf<Int, SourceFile>()
fun assign(file: SourceFile): Int {
return sourceToIndex.getOrPut(file) {
sourceToIndex.size
}
}
fun provide(fileName: String, index: Int, library: KotlinLibrary) {
assert(indexToSource[index] == null)
indexToSource[index] =
DeserializedSourceFile(fileName, index, library)
}
fun sourceFile(index: Int): SourceFile =
indexToSource[index] ?: throw Error("Unknown file for $index")
fun filesAndClear() =
sourceToIndex.keys.sortedBy {
sourceToIndex[it]
}.also{
clear()
}
fun clear() {
sourceToIndex.clear()
indexToSource.clear()
}
}
@@ -0,0 +1,190 @@
package org.jetbrains.kotlin.backend.common.serialization.metadata.impl
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataDeserializedPackageFragmentsFactory
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.library.metadata.KlibMetadataPackageFragment
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.serialization.konan.impl.ForwardDeclarationsFqNames
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
// FIXME(ddol): decouple and move interop-specific logic back to Kotlin/Native.
open class KlibMetadataDeserializedPackageFragmentsFactoryImpl: KlibMetadataDeserializedPackageFragmentsFactory {
override fun createDeserializedPackageFragments(
library: KotlinLibrary,
packageFragmentNames: List<String>,
moduleDescriptor: ModuleDescriptor,
packageAccessedHandler: PackageAccessHandler?,
storageManager: StorageManager
) = packageFragmentNames.flatMap {
val fqName = FqName(it)
val parts = library.packageMetadataParts(fqName.asString())
parts.map { partName ->
KlibMetadataPackageFragment(fqName, library, packageAccessedHandler, storageManager, moduleDescriptor, partName)
}
}
override fun createSyntheticPackageFragments(
library: KotlinLibrary,
deserializedPackageFragments: List<KlibMetadataPackageFragment>,
moduleDescriptor: ModuleDescriptor
): List<PackageFragmentDescriptor> {
if (!library.isInterop) return emptyList()
val mainPackageFqName = library.packageFqName?. let{ FqName(it) }
?: error("Inconsistent manifest: interop library ${library.libraryName} should have `package` specified")
val exportForwardDeclarations = library.exportForwardDeclarations.map{ FqName(it) }
val aliasedPackageFragments = deserializedPackageFragments.filter { it.fqName == mainPackageFqName }
val result = mutableListOf<PackageFragmentDescriptor>()
listOf(
ForwardDeclarationsFqNames.cNamesStructs,
ForwardDeclarationsFqNames.objCNamesClasses,
ForwardDeclarationsFqNames.objCNamesProtocols
).mapTo(result) { fqName ->
ClassifierAliasingPackageFragmentDescriptor(aliasedPackageFragments, moduleDescriptor, fqName)
}
result.add(ExportedForwardDeclarationsPackageFragmentDescriptor(moduleDescriptor, mainPackageFqName, exportForwardDeclarations))
return result
}
}
/**
* The package fragment to export forward declarations from interop package namespace, i.e.
* redirect "$pkg.$name" to e.g. "cnames.structs.$name".
*/
class ExportedForwardDeclarationsPackageFragmentDescriptor(
module: ModuleDescriptor,
fqName: FqName,
declarations: List<FqName>
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
private val nameToFqName = declarations.map { it.shortName() to it }.toMap()
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
val declFqName = nameToFqName[name] ?: return null
val packageView = module.getPackage(declFqName.parent())
return packageView.memberScope.getContributedClassifier(name, location) // ?: FIXME(ddol): delegate to forward declarations synthetic module!
}
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, " {")
p.pushIndent()
p.println("declarations = $declarations")
p.popIndent()
p.println("}")
}
}
override fun getMemberScope() = memberScope
}
/**
* The package fragment that redirects all requests for classifier lookup to its targets.
*/
class ClassifierAliasingPackageFragmentDescriptor(
targets: List<KlibMetadataPackageFragment>,
module: ModuleDescriptor,
fqName: FqName
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
override fun getContributedClassifier(name: Name, location: LookupLocation) =
targets.firstNotNullResult {
if (it.hasTopLevelClassifier(name)) {
it.getMemberScope().getContributedClassifier(name, location)
} else {
null
}
}
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, " {")
p.pushIndent()
p.println("targets = $targets")
p.popIndent()
p.println("}")
}
}
override fun getMemberScope(): MemberScope = memberScope
}
/**
* Package fragment which creates descriptors for forward declarations on demand.
*/
private class ForwardDeclarationsPackageFragmentDescriptor(
storageManager: StorageManager,
module: ModuleDescriptor,
fqName: FqName,
supertypeName: Name,
classKind: ClassKind
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
private val declarations = storageManager.createMemoizedFunction(this::createDeclaration)
private val supertype by storageManager.createLazyValue {
val descriptor = builtIns.builtInsModule.getPackage(ForwardDeclarationsFqNames.packageName)
.memberScope
.getContributedClassifier(supertypeName, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
descriptor.defaultType
}
private fun createDeclaration(name: Name): ClassDescriptor {
return ClassDescriptorImpl(
this@ForwardDeclarationsPackageFragmentDescriptor,
name,
Modality.FINAL,
classKind,
listOf(supertype),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
).apply {
this.initialize(MemberScope.Empty, emptySet(), null)
}
}
override fun getContributedClassifier(name: Name, location: LookupLocation) = declarations(name)
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, "{}")
}
}
override fun getMemberScope(): MemberScope = memberScope
}
@@ -0,0 +1,155 @@
/*
* Copyright 2010-2018 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.serialization.konan.impl
import org.jetbrains.kotlin.backend.common.serialization.metadata.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.contracts.ContractDeserializerImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.KlibModuleDescriptorFactory
import org.jetbrains.kotlin.descriptors.konan.klibModuleOrigin
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
import org.jetbrains.kotlin.library.metadata.parseModuleHeader
import org.jetbrains.kotlin.library.unresolvedDependencies
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.storage.StorageManager
val ModuleDescriptorImpl.isStdlibModule
get() = (this.klibModuleOrigin as? DeserializedKlibModuleOrigin)
?.library?.unresolvedDependencies?.isEmpty() ?: false
class KlibMetadataModuleDescriptorFactoryImpl(
override val descriptorFactory: KlibModuleDescriptorFactory,
override val packageFragmentsFactory: KlibMetadataDeserializedPackageFragmentsFactory,
override val flexibleTypeDeserializer: FlexibleTypeDeserializer
): KlibMetadataModuleDescriptorFactory {
override fun createDescriptorOptionalBuiltIns(
library: KotlinLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
packageAccessHandler: PackageAccessHandler?
): ModuleDescriptorImpl {
val libraryProto = parseModuleHeader(library.moduleHeaderData)
val moduleName = Name.special(libraryProto.moduleName)
val moduleOrigin = DeserializedKlibModuleOrigin(library)
val moduleDescriptor = if (builtIns != null )
descriptorFactory.createDescriptor(moduleName, storageManager, builtIns, moduleOrigin)
else
descriptorFactory.createDescriptorAndNewBuiltIns(moduleName, storageManager, moduleOrigin)
val deserializationConfiguration = CompilerDeserializationConfiguration(languageVersionSettings)
val compositePackageFragmentAddend =
if (moduleDescriptor.isStdlibModule) {
functionInterfacePackageFragmentProvider(storageManager, moduleDescriptor)
} else null
val provider = createPackageFragmentProvider(
library,
packageAccessHandler,
libraryProto.packageFragmentNameList,
storageManager,
moduleDescriptor,
deserializationConfiguration,
compositePackageFragmentAddend
)
moduleDescriptor.initialize(provider)
return moduleDescriptor
}
override fun createPackageFragmentProvider(
library: KotlinLibrary,
packageAccessHandler: PackageAccessHandler?,
packageFragmentNames: List<String>,
storageManager: StorageManager,
moduleDescriptor: ModuleDescriptor,
configuration: DeserializationConfiguration,
compositePackageFragmentAddend: PackageFragmentProvider?
): PackageFragmentProvider {
val deserializedPackageFragments = packageFragmentsFactory.createDeserializedPackageFragments(
library, packageFragmentNames, moduleDescriptor, packageAccessHandler, storageManager)
// TODO: this is native specific. Move to a child class.
val syntheticPackageFragments = packageFragmentsFactory.createSyntheticPackageFragments(
library, deserializedPackageFragments, moduleDescriptor)
val provider = PackageFragmentProviderImpl(deserializedPackageFragments + syntheticPackageFragments)
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
val annotationAndConstantLoader = AnnotationAndConstantLoaderImpl(
moduleDescriptor,
notFoundClasses,
KlibMetadataSerializerProtocol
)
val components = DeserializationComponents(
storageManager,
moduleDescriptor,
configuration,
DeserializedClassDataFinder(provider),
annotationAndConstantLoader,
provider,
LocalClassifierTypeSettings.Default,
ErrorReporter.DO_NOTHING,
LookupTracker.DO_NOTHING,
flexibleTypeDeserializer,
emptyList(),
notFoundClasses,
ContractDeserializerImpl(configuration, storageManager),
extensionRegistryLite = KlibMetadataSerializerProtocol.extensionRegistry)
for (packageFragment in deserializedPackageFragments) {
packageFragment.initialize(components)
}
return compositePackageFragmentAddend ?.let {
CompositePackageFragmentProvider(listOf(it, provider))
} ?: provider
}
fun createForwardDeclarationHackPackagePartProvider(
storageManager: StorageManager,
module: ModuleDescriptorImpl
): PackageFragmentProviderImpl {
fun createPackage(fqName: FqName, supertypeName: String, classKind: ClassKind) =
ForwardDeclarationsPackageFragmentDescriptor(
storageManager,
module,
fqName,
Name.identifier(supertypeName),
classKind
)
val packageFragmentProvider = PackageFragmentProviderImpl(
listOf(
createPackage(ForwardDeclarationsFqNames.cNamesStructs, "COpaque", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesClasses, "ObjCObjectBase", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesProtocols, "ObjCObject", ClassKind.INTERFACE)
)
)
return packageFragmentProvider
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2018 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.descriptors.konan.impl
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.*
import org.jetbrains.kotlin.descriptors.konan.isInteropLibrary
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ImplicitIntegerCoercion
import org.jetbrains.kotlin.storage.StorageManager
internal class KlibModuleDescriptorFactoryImpl(val createBuiltIns: (StorageManager) -> KotlinBuiltIns) : KlibModuleDescriptorFactory {
override fun createDescriptor(
name: Name,
storageManager: StorageManager,
builtIns: KotlinBuiltIns,
origin: KlibModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
) = ModuleDescriptorImpl(
name,
storageManager,
builtIns,
capabilities = customCapabilities + mapOf(
KlibModuleOrigin.CAPABILITY to origin,
ImplicitIntegerCoercion.MODULE_CAPABILITY to origin.isInteropLibrary()
)
)
override fun createDescriptorAndNewBuiltIns(
name: Name,
storageManager: StorageManager,
origin: KlibModuleOrigin,
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
): ModuleDescriptorImpl {
val builtIns = createBuiltIns(storageManager)
val moduleDescriptor = createDescriptor(name, storageManager, builtIns, origin, customCapabilities)
builtIns.builtInsModule = moduleDescriptor
return moduleDescriptor
}
}
@@ -0,0 +1,183 @@
package org.jetbrains.kotlin.serialization.konan.impl
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataModuleDescriptorFactory
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.SyntheticModulesOrigin
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.util.profile
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
import org.jetbrains.kotlin.serialization.konan.KlibResolvedModuleDescriptorsFactory
import org.jetbrains.kotlin.serialization.konan.KotlinResolvedModuleDescriptors
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.utils.Printer
// TODO: eliminate Native specifics.
class KlibResolvedModuleDescriptorsFactoryImpl(
override val moduleDescriptorFactory: KlibMetadataModuleDescriptorFactory
): KlibResolvedModuleDescriptorsFactory {
override fun createResolved(
resolvedLibraries: KotlinLibraryResolveResult,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
languageVersionSettings: LanguageVersionSettings,
customAction: ((KotlinLibrary, ModuleDescriptorImpl) -> Unit)?
): KotlinResolvedModuleDescriptors {
val moduleDescriptors = mutableListOf<ModuleDescriptorImpl>()
@Suppress("NAME_SHADOWING")
var builtIns = builtIns
// Build module descriptors.
resolvedLibraries.forEach { library, packageAccessHandler ->
profile("Loading ${library.libraryName}") {
// MutableModuleContext needs ModuleDescriptorImpl, rather than ModuleDescriptor.
val moduleDescriptor = createDescriptorOptionalBuiltsIns(
library, languageVersionSettings, storageManager, builtIns, packageAccessHandler
)
builtIns = moduleDescriptor.builtIns
moduleDescriptors.add(moduleDescriptor)
customAction?.invoke(library, moduleDescriptor)
}
}
val forwardDeclarationsModule = createForwardDeclarationsModule(builtIns, storageManager)
// Set inter-dependencies between module descriptors, add forwarding declarations module.
for (module in moduleDescriptors) {
// Yes, just to all of them.
module.setDependencies(moduleDescriptors + forwardDeclarationsModule)
}
return KotlinResolvedModuleDescriptors(moduleDescriptors, forwardDeclarationsModule)
}
private fun createForwardDeclarationsModule(
builtIns: KotlinBuiltIns?,
storageManager: StorageManager): ModuleDescriptorImpl {
val name = Name.special("<forward declarations>")
val module = createDescriptorOptionalBuiltsIns(name, storageManager, builtIns, SyntheticModulesOrigin)
fun createPackage(fqName: FqName, supertypeName: String, classKind: ClassKind) =
ForwardDeclarationsPackageFragmentDescriptor(
storageManager,
module,
fqName,
Name.identifier(supertypeName),
classKind)
val packageFragmentProvider = PackageFragmentProviderImpl(
listOf(
createPackage(ForwardDeclarationsFqNames.cNamesStructs, "COpaque", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesClasses, "ObjCObjectBase", ClassKind.CLASS),
createPackage(ForwardDeclarationsFqNames.objCNamesProtocols, "ObjCObject", ClassKind.INTERFACE)
)
)
module.initialize(packageFragmentProvider)
module.setDependencies(module)
return module
}
private fun createDescriptorOptionalBuiltsIns(
name: Name,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
moduleOrigin: KlibModuleOrigin
) = if (builtIns != null)
moduleDescriptorFactory.descriptorFactory.createDescriptor(name, storageManager, builtIns, moduleOrigin)
else
moduleDescriptorFactory.descriptorFactory.createDescriptorAndNewBuiltIns(name, storageManager, moduleOrigin)
private fun createDescriptorOptionalBuiltsIns(
library: KotlinLibrary,
languageVersionSettings: LanguageVersionSettings,
storageManager: StorageManager,
builtIns: KotlinBuiltIns?,
packageAccessHandler: PackageAccessHandler?
) = if (builtIns != null)
moduleDescriptorFactory.createDescriptor(library, languageVersionSettings, storageManager, builtIns, packageAccessHandler)
else
moduleDescriptorFactory.createDescriptorAndNewBuiltIns(library, languageVersionSettings, storageManager, packageAccessHandler)
}
/**
* Package fragment which creates descriptors for forward declarations on demand.
*/
class ForwardDeclarationsPackageFragmentDescriptor(
storageManager: StorageManager,
module: ModuleDescriptor,
fqName: FqName,
supertypeName: Name,
classKind: ClassKind
) : PackageFragmentDescriptorImpl(module, fqName) {
private val memberScope = object : MemberScopeImpl() {
private val declarations = storageManager.createMemoizedFunction(this::createDeclaration)
private val supertype by storageManager.createLazyValue {
val descriptor = builtIns.builtInsModule.getPackage(ForwardDeclarationsFqNames.packageName)
.memberScope
.getContributedClassifier(supertypeName, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
descriptor.defaultType
}
private fun createDeclaration(name: Name): ClassDescriptor {
return ClassDescriptorImpl(
this@ForwardDeclarationsPackageFragmentDescriptor,
name,
Modality.FINAL,
classKind,
listOf(supertype),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
).apply {
this.initialize(MemberScope.Empty, emptySet(), null)
}
}
override fun getContributedClassifier(name: Name, location: LookupLocation) = declarations(name)
override fun printScopeStructure(p: Printer) {
p.println(this::class.java.simpleName, "{}")
}
}
override fun getMemberScope(): MemberScope = memberScope
}
// FIXME(ddol): decouple and move interop-specific logic back to Kotlin/Native.
internal object ForwardDeclarationsFqNames {
val packageName = FqName("kotlinx.cinterop")
val cNames = FqName("cnames")
val cNamesStructs = cNames.child(Name.identifier("structs"))
val objCNames = FqName("objcnames")
val objCNamesClasses = objCNames.child(Name.identifier("classes"))
val objCNamesProtocols = objCNames.child(Name.identifier("protocols"))
}
@@ -0,0 +1,56 @@
package org.jetbrains.kotlin.library.resolver
import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
interface KotlinLibraryResolver<L: KotlinLibrary> {
val searchPathResolver: SearchPathResolver<L>
/**
* Given the list of Kotlin/Native library names, ABI version and other parameters
* resolves libraries and evaluates dependencies between them.
*/
fun resolveWithDependencies(
unresolvedLibraries: List<UnresolvedLibrary>,
noStdLib: Boolean = false,
noDefaultLibs: Boolean = false,
noEndorsedLibs: Boolean = false
): KotlinLibraryResolveResult
}
interface KotlinLibraryResolveResult {
fun filterRoots(predicate: (KotlinResolvedLibrary) -> Boolean): KotlinLibraryResolveResult
fun getFullList(order: LibraryOrder? = null): List<KotlinLibrary>
fun forEach(action: (KotlinLibrary, PackageAccessHandler) -> Unit)
}
typealias LibraryOrder = (Iterable<KotlinResolvedLibrary>) -> List<KotlinResolvedLibrary>
val TopologicalLibraryOrder: LibraryOrder = { input ->
val sorted = mutableListOf<KotlinResolvedLibrary>()
val visited = mutableSetOf<KotlinResolvedLibrary>()
val tempMarks = mutableSetOf<KotlinResolvedLibrary>()
fun visit(node: KotlinResolvedLibrary, result: MutableList<KotlinResolvedLibrary>) {
if (visited.contains(node)) return
if (tempMarks.contains(node)) error("Cyclic dependency in library graph for: ${node.library.libraryName}")
tempMarks.add(node)
node.resolvedDependencies.forEach {
visit(it, result)
}
visited.add(node)
result += node
}
input.forEach next@{
if (visited.contains(it)) return@next
visit(it, sorted)
}
sorted
}
@@ -0,0 +1,23 @@
package org.jetbrains.kotlin.library.resolver
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
/**
* A [KotlinLibrary] wrapper that is used for resolving library's dependencies.
*/
interface KotlinResolvedLibrary: PackageAccessHandler {
// The library itself.
val library: KotlinLibrary
// Dependencies on other libraries.
val resolvedDependencies: List<KotlinResolvedLibrary>
// Any package fragment within this library has beed visited during frontend resolve phase.
// You need to utilize PackageAccessHandler to make it work for you.
val isNeededForLink: Boolean
// Is provided by the distribution?
val isDefault: Boolean
}
@@ -0,0 +1,156 @@
/*
* Copyright 2010-2019 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.library.resolver.impl
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.library.metadata.PackageAccessHandler
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolver
import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.library.resolver.LibraryOrder
import org.jetbrains.kotlin.util.WithLogger
fun <L: KotlinLibrary> SearchPathResolver<L>.libraryResolver()
= KotlinLibraryResolverImpl<L>(this)
class KotlinLibraryResolverImpl<L: KotlinLibrary>(
override val searchPathResolver: SearchPathResolver<L>
): KotlinLibraryResolver<L>, WithLogger by searchPathResolver {
override fun resolveWithDependencies(
unresolvedLibraries: List<UnresolvedLibrary>,
noStdLib: Boolean,
noDefaultLibs: Boolean,
noEndorsedLibs: Boolean
) = findLibraries(unresolvedLibraries, noStdLib, noDefaultLibs, noEndorsedLibs)
.leaveDistinct()
.resolveDependencies()
/**
* Returns the list of libraries based on [libraryNames], [noStdLib], [noDefaultLibs] and [noEndorsedLibs] criteria.
*
* This method does not return any libraries that might be available via transitive dependencies
* from the original library set (root set).
*/
private fun findLibraries(
unresolvedLibraries: List<UnresolvedLibrary>,
noStdLib: Boolean,
noDefaultLibs: Boolean,
noEndorsedLibs: Boolean
): List<KotlinLibrary> {
val userProvidedLibraries = unresolvedLibraries.asSequence()
.map { searchPathResolver.resolve(it) }
.toList()
val defaultLibraries = searchPathResolver.defaultLinks(noStdLib, noDefaultLibs, noEndorsedLibs)
// Make sure the user provided ones appear first, so that
// they have precedence over defaults when duplicates are eliminated.
return userProvidedLibraries + defaultLibraries
}
/**
* Leaves only distinct libraries (by absolute path), warns on duplicated paths.
*/
private fun List<KotlinLibrary>.leaveDistinct() =
this.groupBy { it.libraryFile.absolutePath }.let { groupedByAbsolutePath ->
warnOnLibraryDuplicates(groupedByAbsolutePath.filter { it.value.size > 1 }.keys)
groupedByAbsolutePath.map { it.value.first() }
}
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>) {
duplicatedPaths.forEach { logger.warning("library included more than once: $it") }
}
/**
* Given the list of root libraries does the following:
*
* 1. Evaluates other libraries that are available via transitive dependencies.
* 2. Wraps each [KotlinLibrary] into a [KotlinResolvedLibrary] with information about dependencies on other libraries.
* 3. Creates resulting [KotlinLibraryResolveResult] object.
*/
private fun List<KotlinLibrary>.resolveDependencies(): KotlinLibraryResolveResult {
val rootLibraries = this.map { KotlinResolvedLibraryImpl(it) }
// As far as the list of root libraries is known from the very beginning, the result can be
// constructed from the very beginning as well.
val result = KotlinLibraryResolverResultImpl(rootLibraries)
val cache = mutableMapOf<File, KotlinResolvedLibrary>()
cache.putAll(rootLibraries.map { it.library.libraryFile.absoluteFile to it })
var newDependencies = rootLibraries
do {
newDependencies = newDependencies.map { library: KotlinResolvedLibraryImpl ->
library.library.unresolvedDependencies.asSequence()
.map { KotlinResolvedLibraryImpl(searchPathResolver.resolve(it)) }
.map { resolved ->
val absoluteFile = resolved.library.libraryFile.absoluteFile
if (absoluteFile in cache) {
library.addDependency(cache[absoluteFile]!!)
null
} else {
cache.put(absoluteFile, resolved)
library.addDependency(resolved)
resolved
}
}.filterNotNull()
.toList()
}.flatten()
} while (newDependencies.isNotEmpty())
return result
}
}
class KotlinLibraryResolverResultImpl(
private val roots: List<KotlinResolvedLibrary>
): KotlinLibraryResolveResult {
private val all: List<KotlinResolvedLibrary> by lazy {
val result = mutableSetOf<KotlinResolvedLibrary>().also { it.addAll(roots) }
var newDependencies = result.toList()
do {
newDependencies = newDependencies
.map { it -> it.resolvedDependencies }.flatten()
.filter { it !in result }
result.addAll(newDependencies)
} while (newDependencies.isNotEmpty())
result.toList()
}
override fun filterRoots(predicate: (KotlinResolvedLibrary) -> Boolean) =
KotlinLibraryResolverResultImpl(roots.filter(predicate))
override fun getFullList(order: LibraryOrder?) = (order?.invoke(all) ?: all).asPlain()
override fun forEach(action: (KotlinLibrary, PackageAccessHandler) -> Unit) {
all.forEach { action(it.library, it) }
}
private fun List<KotlinResolvedLibrary>.asPlain() = map { it.library }
override fun toString() = "roots=$roots, all=$all"
}
@@ -0,0 +1,38 @@
package org.jetbrains.kotlin.library.resolver.impl
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.metadata.parseModuleHeader
import org.jetbrains.kotlin.library.metadata.parsePackageFragment
import org.jetbrains.kotlin.library.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.metadata.ProtoBuf
class KotlinResolvedLibraryImpl(override val library: KotlinLibrary): KotlinResolvedLibrary {
private val _resolvedDependencies = mutableListOf<KotlinResolvedLibrary>()
private val _emptyPackages by lazy { parseModuleHeader(library.moduleHeaderData).emptyPackageList }
override val resolvedDependencies: List<KotlinResolvedLibrary>
get() = _resolvedDependencies
internal fun addDependency(resolvedLibrary: KotlinResolvedLibrary) = _resolvedDependencies.add(resolvedLibrary)
override var isNeededForLink: Boolean = false
private set
override val isDefault: Boolean
get() = library.isDefault
override fun loadPackageFragment(
library: KotlinLibrary,
packageFqName: String,
partName: String
): ProtoBuf.PackageFragment {
if (!isNeededForLink // fast path
&& !_emptyPackages.contains(packageFqName)) {
isNeededForLink = true
}
return parsePackageFragment(library.packageMetadata(packageFqName, partName))
}
override fun toString() = "library=$library, dependsOn=${_resolvedDependencies.joinToString { it.library.toString() }}"
}
@@ -11,6 +11,9 @@ const val KLIB_PROPERTY_LIBRARY_VERSION = "library_version"
const val KLIB_PROPERTY_UNIQUE_NAME = "unique_name"
const val KLIB_PROPERTY_DEPENDS = "depends"
const val KLIB_PROPERTY_PACKAGE = "package"
const val KLIB_PROPERTY_INTEROP = "interop"
const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
/**
* Abstractions for getting access to the information stored inside of Kotlin/Native library.
*/
@@ -51,3 +54,17 @@ val BaseKotlinLibrary.unresolvedDependencies: List<UnresolvedLibrary>
}
interface KotlinLibrary : BaseKotlinLibrary, MetadataLibrary, IrLibrary
// TODO: should we move the below ones to Native?
val KotlinLibrary.isInterop
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
val KotlinLibrary.packageFqName: String?
get() = manifestProperties.getProperty(org.jetbrains.kotlin.library.KLIB_PROPERTY_PACKAGE)
val KotlinLibrary.exportForwardDeclarations
get() = manifestProperties.propertyList(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS, escapeInQuotes = true)
.asSequence()
.map { it.trim() }
.filter { it.isNotEmpty() }
.toList()
@@ -36,4 +36,4 @@ val List<String>.toUnresolvedLibraries
.let { if (it.isEmpty()) null else it }
val name = it.substringBeforeLast('@')
UnresolvedLibrary(name, version)
}
}
@@ -0,0 +1,160 @@
package org.jetbrains.kotlin.library
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
import org.jetbrains.kotlin.util.*
const val KOTLIN_STDLIB_NAME = "stdlib"
interface SearchPathResolver<out L: KotlinLibrary> : WithLogger {
val searchRoots: List<File>
fun resolutionSequence(givenPath: String): Sequence<File>
fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean = false): L
fun resolve(givenPath: String): L
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean, noEndorsedLibs: Boolean): List<L>
}
interface SearchPathResolverWithAttributes<out L: KotlinLibrary>: SearchPathResolver<L> {
val knownAbiVersions: List<KotlinAbiVersion>?
val knownCompilerVersions: List<KonanVersion>?
}
fun resolverByName(
repositories: List<String>,
directLibs: List<String> = emptyList(),
distributionKlib: String? = null,
localKotlinDir: String? = null,
skipCurrentDir: Boolean = false,
logger: Logger = DummyLogger
): SearchPathResolver<KotlinLibrary> = KotlinLibrarySearchPathResolver(repositories, directLibs, distributionKlib, localKotlinDir, skipCurrentDir, logger)
open class KotlinLibrarySearchPathResolver<out L: KotlinLibrary>(
repositories: List<String>,
directLibs: List<String>,
val distributionKlib: String?,
val localKotlinDir: String?,
val skipCurrentDir: Boolean,
override val logger: Logger = DummyLogger
) : SearchPathResolver<L> {
val localHead: File?
get() = localKotlinDir?.File()?.klib
val distHead: File?
get() = distributionKlib?.File()?.child("common")
open val distPlatformHead: File? = null
val currentDirHead: File?
get() = if (!skipCurrentDir) File.userDir else null
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
private val directLibraries: List<KotlinLibrary> by lazy {
directLibs.mapNotNull { found(File(it)) }.map { createKotlinLibrary(it) }
}
// This is the place where we specify the order of library search.
override val searchRoots: List<File> by lazy {
(listOf(currentDirHead) + repoRoots + listOf(localHead, distHead, distPlatformHead)).filterNotNull()
}
private fun found(candidate: File): File? {
fun check(file: File): Boolean =
file.exists && (file.isFile || File(file, "manifest").exists)
val noSuffix = File(candidate.path.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT))
val withSuffix = File(candidate.path.suffixIfNot(KLIB_FILE_EXTENSION_WITH_DOT))
return when {
check(withSuffix) -> withSuffix
check(noSuffix) -> noSuffix
else -> null
}
}
override fun resolutionSequence(givenPath: String): Sequence<File> {
val given = File(givenPath)
val sequence = if (given.isAbsolute) {
sequenceOf(found(given))
} else {
// Search among user-provided libraries by unique name.
// It's a workaround for maven publication. When a library is published without Gradle metadata,
// it has a complex file name (e.g. foo-macos_x64-1.0.klib). But a dependency on this lib in manifests
// of other libs uses its unique name written in the manifest (i.e just 'foo'). So we cannot resolve this
// library by its filename. But we have this library's file (we've downloaded it using maven dependency
// resolution) so we can pass it to the compiler directly. This code takes this into account and looks for
// a library dependencies also in libs passed to the compiler as files (passed to the resolver as the
// 'directLibraries' property).
val directLibs = directLibraries.asSequence().filter {
it.uniqueName == givenPath
}.map {
it.libraryFile
}
// Search among libraries in repositoreis by library filename.
val repoLibs = searchRoots.asSequence().map {
found(File(it, givenPath))
}
directLibs + repoLibs
}
return sequence.filterNotNull()
}
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): L {
val givenPath = unresolved.path
return resolutionSequence(givenPath).firstOrNull() ?. let {
createKotlinLibrary(it, isDefaultLink) as L
} ?: run {
logger.fatal("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
}
}
override fun resolve(givenPath: String) = resolve(UnresolvedLibrary(givenPath, null), false)
private val File.klib
get() = File(this, "klib")
// The libraries from the default root are linked automatically.
val defaultRoots: List<File>
get() = listOfNotNull(distHead, distPlatformHead).filter { it.exists }
private fun getDefaultLibrariesFromDir(directory: File) =
if (directory.exists) {
directory.listFiles
.asSequence()
.filterNot { it.name.startsWith('.') }
.filterNot { it.name.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT) == KOTLIN_STDLIB_NAME }
.map { UnresolvedLibrary(it.absolutePath, null) }
.map { resolve(it, isDefaultLink = true) }
} else emptySequence()
override fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean, noEndorsedLibs: Boolean): List<L> {
val result = mutableListOf<L>()
if (!noStdLib) {
result.add(resolve(UnresolvedLibrary(KOTLIN_STDLIB_NAME, null), true))
}
// Endorsed libraries in distHead.
if (!noEndorsedLibs) {
distHead?.let {
result.addAll(getDefaultLibrariesFromDir(it))
}
}
// Platform libraries resolve.
if (!noDefaultLibs) {
distPlatformHead?.let {
result.addAll(getDefaultLibrariesFromDir(it))
}
}
return result
}
}
fun KonanVersion.compatible(other: KonanVersion) =
this.major == other.major
&& this.minor == other.minor
&& this.maintenance == other.maintenance
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.loadProperties
open class BaseKotlinLibraryImpl(
private val access: BaseLibraryAccess<KotlinLibraryLayout>,
val access: BaseLibraryAccess<KotlinLibraryLayout>,
override val isDefault: Boolean
) : BaseKotlinLibrary {
override val libraryFile get() = access.klib
@@ -40,7 +40,7 @@ open class BaseKotlinLibraryImpl(
}
open class MetadataLibraryImpl(
private val access: MetadataLibraryAccess<MetadataKotlinLibraryLayout>
val access: MetadataLibraryAccess<MetadataKotlinLibraryLayout>
) : MetadataLibrary {
override val moduleHeaderData: ByteArray by lazy {
@@ -72,7 +72,7 @@ open class MetadataLibraryImpl(
}
abstract class IrLibraryImpl(
protected val access: IrLibraryAccess<IrKotlinLibraryLayout>
val access: IrLibraryAccess<IrKotlinLibraryLayout>
) : IrLibrary {
override val dataFlowGraph by lazy {
access.inPlace { it: IrKotlinLibraryLayout ->
@@ -211,9 +211,9 @@ class IrPerFileLibraryImpl(_access: IrLibraryAccess<IrKotlinLibraryLayout>) : Ir
}
open class KotlinLibraryImpl(
base: BaseKotlinLibraryImpl,
metadata: MetadataLibraryImpl,
ir: IrLibraryImpl
val base: BaseKotlinLibraryImpl,
val metadata: MetadataLibraryImpl,
val ir: IrLibraryImpl
) : KotlinLibrary,
BaseKotlinLibrary by base,
MetadataLibrary by metadata,
@@ -4,7 +4,7 @@ import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.file
import org.jetbrains.kotlin.konan.file.withZipFileSystem
import org.jetbrains.kotlin.library.*
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
import org.jetbrains.kotlin.util.removeSuffixIfPresent
import java.nio.file.FileSystem
open class KotlinLibraryLayoutImpl(val klib: File) : KotlinLibraryLayout {