Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2020 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
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite.newInstance
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.backend.common.serialization.proto.Actual as ProtoActual
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructorCall as ProtoConstructorCall
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType as ProtoType
abstract class KotlinIrLinker(
private val currentModule: ModuleDescriptor?,
val logger: LoggingContext,
val builtIns: IrBuiltIns,
val symbolTable: SymbolTable,
private val exportedDependencies: List,
private val deserializeFakeOverrides: Boolean
) : IrDeserializer {
// Kotlin-MPP related data. Consider some refactoring
private val expectUniqIdToActualUniqId = mutableMapOf()
private val topLevelActualUniqItToDeserializer = mutableMapOf()
private val expectSymbols = mutableMapOf()
private val actualSymbols = mutableMapOf()
private val modulesWithReachableTopLevels = mutableSetOf()
protected val deserializersForModules = mutableMapOf()
abstract val fakeOverrideBuilder: FakeOverrideBuilder
abstract val translationPluginContext: TranslationPluginContext?
private val haveSeen = mutableSetOf()
private val fakeOverrideClassQueue = mutableListOf()
private lateinit var linkerExtensions: Collection
abstract inner class BasicIrModuleDeserializer(moduleDescriptor: ModuleDescriptor, override val klib: IrLibrary, override val strategy: DeserializationStrategy) :
IrModuleDeserializer(moduleDescriptor) {
private val fileToDeserializerMap = mutableMapOf()
private inner class ModuleDeserializationState {
private val filesWithPendingTopLevels = mutableSetOf()
fun enqueueFile(fileDeserializer: IrDeserializerForFile) {
filesWithPendingTopLevels.add(fileDeserializer)
enqueueModule()
}
fun addIdSignature(key: IdSignature) {
val fileDeserializer = moduleReversedFileIndex[key] ?: error("No file found for key $key")
fileDeserializer.fileLocalDeserializationState.addIdSignature(key)
enqueueFile(fileDeserializer)
}
fun processPendingDeclarations() {
while (filesWithPendingTopLevels.isNotEmpty()) {
val pendingDeserializer = filesWithPendingTopLevels.first()
pendingDeserializer.deserializeFileImplicitDataIfFirstUse()
pendingDeserializer.deserializeAllFileReachableTopLevel()
filesWithPendingTopLevels.remove(pendingDeserializer)
}
}
}
private val moduleDeserializationState = ModuleDeserializationState()
private val moduleReversedFileIndex = mutableMapOf()
override val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { resolveModuleDeserializer(it) }
}
override fun init(delegate: IrModuleDeserializer) {
val fileCount = klib.fileCount()
val files = ArrayList(fileCount)
for (i in 0 until fileCount) {
val fileStream = klib.file(i).codedInputStream
files.add(deserializeIrFile(ProtoFile.parseFrom(fileStream, newInstance()), i, delegate))
}
moduleFragment.files.addAll(files)
fileToDeserializerMap.values.forEach { it.deserializeExpectActualMapping() }
}
// TODO: fix to topLevel checker
override fun contains(idSig: IdSignature): Boolean = idSig in moduleReversedFileIndex
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
assert(idSig.isPublic)
val topLevelSignature = idSig.topLevelSignature()
val fileDeserializer = moduleReversedFileIndex[topLevelSignature]
?: error("No file for $topLevelSignature (@ $idSig) in module $moduleDescriptor")
val fileDeserializationState = fileDeserializer.fileLocalDeserializationState
fileDeserializationState.addIdSignature(topLevelSignature)
moduleDeserializationState.enqueueFile(fileDeserializer)
return fileDeserializationState.deserializedSymbols.getOrPut(idSig) {
// val descriptor = resolveSpecialSignature(idSig)
val symbol = referenceDeserializedSymbol(symbolKind, idSig)
handleExpectActualMapping(idSig, symbol)
}
}
override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList())
private fun deserializeIrFile(fileProto: ProtoFile, fileIndex: Int, moduleDeserializer: IrModuleDeserializer): IrFile {
val fileName = fileProto.fileEntry.name
val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray())
val fileDeserializer =
IrDeserializerForFile(fileProto.annotationList,
fileProto.actualsList,
fileIndex,
!strategy.needBodies,
strategy.inlineBodies,
deserializeFakeOverrides,
moduleDeserializer).apply {
// Explicitly exported declarations (e.g. top-level initializers) must be deserialized before all other declarations.
// Thus we schedule their deserialization in deserializer's constructor.
fileProto.explicitlyExportedToCompilerList.forEach {
val symbolData = parseSymbolData(it)
val sig = deserializeIdSignature(symbolData.signatureId)
assert(!sig.isPackageSignature())
fileLocalDeserializationState.addIdSignature(sig.topLevelSignature())
}
}
val fqName = FqName(fileDeserializer.deserializeFqName(fileProto.fqNameList))
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
val file = IrFileImpl(fileEntry, symbol, fqName)
fileDeserializer.file = file
fileToDeserializerMap[file] = fileDeserializer
val fileSignatureIndex = fileProto.declarationIdList.map { fileDeserializer.deserializeIdSignature(it) to it }
fileSignatureIndex.forEach {
moduleReversedFileIndex.getOrPut(it.first) { fileDeserializer }
}
fileDeserializer.reversedSignatureIndex = fileSignatureIndex.toMap()
if (strategy.theWholeWorld) {
for (id in fileSignatureIndex) {
moduleDeserializationState.addIdSignature(id.first)
}
moduleDeserializationState.enqueueFile(fileDeserializer)
} else if (strategy.explicitlyExported) {
moduleDeserializationState.enqueueFile(fileDeserializer)
}
return file
}
override fun deserializeReachableDeclarations() {
moduleDeserializationState.processPendingDeclarations()
}
private fun enqueueModule() {
modulesWithReachableTopLevels.add(this)
}
override fun addModuleReachableTopLevel(idSig: IdSignature) {
moduleDeserializationState.addIdSignature(idSig)
}
}
inner class IrDeserializerForFile(
private var annotations: List?,
private val actuals: List,
private val fileIndex: Int,
onlyHeaders: Boolean,
inlineBodies: Boolean,
deserializeFakeOverrides: Boolean,
private val moduleDeserializer: IrModuleDeserializer
) : IrFileDeserializer(logger, builtIns, symbolTable, !onlyHeaders, deserializeFakeOverrides, fakeOverrideClassQueue) {
private var fileLoops = mutableMapOf()
lateinit var file: IrFile
private val irTypeCache = mutableMapOf()
override val deserializeInlineFunctions: Boolean = inlineBodies
override val platformFakeOverrideClassFilter = fakeOverrideBuilder.platformSpecificClassFilter
var reversedSignatureIndex = emptyMap()
inner class FileDeserializationState {
private val reachableTopLevels = LinkedHashSet()
val deserializedSymbols = mutableMapOf()
fun addIdSignature(key: IdSignature) {
reachableTopLevels.add(key)
}
fun processPendingDeclarations() {
while (reachableTopLevels.isNotEmpty()) {
val reachableKey = reachableTopLevels.first()
val existedSymbol = deserializedSymbols[reachableKey]
if (existedSymbol == null || !existedSymbol.isBound) {
val declaration = deserializeDeclaration(reachableKey)
file.declarations.add(declaration)
}
reachableTopLevels.remove(reachableKey)
}
}
}
val fileLocalDeserializationState = FileDeserializationState()
fun deserializeDeclaration(idSig: IdSignature): IrDeclaration {
return deserializeDeclaration(loadTopLevelDeclarationProto(idSig), file)
}
fun deserializeExpectActualMapping() {
actuals.forEach {
val expectSymbol = parseSymbolData(it.expectSymbol)
val actualSymbol = parseSymbolData(it.actualSymbol)
val expect = deserializeIdSignature(expectSymbol.signatureId)
val actual = deserializeIdSignature(actualSymbol.signatureId)
assert(expectUniqIdToActualUniqId[expect] == null) {
"Expect signature $expect is already actualized by ${expectUniqIdToActualUniqId[expect]}, while we try to record $actual"
}
expectUniqIdToActualUniqId[expect] = actual
// Non-null only for topLevel declarations.
getModuleForTopLevelId(actual)?.let { md -> topLevelActualUniqItToDeserializer[actual] = md }
}
}
private fun resolveSignatureIndex(idSig: IdSignature): Int {
return reversedSignatureIndex[idSig] ?: error("Not found Idx for $idSig")
}
private fun readDeclaration(index: Int): CodedInputStream =
moduleDeserializer.klib.irDeclaration(index, fileIndex).codedInputStream
private fun loadTopLevelDeclarationProto(idSig: IdSignature): ProtoDeclaration {
val idSigIndex = resolveSignatureIndex(idSig)
return ProtoDeclaration.parseFrom(readDeclaration(idSigIndex), newInstance())
}
private fun readType(index: Int): CodedInputStream =
moduleDeserializer.klib.type(index, fileIndex).codedInputStream
private fun loadTypeProto(index: Int): ProtoType {
return ProtoType.parseFrom(readType(index), newInstance())
}
private fun readSignature(index: Int): CodedInputStream =
moduleDeserializer.klib.signature(index, fileIndex).codedInputStream
private fun loadSignatureProto(index: Int): ProtoIdSignature {
return ProtoIdSignature.parseFrom(readSignature(index), newInstance())
}
private fun readBody(index: Int): CodedInputStream =
moduleDeserializer.klib.body(index, fileIndex).codedInputStream
private fun loadStatementBodyProto(index: Int): ProtoStatement {
return ProtoStatement.parseFrom(readBody(index), newInstance())
}
private fun loadExpressionBodyProto(index: Int): ProtoExpression {
return ProtoExpression.parseFrom(readBody(index), newInstance())
}
private fun loadStringProto(index: Int): String {
return String(moduleDeserializer.klib.string(index, fileIndex))
}
private fun getModuleForTopLevelId(idSignature: IdSignature): IrModuleDeserializer? {
if (idSignature in moduleDeserializer) return moduleDeserializer
return moduleDeserializer.moduleDependencies.firstOrNull { idSignature in it }
}
private fun findModuleDeserializer(idSig: IdSignature): IrModuleDeserializer {
assert(idSig.isPublic)
val topLevelSig = idSig.topLevelSignature()
if (topLevelSig in moduleDeserializer) return moduleDeserializer
return moduleDeserializer.moduleDependencies.firstOrNull { topLevelSig in it } ?: handleNoModuleDeserializerFound(idSig)
}
private fun referenceIrSymbolData(symbol: IrSymbol, signature: IdSignature) {
assert(signature.isLocal)
fileLocalDeserializationState.deserializedSymbols.putIfAbsent(signature, symbol)
}
private fun deserializeIrLocalSymbolData(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
assert(idSig.isLocal)
if (idSig.hasTopLevel) {
fileLocalDeserializationState.addIdSignature(idSig.topLevelSignature())
}
return fileLocalDeserializationState.deserializedSymbols.getOrPut(idSig) {
referenceDeserializedSymbol(symbolKind, idSig)
}
}
private fun deserializeIrSymbolData(idSignature: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
if (idSignature.isLocal) return deserializeIrLocalSymbolData(idSignature, symbolKind)
return findModuleDeserializer(idSignature).deserializeIrSymbol(idSignature, symbolKind).also {
haveSeen.add(it)
}
}
override fun deserializeIrSymbolToDeclare(code: Long): Pair {
val symbolData = parseSymbolData(code)
val signature = deserializeIdSignature(symbolData.signatureId)
return Pair(deserializeIrSymbolData(signature, symbolData.kind), signature)
}
fun parseSymbolData(code: Long): BinarySymbolData = BinarySymbolData.decode(code)
override fun deserializeIrSymbol(code: Long): IrSymbol {
val symbolData = parseSymbolData(code)
val signature = deserializeIdSignature(symbolData.signatureId)
return deserializeIrSymbolData(signature, symbolData.kind)
}
override fun deserializeIrType(index: Int): IrType {
return irTypeCache.getOrPut(index) {
val typeData = loadTypeProto(index)
deserializeIrTypeData(typeData)
}
}
override fun deserializeIdSignature(index: Int): IdSignature {
val sigData = loadSignatureProto(index)
return deserializeSignatureData(sigData)
}
override fun deserializeString(index: Int): String =
loadStringProto(index)
override fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoop) =
fileLoops.getOrPut(loopIndex, loopBuilder)
override fun deserializeExpressionBody(index: Int): IrExpression {
return if (deserializeBodies) {
val bodyData = loadExpressionBodyProto(index)
deserializeExpression(bodyData)
} else {
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
IrErrorExpressionImpl(-1, -1, errorType, "Expression body is not deserialized yet")
}
}
override fun deserializeStatementBody(index: Int): IrElement {
return if (deserializeBodies) {
val bodyData = loadStatementBodyProto(index)
deserializeStatement(bodyData)
} else {
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
irFactory.createBlockBody(
-1, -1, listOf(IrErrorExpressionImpl(-1, -1, errorType, "Statement body is not deserialized yet"))
)
}
}
override fun referenceIrSymbol(symbol: IrSymbol, signature: IdSignature) {
referenceIrSymbolData(symbol, signature)
}
fun deserializeFileImplicitDataIfFirstUse() {
annotations?.let {
file.annotations += deserializeAnnotations(it)
annotations = null
}
}
fun deserializeAllFileReachableTopLevel() {
fileLocalDeserializationState.processPendingDeclarations()
}
}
private val ByteArray.codedInputStream: CodedInputStream
get() {
val codedInputStream = CodedInputStream.newInstance(this)
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
return codedInputStream
}
protected open fun handleNoModuleDeserializerFound(idSignature: IdSignature): IrModuleDeserializer {
error("Deserializer for declaration $idSignature is not found")
}
protected open fun resolveModuleDeserializer(moduleDescriptor: ModuleDescriptor): IrModuleDeserializer {
return deserializersForModules[moduleDescriptor] ?: error("No module deserializer found for $moduleDescriptor")
}
protected abstract fun createModuleDeserializer(
moduleDescriptor: ModuleDescriptor,
klib: IrLibrary?,
strategy: DeserializationStrategy,
): IrModuleDeserializer
protected abstract val functionalInterfaceFactory: IrAbstractFunctionFactory
protected abstract fun isBuiltInModule(moduleDescriptor: ModuleDescriptor): Boolean
// TODO: the following code worth some refactoring in the nearest future
private fun handleExpectActualMapping(idSig: IdSignature, rawSymbol: IrSymbol): IrSymbol {
val referencingSymbol = if (idSig in expectUniqIdToActualUniqId.keys) {
assert(idSig.run { IdSignature.Flags.IS_EXPECT.test() })
wrapInDelegatedSymbol(rawSymbol).also { expectSymbols[idSig] = it }
} else rawSymbol
if (idSig in expectUniqIdToActualUniqId.values) {
actualSymbols[idSig] = rawSymbol
}
return referencingSymbol
}
private fun referenceDeserializedSymbol(symbolKind: BinarySymbolData.SymbolKind, idSig: IdSignature): IrSymbol = symbolTable.run {
when (symbolKind) {
BinarySymbolData.SymbolKind.ANONYMOUS_INIT_SYMBOL -> IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor())
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(WrappedClassDescriptor(), idSig)
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(WrappedClassConstructorDescriptor(), idSig)
BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL -> referenceTypeParameterFromLinker(WrappedTypeParameterDescriptor(), idSig)
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(WrappedEnumEntryDescriptor(), idSig)
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(WrappedFieldDescriptor(), idSig)
BinarySymbolData.SymbolKind.FIELD_SYMBOL -> referenceFieldFromLinker(WrappedPropertyDescriptor(), idSig)
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(WrappedSimpleFunctionDescriptor(), idSig)
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(WrappedTypeAliasDescriptor(), idSig)
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(WrappedPropertyDescriptor(), idSig)
BinarySymbolData.SymbolKind.VARIABLE_SYMBOL -> IrVariableSymbolImpl(WrappedVariableDescriptor())
BinarySymbolData.SymbolKind.VALUE_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl(WrappedValueParameterDescriptor())
BinarySymbolData.SymbolKind.RECEIVER_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl(WrappedReceiverParameterDescriptor())
BinarySymbolData.SymbolKind.LOCAL_DELEGATED_PROPERTY_SYMBOL ->
IrLocalDelegatedPropertySymbolImpl(WrappedVariableDescriptorWithAccessor())
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
}
}
private fun deserializeAllReachableTopLevels() {
while (modulesWithReachableTopLevels.isNotEmpty()) {
val moduleDeserializer = modulesWithReachableTopLevels.first()
modulesWithReachableTopLevels.remove(moduleDeserializer)
moduleDeserializer.deserializeReachableDeclarations()
}
}
private fun findDeserializedDeclarationForSymbol(symbol: IrSymbol): DeclarationDescriptor? {
assert(symbol.isPublicApi || symbol.descriptor.module === currentModule || platformSpecificSymbol(symbol))
if (haveSeen.contains(symbol)) {
return null
}
haveSeen.add(symbol)
val descriptor = symbol.descriptor
val moduleDeserializer = resolveModuleDeserializer(descriptor.module)
// moduleDeserializer.deserializeIrSymbol(signature, symbol.kind())
moduleDeserializer.declareIrSymbol(symbol)
deserializeAllReachableTopLevels()
if (!symbol.isBound) return null
return descriptor
}
protected open fun platformSpecificSymbol(symbol: IrSymbol): Boolean = false
private fun tryResolveCustomDeclaration(symbol: IrSymbol): IrDeclaration? {
val descriptor = symbol.descriptor
if (descriptor is WrappedDeclarationDescriptor<*>) return null
if (descriptor is CallableMemberDescriptor) {
if (descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
// skip fake overrides
return null
}
}
return translationPluginContext?.let { ctx ->
linkerExtensions.firstNotNullResult {
it.resolveSymbol(symbol, ctx)
}?.also {
require(symbol.owner == it)
}
}
}
override fun getDeclaration(symbol: IrSymbol): IrDeclaration? {
if (!symbol.isPublicApi) {
val descriptor = symbol.descriptor
if (descriptor is WrappedDeclarationDescriptor<*>) return null
if (!platformSpecificSymbol(symbol)) {
if (descriptor.module !== currentModule) return null
}
}
if (!symbol.isBound) {
findDeserializedDeclarationForSymbol(symbol) ?: tryResolveCustomDeclaration(symbol) ?: return null
}
// TODO: we do have serializations for those, but let's just create a stub for now.
if (!symbol.isBound && (symbol.descriptor.isExpectMember || symbol.descriptor.containingDeclaration?.isExpectMember == true))
return null
if (!symbol.isBound) return null
//assert(symbol.isBound) {
// "getDeclaration: symbol $symbol is unbound, descriptor = ${symbol.descriptor}, signature = ${symbol.signature}"
//}
return symbol.owner as IrDeclaration
}
protected open fun createCurrentModuleDeserializer(moduleFragment: IrModuleFragment, dependencies: Collection): IrModuleDeserializer =
CurrentModuleDeserializer(moduleFragment, dependencies)
override fun init(moduleFragment: IrModuleFragment?, extensions: Collection) {
linkerExtensions = extensions
if (moduleFragment != null) {
val currentModuleDependencies = moduleFragment.descriptor.allDependencyModules.map {
deserializersForModules[it] ?: error("No deserializer found for $it")
}
val currentModuleDeserializer = createCurrentModuleDeserializer(moduleFragment, currentModuleDependencies)
deserializersForModules[moduleFragment.descriptor] =
maybeWrapWithBuiltInAndInit(moduleFragment.descriptor, currentModuleDeserializer)
}
deserializersForModules.values.forEach { it.init() }
}
override fun postProcess() {
finalizeExpectActualLinker()
while (fakeOverrideClassQueue.isNotEmpty()) {
val klass = fakeOverrideClassQueue.removeLast()
fakeOverrideBuilder.provideFakeOverrides(klass)
}
haveSeen.clear()
// TODO: fix IrPluginContext to make it not produce additional external reference
// symbolTable.noUnboundLeft("unbound after fake overrides:")
}
// The issue here is that an expect can not trigger its actual deserialization by reachability
// because the expect can not see the actual higher in the module dependency dag.
// So we force deserialization of actuals for all deserialized expect symbols here.
private fun finalizeExpectActualLinker() {
expectUniqIdToActualUniqId.filter { topLevelActualUniqItToDeserializer[it.value] != null }.forEach {
val expectSymbol = expectSymbols[it.key]
val actualSymbol = actualSymbols[it.value]
if (expectSymbol != null && (actualSymbol == null || !actualSymbol.isBound)) {
topLevelActualUniqItToDeserializer[it.value]!!.addModuleReachableTopLevel(it.value)
deserializeAllReachableTopLevels()
}
}
// Now after all actuals have been deserialized, retarget delegating symbols from expects to actuals.
expectUniqIdToActualUniqId.forEach {
val expectSymbol = expectSymbols[it.key]
val actualSymbol = actualSymbols[it.value]
if (expectSymbol != null && actualSymbol != null) {
when (expectSymbol) {
is IrDelegatingClassSymbolImpl ->
expectSymbol.delegate = actualSymbol as IrClassSymbol
is IrDelegatingEnumEntrySymbolImpl ->
expectSymbol.delegate = actualSymbol as IrEnumEntrySymbol
is IrDelegatingSimpleFunctionSymbolImpl ->
expectSymbol.delegate = actualSymbol as IrSimpleFunctionSymbol
is IrDelegatingConstructorSymbolImpl ->
expectSymbol.delegate = actualSymbol as IrConstructorSymbol
is IrDelegatingPropertySymbolImpl ->
expectSymbol.delegate = actualSymbol as IrPropertySymbol
else -> error("Unexpected expect symbol kind during actualization: $expectSymbol")
}
}
}
}
fun deserializeIrModuleHeader(
moduleDescriptor: ModuleDescriptor,
kotlinLibrary: KotlinLibrary?,
deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED
): IrModuleFragment {
val deserializerForModule = deserializersForModules.getOrPut(moduleDescriptor) {
maybeWrapWithBuiltInAndInit(moduleDescriptor, createModuleDeserializer(moduleDescriptor, kotlinLibrary, deserializationStrategy))
}
// The IrModule and its IrFiles have been created during module initialization.
return deserializerForModule.moduleFragment
}
private fun maybeWrapWithBuiltInAndInit(
moduleDescriptor: ModuleDescriptor,
moduleDeserializer: IrModuleDeserializer
): IrModuleDeserializer =
if (isBuiltInModule(moduleDescriptor)) IrModuleDeserializerWithBuiltIns(builtIns, functionalInterfaceFactory, moduleDeserializer)
else moduleDeserializer
fun deserializeIrModuleHeader(moduleDescriptor: ModuleDescriptor, kotlinLibrary: KotlinLibrary?): IrModuleFragment {
// TODO: consider skip deserializing explicitly exported declarations for libraries.
// Now it's not valid because of all dependencies that must be computed.
val deserializationStrategy =
if (exportedDependencies.contains(moduleDescriptor)) {
DeserializationStrategy.ALL
} else {
DeserializationStrategy.EXPLICITLY_EXPORTED
}
return deserializeIrModuleHeader(moduleDescriptor, kotlinLibrary, deserializationStrategy)
}
fun deserializeFullModule(moduleDescriptor: ModuleDescriptor, kotlinLibrary: KotlinLibrary?): IrModuleFragment =
deserializeIrModuleHeader(moduleDescriptor, kotlinLibrary, DeserializationStrategy.ALL)
fun deserializeOnlyHeaderModule(moduleDescriptor: ModuleDescriptor, kotlinLibrary: KotlinLibrary?): IrModuleFragment =
deserializeIrModuleHeader(moduleDescriptor, kotlinLibrary, DeserializationStrategy.ONLY_DECLARATION_HEADERS)
fun deserializeHeadersWithInlineBodies(moduleDescriptor: ModuleDescriptor, kotlinLibrary: KotlinLibrary?): IrModuleFragment =
deserializeIrModuleHeader(moduleDescriptor, kotlinLibrary, DeserializationStrategy.WITH_INLINE_BODIES)
}
enum class DeserializationStrategy(
val needBodies: Boolean,
val explicitlyExported: Boolean,
val theWholeWorld: Boolean,
val inlineBodies: Boolean
) {
ONLY_REFERENCED(true, false, false, true),
ALL(true, true, true, true),
EXPLICITLY_EXPORTED(true, true, false, true),
ONLY_DECLARATION_HEADERS(false, false, false, false),
WITH_INLINE_BODIES(false, false, false, true)
}