A little refactoring of deserializer in preparation for the next commit.

This commit is contained in:
Alexander Gorshenev
2019-03-21 18:09:07 +03:00
committed by alexander-gorshenev
parent 3bc4616a17
commit 215da10687
4 changed files with 140 additions and 112 deletions
@@ -1103,7 +1103,7 @@ abstract class IrModuleDeserializer(
val originIndex = allKnownOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name }
fun deserializeIrDeclarationOrigin(proto: KotlinIr.IrDeclarationOrigin) = originIndex[deserializeString(proto.custom)]!!
public open fun deserializeDeclaration(proto: KotlinIr.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration {
open fun deserializeDeclaration(proto: KotlinIr.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration {
val start = proto.coordinates.startOffset
val end = proto.coordinates.endOffset
@@ -38,6 +38,7 @@ abstract class KotlinIrLinker(
val logger: LoggingContext,
val builtIns: IrBuiltIns,
val symbolTable: SymbolTable,
val exportedDependencies: List<ModuleDescriptor>,
private val forwardModuleDescriptor: ModuleDescriptor?,
private val firstKnownBuiltinsIndex: Long
) : DescriptorUniqIdAware, IrDeserializer {
@@ -45,19 +46,24 @@ abstract class KotlinIrLinker(
protected val deserializedSymbols = mutableMapOf<UniqIdKey, IrSymbol>()
private val reachableTopLevels = mutableSetOf<UniqIdKey>()
private val deserializedTopLevels = mutableSetOf<UniqIdKey>()
//TODO: This is Native specific. Eliminate me.
private val forwardDeclarations = mutableSetOf<IrSymbol>()
private val deserializersForModules = mutableMapOf<ModuleDescriptor, IrDeserializerForModule>()
val resolvedForwardDeclarations = mutableMapOf<UniqIdKey, UniqIdKey>()
protected val deserializersForModules = mutableMapOf<ModuleDescriptor, IrDeserializerForModule>()
inner class IrDeserializerForModule(
private val moduleDescriptor: ModuleDescriptor,
private val moduleProto: KotlinIr.IrModule
private val moduleProto: KotlinIr.IrModule,
private val deserializationStrategy: DeserializationStrategy
) : IrModuleDeserializer(logger, builtIns, symbolTable) {
private var moduleLoops = mutableMapOf<Int, IrLoopBase>()
// This is a heavy initializer
val module = deserializeIrModuleHeader(moduleProto)
private fun referenceDeserializedSymbol(
proto: KotlinIr.IrSymbolData,
descriptor: DeclarationDescriptor?
@@ -176,12 +182,65 @@ abstract class KotlinIrLinker(
isSetter = proto.isSetter,
isTypeParameter = proto.isTypeParameter
)
// TODO: this is JS specific. Eliminate me.
override fun getPrimitiveTypeOrNull(symbol: IrClassifierSymbol, hasQuestionMark: Boolean) =
this@KotlinIrLinker.getPrimitiveTypeOrNull(symbol, hasQuestionMark)
fun deserializeIrFile(fileProto: KotlinIr.IrFile): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(
this.deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = this.deserializeString(fileProto.fqName)
.let { if (it == "<root>") FqName.ROOT else FqName(it) }
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
val file = IrFileImpl(fileEntry, symbol, fqName)
file.annotations.addAll(deserializeAnnotations(fileProto.annotations))
fileProto.declarationIdList.forEach {
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reversedFileIndex.put(uniqIdKey, file)
}
when (deserializationStrategy) {
DeserializationStrategy.EXPLICITLY_EXPORTED -> {
fileProto.explicitlyExportedToCompilerList.forEach {
val symbolProto = moduleProto.symbolTable.getSymbols(it.index)
reachableTopLevels.add(symbolProto.topLevelUniqId.uniqIdKey(moduleDescriptor))
}
}
DeserializationStrategy.ALL -> {
fileProto.declarationIdList.forEach {
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reachableTopLevels.add(uniqIdKey)
}
}
else -> error("Unixpected deserialization strategy")
}
return file
}
fun deserializeIrModuleHeader(
proto: KotlinIr.IrModule
): IrModuleFragment {
val files = proto.fileList.map {
deserializeIrFile(it)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null)
return module
}
}
// TODO: this is JS specific. Eliminate me.
protected open fun getPrimitiveTypeOrNull(symbol: IrClassifierSymbol, hasQuestionMark: Boolean): IrSimpleType? = null
protected abstract val descriptorReferenceDeserializer: DescriptorReferenceDeserializer
@@ -214,10 +273,8 @@ abstract class KotlinIrLinker(
private fun deserializeTopLevelDeclaration(uniqIdKey: UniqIdKey): IrDeclaration {
val proto = loadTopLevelDeclarationProto(uniqIdKey)
return deserializersForModules[uniqIdKey.moduleOfOrigin]!!.deserializeDeclaration(
proto,
reversedFileIndex[uniqIdKey]!!
)
return deserializersForModules[uniqIdKey.moduleOfOrigin]!!
.deserializeDeclaration(proto, reversedFileIndex[uniqIdKey]!!)
}
protected abstract fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId): ByteArray
@@ -227,6 +284,32 @@ abstract class KotlinIrLinker(
return KotlinIr.IrDeclaration.parseFrom(stream, newInstance())
}
private fun deserializeAllReachableTopLevels() {
do {
val key = reachableTopLevels.first()
val moduleOfOrigin = key.moduleOfOrigin
if (deserializedSymbols[key]?.isBound == true ||
// The key.moduleOrigin is null for uniqIds that we haven't seen in any of the library headers.
// Just skip it for now and handle it elsewhere.
moduleOfOrigin == null
) {
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
continue
}
val reachable = deserializeTopLevelDeclaration(key)
val file = reversedFileIndex[key]!!
file.declarations.add(reachable)
reachable.patchDeclarationParents(file)
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
} while (reachableTopLevels.isNotEmpty())
}
private fun findDeserializedDeclarationForDescriptor(descriptor: DeclarationDescriptor): DeclarationDescriptor? {
val topLevelDescriptor = descriptor.findTopLevelDescriptor()
@@ -247,29 +330,7 @@ abstract class KotlinIrLinker(
reachableTopLevels.add(topLevelKey)
do {
val key = reachableTopLevels.first()
if (deserializedSymbols[key]?.isBound == true ||
// The key.moduleOrigin is null for uniqIds that we haven't seen in any of the library headers.
// Just skip it for now and handle it elsewhere.
key.moduleOfOrigin == null
) {
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
continue
}
val reachable = deserializeTopLevelDeclaration(key)
val file = reversedFileIndex[key]!!
file.declarations.add(reachable)
reachable.patchDeclarationParents(file)
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
} while (reachableTopLevels.isNotEmpty())
deserializeAllReachableTopLevels()
return topLevelDescriptor
}
@@ -294,6 +355,7 @@ abstract class KotlinIrLinker(
?: error("findDeserializedDeclaration: property descriptor $propertyDescriptor} is not present in propertyTable after deserialization}")
}
// TODO: This is Native specific. Eliminate me.
override fun declareForwardDeclarations() {
if (forwardModuleDescriptor == null) return
@@ -328,71 +390,34 @@ abstract class KotlinIrLinker(
}
}
fun deserializeIrFile(
fileProto: KotlinIr.IrFile,
moduleDescriptor: ModuleDescriptor,
deseralizationStrategy: DeserializationStrategy
): IrFile {
val moduleDeserializer = deserializersForModules[moduleDescriptor]!!
val fileEntry = NaiveSourceBasedFileEntryImpl(
moduleDeserializer.deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = moduleDeserializer.deserializeString(fileProto.fqName)
.let { if (it == "<root>") FqName.ROOT else FqName(it) }
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
val file = IrFileImpl(fileEntry, symbol, fqName)
fileProto.declarationIdList.forEach {
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reversedFileIndex.put(uniqIdKey, file)
if (deseralizationStrategy == DeserializationStrategy.ALL) {
file.declarations.add(deserializeTopLevelDeclaration(uniqIdKey))
}
}
val annotations = moduleDeserializer.deserializeAnnotations(fileProto.annotations)
file.annotations.addAll(annotations)
if (deseralizationStrategy == DeserializationStrategy.EXPLICITLY_EXPORTED)
fileProto.explicitlyExportedToCompilerList.forEach { moduleDeserializer.deserializeIrSymbol(it) }
return file
}
fun deserializeIrModuleHeader(
proto: KotlinIr.IrModule,
moduleDescriptor: ModuleDescriptor,
deserializationStrategy: DeserializationStrategy
): IrModuleFragment {
deserializersForModules[moduleDescriptor] = IrDeserializerForModule(moduleDescriptor, proto)
val files = proto.fileList.map {
deserializeIrFile(it, moduleDescriptor, deserializationStrategy)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null)
return module
}
fun deserializeIrModuleHeader(
moduleDescriptor: ModuleDescriptor,
byteArray: ByteArray,
deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED
): IrModuleFragment {
val proto = KotlinIr.IrModule.parseFrom(byteArray.codedInputStream, newInstance())
return deserializeIrModuleHeader(proto, moduleDescriptor, deserializationStrategy)
val deserializerForModule = deserializersForModules.getOrPut(moduleDescriptor) {
val proto = KotlinIr.IrModule.parseFrom(byteArray.codedInputStream, newInstance())
IrDeserializerForModule(moduleDescriptor, proto, deserializationStrategy)
}
// The IrModule and its IrFiles have been created during module initialization.
return deserializerForModule.module
}
abstract val ModuleDescriptor.irHeader: ByteArray?
fun deserializeIrModuleHeader(moduleDescriptor: ModuleDescriptor): IrModuleFragment? =
// TODO: do we really allow libraries without any IR?
moduleDescriptor.irHeader?.let { header ->
// 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
}
deserializeIrModuleHeader(moduleDescriptor, header, deserializationStrategy)
}
}
enum class DeserializationStrategy {
@@ -9,7 +9,6 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.config.CommonConfigurationKeys
@@ -20,6 +19,8 @@ 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.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.backend.js.lower.inline.replaceUnboundSymbols
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsDeclarationTable
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrModuleSerializer
@@ -64,8 +65,9 @@ enum class CompilationMode {
JS
}
private val moduleHeaderFileName = "module.kji"
private val declarationsDirName = "ir/"
internal val JS_KLIBRARY_CAPABILITY = ModuleDescriptor.Capability<File>("JS KLIBRARY")
internal val moduleHeaderFileName = "module.kji"
internal val declarationsDirName = "ir/"
private val logggg = object : LoggingContext {
override var inVerbosePhase: Boolean
get() = TODO("not implemented")
@@ -144,7 +146,7 @@ fun compile(
val deserializedModuleFragments = sortedImmediateDependencies.map {
val moduleFile = File(it.klibPath, moduleHeaderFileName)
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it), moduleFile.readBytes(), File(it.klibPath), DeserializationStrategy.ONLY_REFERENCED)
deserializer.deserializeIrModuleHeader(depsDescriptors.getModuleDescriptor(it))!!
}
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files, deserializer)
@@ -220,7 +222,8 @@ private fun loadKlibMetadata(
): ModuleDescriptorImpl {
assert(isBuiltIn == (builtinsModule === null))
val builtIns = builtinsModule?.builtIns ?: object : KotlinBuiltIns(storageManager) {}
val md = ModuleDescriptorImpl(Name.special("<${moduleId.moduleName}>"), storageManager, builtIns)
val md = ModuleDescriptorImpl(Name.special("<${moduleId.moduleName}>"), storageManager, builtIns,
capabilities = mapOf(JS_KLIBRARY_CAPABILITY to File(moduleId.klibPath)))
if (isBuiltIn) builtIns.builtInsModule = md
val currentModuleFragmentProvider = createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.backend.common.library.DeclarationId
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.backend.js.JS_KLIBRARY_CAPABILITY
import org.jetbrains.kotlin.ir.backend.js.moduleHeaderFileName
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.util.SymbolTable
@@ -20,8 +22,8 @@ class JsIrLinker(
currentModule: ModuleDescriptor,
logger: LoggingContext,
builtIns: IrBuiltIns,
symbolTable: SymbolTable) :
KotlinIrLinker(logger, builtIns, symbolTable, null, 0x1_0000_0000L),
symbolTable: SymbolTable
) : KotlinIrLinker(logger, builtIns, symbolTable, emptyList<ModuleDescriptor>(), null, 0x1_0000_0000L),
DescriptorUniqIdAware by JsDescriptorUniqIdAware {
private val FUNCTION_INDEX_START: Long = indexAfterKnownBuiltins
@@ -34,20 +36,17 @@ class JsIrLinker(
override val descriptorReferenceDeserializer =
JsDescriptorReferenceDeserializer(currentModule, builtIns, FUNCTION_INDEX_START)
override fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId) =
moduleToReaderMap[moduleDescriptor]!!.declarationBytes(DeclarationId(uniqId.index, uniqId.isLocal))
fun deserializeIrModuleHeader(
moduleDescriptor: ModuleDescriptor,
byteArray: ByteArray,
klibLocation: File,
deserializationStrategy: DeserializationStrategy
): IrModuleFragment {
val irFile = File(klibLocation, "ir/irCombined.knd")
moduleToReaderMap[moduleDescriptor] = CombinedIrFileReader(irFile)
return deserializeIrModuleHeader(moduleDescriptor, byteArray, deserializationStrategy)
override fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId): ByteArray {
val irFileReader = moduleToReaderMap.getOrPut(moduleDescriptor) {
val irFile = File(moduleDescriptor.getCapability(JS_KLIBRARY_CAPABILITY)!!, "ir/irCombined.knd")
CombinedIrFileReader(irFile)
}
return irFileReader.declarationBytes(DeclarationId(uniqId.index, uniqId.isLocal))
}
override val ModuleDescriptor.irHeader: ByteArray? get() =
this.getCapability(JS_KLIBRARY_CAPABILITY)?.let { File(it, moduleHeaderFileName).readBytes() }
override fun declareForwardDeclarations() {
// since for `knownBuiltIns` such as FunctionN it is possible to have unbound symbols after deserialization
// reference them through out lazy symbol table
@@ -61,3 +60,4 @@ class JsIrLinker(
}
}
}