Refactor klib serializer/deserializer

This commit is contained in:
Anton Bannykh
2020-12-15 20:09:54 +03:00
parent ad9fd7ecf3
commit bc9a791809
10 changed files with 2012 additions and 1926 deletions
@@ -0,0 +1,182 @@
/*
* 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.serialization.encodings.BinarySymbolData
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile
abstract class BasicIrModuleDeserializer(
val linker: KotlinIrLinker,
moduleDescriptor: ModuleDescriptor,
override val klib: IrLibrary,
override val strategy: DeserializationStrategy,
private val containsErrorCode: Boolean = false
) :
IrModuleDeserializer(moduleDescriptor) {
private val fileToDeserializerMap = mutableMapOf<IrFile, IrFileDeserializer>()
private val moduleDeserializationState = ModuleDeserializationState(linker, this)
internal val moduleReversedFileIndex = mutableMapOf<IdSignature, FileDeserializationState>()
override val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { linker.resolveModuleDeserializer(it, null) }
}
override fun init(delegate: IrModuleDeserializer) {
val fileCount = klib.fileCount()
val files = ArrayList<IrFile>(fileCount)
for (i in 0 until fileCount) {
val fileStream = klib.file(i).codedInputStream
val fileProto = ProtoFile.parseFrom(fileStream, ExtensionRegistryLite.newInstance())
files.add(deserializeIrFile(fileProto, i, delegate, containsErrorCode))
}
moduleFragment.files.addAll(files)
fileToDeserializerMap.values.forEach { it.symbolDeserializer.deserializeExpectActualMapping() }
}
private fun IrSymbolDeserializer.deserializeExpectActualMapping() {
actuals.forEach {
val expectSymbol = parseSymbolData(it.expectSymbol)
val actualSymbol = parseSymbolData(it.actualSymbol)
val expect = deserializeIdSignature(expectSymbol.signatureId)
val actual = deserializeIdSignature(actualSymbol.signatureId)
assert(linker.expectUniqIdToActualUniqId[expect] == null) {
"Expect signature $expect is already actualized by ${linker.expectUniqIdToActualUniqId[expect]}, while we try to record $actual"
}
linker.expectUniqIdToActualUniqId[expect] = actual
// Non-null only for topLevel declarations.
findModuleDeserializerForTopLevelId(actual)?.let { md -> linker.topLevelActualUniqItToDeserializer[actual] = md }
}
}
override fun referenceSimpleFunctionByLocalSignature(file: IrFile, idSignature: IdSignature) : IrSimpleFunctionSymbol =
fileToDeserializerMap[file]?.symbolDeserializer?.referenceSimpleFunctionByLocalSignature(idSignature)
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
override fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
fileToDeserializerMap[file]?.symbolDeserializer?.referencePropertyByLocalSignature(idSignature)
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
// 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 fileLocalDeserializationState = moduleReversedFileIndex[topLevelSignature]
?: error("No file for $topLevelSignature (@ $idSig) in module $moduleDescriptor")
fileLocalDeserializationState.addIdSignature(topLevelSignature)
moduleDeserializationState.enqueueFile(fileLocalDeserializationState)
return fileLocalDeserializationState.fileDeserializer.symbolDeserializer.deserializeIrSymbol(idSig, symbolKind).also {
linker.deserializedSymbols.add(it)
}
}
override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, linker.builtIns, emptyList())
private fun deserializeIrFile(fileProto: ProtoFile, fileIndex: Int, moduleDeserializer: IrModuleDeserializer, allowErrorNodes: Boolean): IrFile {
val fileReader = IrLibraryFileFromKlib(moduleDeserializer.klib, fileIndex)
val file = fileReader.createFile(moduleDescriptor, fileProto)
val fileDeserializationState = FileDeserializationState(
linker,
file,
fileReader,
fileProto,
strategy.needBodies,
allowErrorNodes,
strategy.inlineBodies,
moduleDeserializer,
linker::handleNoModuleDeserializerFound,
)
fileToDeserializerMap[file] = fileDeserializationState.fileDeserializer
val topLevelDeclarations = fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys
topLevelDeclarations.forEach {
moduleReversedFileIndex.putIfAbsent(it, fileDeserializationState) // TODO Why not simple put?
}
if (strategy.theWholeWorld) {
fileDeserializationState.enqueueAllDeclarations()
}
if (strategy.theWholeWorld || strategy.explicitlyExported) {
moduleDeserializationState.enqueueFile(fileDeserializationState)
}
return file
}
// TODO useless
override fun addModuleReachableTopLevel(idSig: IdSignature) {
moduleDeserializationState.addIdSignature(idSig)
}
}
internal class ModuleDeserializationState(val linker: KotlinIrLinker, val moduleDeserializer: BasicIrModuleDeserializer) {
private val filesWithPendingTopLevels = mutableSetOf<FileDeserializationState>()
fun enqueueFile(fileDeserializationState: FileDeserializationState) {
filesWithPendingTopLevels.add(fileDeserializationState)
linker.modulesWithReachableTopLevels.add(this)
}
fun addIdSignature(key: IdSignature) {
val fileLocalDeserializationState = moduleDeserializer.moduleReversedFileIndex[key] ?: error("No file found for key $key")
fileLocalDeserializationState.addIdSignature(key)
enqueueFile(fileLocalDeserializationState)
}
fun deserializeReachableDeclarations() {
while (filesWithPendingTopLevels.isNotEmpty()) {
val pendingFileDeserializationState = filesWithPendingTopLevels.first()
pendingFileDeserializationState.fileDeserializer.deserializeFileImplicitDataIfFirstUse()
pendingFileDeserializationState.deserializeAllFileReachableTopLevel()
filesWithPendingTopLevels.remove(pendingFileDeserializationState)
}
}
override fun toString(): String = moduleDeserializer.klib.toString()
}
fun IrModuleDeserializer.findModuleDeserializerForTopLevelId(idSignature: IdSignature): IrModuleDeserializer? {
if (idSignature in this) return this
return moduleDependencies.firstOrNull { idSignature in it }
}
internal val ByteArray.codedInputStream: CodedInputStream
get() {
val codedInputStream = CodedInputStream.newInstance(this)
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
return codedInputStream
}
@@ -100,10 +100,6 @@ class CurrentModuleWithICDeserializer(
icDeserializer.addModuleReachableTopLevel(idSig)
}
override fun deserializeReachableDeclarations() {
icDeserializer.deserializeReachableDeclarations()
}
private fun DeclarationDescriptor.isDirtyDescriptor(): Boolean {
if (this is PropertyAccessorDescriptor) return correspondingProperty.isDirtyDescriptor()
// Since descriptors for FO methods of `kotlin.Any` (toString, equals, hashCode) are Deserialized even in
@@ -0,0 +1,787 @@
/*
* 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.serialization.encodings.*
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConst.ValueCase.*
import org.jetbrains.kotlin.backend.common.serialization.proto.IrOperation.OperationCase.*
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement.StatementCase
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVarargElement.VarargElementCase
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBlock as ProtoBlock
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBlockBody as ProtoBlockBody
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBranch as ProtoBranch
import org.jetbrains.kotlin.backend.common.serialization.proto.IrBreak as ProtoBreak
import org.jetbrains.kotlin.backend.common.serialization.proto.IrCall as ProtoCall
import org.jetbrains.kotlin.backend.common.serialization.proto.IrCatch as ProtoCatch
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClassReference as ProtoClassReference
import org.jetbrains.kotlin.backend.common.serialization.proto.IrComposite as ProtoComposite
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConst as ProtoConst
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructorCall as ProtoConstructorCall
import org.jetbrains.kotlin.backend.common.serialization.proto.IrContinue as ProtoContinue
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDelegatingConstructorCall as ProtoDelegatingConstructorCall
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDoWhile as ProtoDoWhile
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDynamicMemberExpression as ProtoDynamicMemberExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDynamicOperatorExpression as ProtoDynamicOperatorExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrEnumConstructorCall as ProtoEnumConstructorCall
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunctionExpression as ProtoFunctionExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorExpression as ProtoErrorExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorCallExpression as ProtoErrorCallExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunctionReference as ProtoFunctionReference
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetClass as ProtoGetClass
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetEnumValue as ProtoGetEnumValue
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetField as ProtoGetField
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetObject as ProtoGetObject
import org.jetbrains.kotlin.backend.common.serialization.proto.IrGetValue as ProtoGetValue
import org.jetbrains.kotlin.backend.common.serialization.proto.IrInstanceInitializerCall as ProtoInstanceInitializerCall
import org.jetbrains.kotlin.backend.common.serialization.proto.IrLocalDelegatedPropertyReference as ProtoLocalDelegatedPropertyReference
import org.jetbrains.kotlin.backend.common.serialization.proto.IrOperation as ProtoOperation
import org.jetbrains.kotlin.backend.common.serialization.proto.IrPropertyReference as ProtoPropertyReference
import org.jetbrains.kotlin.backend.common.serialization.proto.IrReturn as ProtoReturn
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSetField as ProtoSetField
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSetValue as ProtoSetValue
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSpreadElement as ProtoSpreadElement
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStringConcat as ProtoStringConcat
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSyntheticBody as ProtoSyntheticBody
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSyntheticBodyKind as ProtoSyntheticBodyKind
import org.jetbrains.kotlin.backend.common.serialization.proto.IrThrow as ProtoThrow
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTry as ProtoTry
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeOp as ProtoTypeOp
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeOperator as ProtoTypeOperator
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVararg as ProtoVararg
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVarargElement as ProtoVarargElement
import org.jetbrains.kotlin.backend.common.serialization.proto.IrWhen as ProtoWhen
import org.jetbrains.kotlin.backend.common.serialization.proto.IrWhile as ProtoWhile
import org.jetbrains.kotlin.backend.common.serialization.proto.Loop as ProtoLoop
import org.jetbrains.kotlin.backend.common.serialization.proto.MemberAccessCommon as ProtoMemberAccessCommon
class IrBodyDeserializer(
private val builtIns: IrBuiltIns,
private val allowErrorNodes: Boolean,
private val irFactory: IrFactory,
private val fileReader: IrLibraryFile,
private val declarationDeserializer: IrDeclarationDeserializer,
) {
private val fileLoops = mutableMapOf<Int, IrLoop>()
private fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoop): IrLoop =
fileLoops.getOrPut(loopIndex, loopBuilder)
private fun deserializeBlockBody(
proto: ProtoBlockBody,
start: Int, end: Int
): IrBlockBody {
val statements = mutableListOf<IrStatement>()
val statementProtos = proto.statementList
statementProtos.forEach {
statements.add(deserializeStatement(it) as IrStatement)
}
return irFactory.createBlockBody(start, end, statements)
}
private fun deserializeBranch(proto: ProtoBranch, start: Int, end: Int): IrBranch {
val condition = deserializeExpression(proto.condition)
val result = deserializeExpression(proto.result)
return IrBranchImpl(start, end, condition, result)
}
private fun deserializeCatch(proto: ProtoCatch, start: Int, end: Int): IrCatch {
val catchParameter = declarationDeserializer.deserializeIrVariable(proto.catchParameter)
val result = deserializeExpression(proto.result)
return IrCatchImpl(start, end, catchParameter, result)
}
private fun deserializeSyntheticBody(proto: ProtoSyntheticBody, start: Int, end: Int): IrSyntheticBody {
val kind = when (proto.kind!!) {
ProtoSyntheticBodyKind.ENUM_VALUES -> IrSyntheticBodyKind.ENUM_VALUES
ProtoSyntheticBodyKind.ENUM_VALUEOF -> IrSyntheticBodyKind.ENUM_VALUEOF
}
return IrSyntheticBodyImpl(start, end, kind)
}
internal fun deserializeStatement(proto: ProtoStatement): IrElement {
val coordinates = BinaryCoordinates.decode(proto.coordinates)
val start = coordinates.startOffset
val end = coordinates.endOffset
val element = when (proto.statementCase) {
StatementCase.BLOCK_BODY //proto.hasBlockBody()
-> deserializeBlockBody(proto.blockBody, start, end)
StatementCase.BRANCH //proto.hasBranch()
-> deserializeBranch(proto.branch, start, end)
StatementCase.CATCH //proto.hasCatch()
-> deserializeCatch(proto.catch, start, end)
StatementCase.DECLARATION // proto.hasDeclaration()
-> declarationDeserializer.deserializeDeclaration(proto.declaration)
StatementCase.EXPRESSION // proto.hasExpression()
-> deserializeExpression(proto.expression)
StatementCase.SYNTHETIC_BODY // proto.hasSyntheticBody()
-> deserializeSyntheticBody(proto.syntheticBody, start, end)
else
-> TODO("Statement deserialization not implemented: ${proto.statementCase}")
}
return element
}
private fun deserializeBlock(proto: ProtoBlock, start: Int, end: Int, type: IrType): IrBlock {
val statements = mutableListOf<IrStatement>()
val statementProtos = proto.statementList
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
statementProtos.forEach {
statements.add(deserializeStatement(it) as IrStatement)
}
return IrBlockImpl(start, end, type, origin, statements)
}
private fun deserializeMemberAccessCommon(access: IrMemberAccessExpression<*>, proto: ProtoMemberAccessCommon) {
proto.valueArgumentList.mapIndexed { i, arg ->
if (arg.hasExpression()) {
val expr = deserializeExpression(arg.expression)
access.putValueArgument(i, expr)
}
}
proto.typeArgumentList.mapIndexed { i, arg ->
access.putTypeArgument(i, declarationDeserializer.deserializeIrType(arg))
}
if (proto.hasDispatchReceiver()) {
access.dispatchReceiver = deserializeExpression(proto.dispatchReceiver)
}
if (proto.hasExtensionReceiver()) {
access.extensionReceiver = deserializeExpression(proto.extensionReceiver)
}
}
private fun deserializeClassReference(
proto: ProtoClassReference,
start: Int,
end: Int,
type: IrType
): IrClassReference {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.classSymbol) as IrClassifierSymbol
val classType = declarationDeserializer.deserializeIrType(proto.classType)
/** TODO: [createClassifierSymbolForClassReference] is internal function */
return IrClassReferenceImpl(start, end, type, symbol, classType)
}
fun deserializeAnnotation(proto: ProtoConstructorCall): IrConstructorCall {
return deserializeConstructorCall(proto, 0, 0, builtIns.unitType) // TODO: need a proper deserialization here
}
fun deserializeConstructorCall(proto: ProtoConstructorCall, start: Int, end: Int, type: IrType): IrConstructorCall {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrConstructorSymbol
return IrConstructorCallImpl(
start, end, type,
symbol, typeArgumentsCount = proto.memberAccess.typeArgumentCount,
constructorTypeArgumentsCount = proto.constructorTypeArgumentsCount,
valueArgumentsCount = proto.memberAccess.valueArgumentCount
).also {
deserializeMemberAccessCommon(it, proto.memberAccess)
}
}
private fun deserializeCall(proto: ProtoCall, start: Int, end: Int, type: IrType): IrCall {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrSimpleFunctionSymbol
val superSymbol = if (proto.hasSuper()) {
declarationDeserializer.deserializeIrSymbolAndRemap(proto.`super`) as IrClassSymbol
} else null
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
val call: IrCall =
// TODO: implement the last three args here.
IrCallImpl(
start, end, type,
symbol, proto.memberAccess.typeArgumentCount,
proto.memberAccess.valueArgumentList.size,
origin,
superSymbol
)
deserializeMemberAccessCommon(call, proto.memberAccess)
return call
}
private fun deserializeComposite(proto: ProtoComposite, start: Int, end: Int, type: IrType): IrComposite {
val statements = mutableListOf<IrStatement>()
val statementProtos = proto.statementList
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
statementProtos.forEach {
statements.add(deserializeStatement(it) as IrStatement)
}
return IrCompositeImpl(start, end, type, origin, statements)
}
private fun deserializeDelegatingConstructorCall(
proto: ProtoDelegatingConstructorCall,
start: Int,
end: Int
): IrDelegatingConstructorCall {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrConstructorSymbol
val call = IrDelegatingConstructorCallImpl(
start,
end,
builtIns.unitType,
symbol,
proto.memberAccess.typeArgumentCount,
proto.memberAccess.valueArgumentCount
)
deserializeMemberAccessCommon(call, proto.memberAccess)
return call
}
private fun deserializeEnumConstructorCall(
proto: ProtoEnumConstructorCall,
start: Int,
end: Int,
): IrEnumConstructorCall {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrConstructorSymbol
val call = IrEnumConstructorCallImpl(
start,
end,
builtIns.unitType,
symbol,
proto.memberAccess.typeArgumentCount,
proto.memberAccess.valueArgumentCount
)
deserializeMemberAccessCommon(call, proto.memberAccess)
return call
}
private fun deserializeFunctionExpression(
functionExpression: ProtoFunctionExpression,
start: Int,
end: Int,
type: IrType
) =
IrFunctionExpressionImpl(
start, end, type,
declarationDeserializer.deserializeIrFunction(functionExpression.function),
deserializeIrStatementOrigin(functionExpression.originName)
)
private fun deserializeErrorExpression(
proto: ProtoErrorExpression,
start: Int, end: Int, type: IrType
): IrErrorExpression {
require(allowErrorNodes) {
"IrErrorExpression($start, $end, \"${fileReader.deserializeString(proto.description)}\") found but error code is not allowed"
}
return IrErrorExpressionImpl(start, end, type, fileReader.deserializeString(proto.description))
}
private fun deserializeErrorCallExpression(
proto: ProtoErrorCallExpression,
start: Int, end: Int, type: IrType
): IrErrorCallExpression {
require(allowErrorNodes) {
"IrErrorCallExpressionImpl($start, $end, \"${fileReader.deserializeString(proto.description)}\") found but error code is not allowed"
}
return IrErrorCallExpressionImpl(start, end, type, fileReader.deserializeString(proto.description)).apply {
if (proto.hasReceiver()) {
explicitReceiver = deserializeExpression(proto.receiver)
}
proto.valueArgumentList.forEach {
addArgument(deserializeExpression(it))
}
}
}
private fun deserializeFunctionReference(
proto: ProtoFunctionReference,
start: Int, end: Int, type: IrType
): IrFunctionReference {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrFunctionSymbol
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
val reflectionTarget =
if (proto.hasReflectionTargetSymbol()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.reflectionTargetSymbol) as IrFunctionSymbol else null
val callable = IrFunctionReferenceImpl(
start,
end,
type,
symbol,
proto.memberAccess.typeArgumentCount,
proto.memberAccess.valueArgumentCount,
reflectionTarget,
origin
)
deserializeMemberAccessCommon(callable, proto.memberAccess)
return callable
}
private fun deserializeGetClass(proto: ProtoGetClass, start: Int, end: Int, type: IrType): IrGetClass {
val argument = deserializeExpression(proto.argument)
return IrGetClassImpl(start, end, type, argument)
}
private fun deserializeGetField(proto: ProtoGetField, start: Int, end: Int, type: IrType): IrGetField {
val access = proto.fieldAccess
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrFieldSymbol
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
val superQualifier = if (access.hasSuper()) {
declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrClassSymbol
} else null
val receiver = if (access.hasReceiver()) {
deserializeExpression(access.receiver)
} else null
return IrGetFieldImpl(start, end, symbol, type, receiver, origin, superQualifier)
}
private fun deserializeGetValue(proto: ProtoGetValue, start: Int, end: Int, type: IrType): IrGetValue {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrValueSymbol
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
// TODO: origin!
return IrGetValueImpl(start, end, type, symbol, origin)
}
private fun deserializeGetEnumValue(
proto: ProtoGetEnumValue,
start: Int,
end: Int,
type: IrType
): IrGetEnumValue {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrEnumEntrySymbol
return IrGetEnumValueImpl(start, end, type, symbol)
}
private fun deserializeGetObject(
proto: ProtoGetObject,
start: Int,
end: Int,
type: IrType
): IrGetObjectValue {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrClassSymbol
return IrGetObjectValueImpl(start, end, type, symbol)
}
private fun deserializeInstanceInitializerCall(
proto: ProtoInstanceInitializerCall,
start: Int,
end: Int
): IrInstanceInitializerCall {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrClassSymbol
return IrInstanceInitializerCallImpl(start, end, symbol, builtIns.unitType)
}
private fun deserializeIrLocalDelegatedPropertyReference(
proto: ProtoLocalDelegatedPropertyReference,
start: Int,
end: Int,
type: IrType
): IrLocalDelegatedPropertyReference {
val delegate = declarationDeserializer.deserializeIrSymbolAndRemap(proto.delegate) as IrVariableSymbol
val getter = declarationDeserializer.deserializeIrSymbolAndRemap(proto.getter) as IrSimpleFunctionSymbol
val setter = if (proto.hasSetter()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.setter) as IrSimpleFunctionSymbol else null
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrLocalDelegatedPropertySymbol
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
return IrLocalDelegatedPropertyReferenceImpl(
start, end, type,
symbol,
delegate,
getter,
setter,
origin
)
}
private fun deserializePropertyReference(proto: ProtoPropertyReference, start: Int, end: Int, type: IrType): IrPropertyReference {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrPropertySymbol
val field = if (proto.hasField()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.field) as IrFieldSymbol else null
val getter = if (proto.hasGetter()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.getter) as IrSimpleFunctionSymbol else null
val setter = if (proto.hasSetter()) declarationDeserializer.deserializeIrSymbolAndRemap(proto.setter) as IrSimpleFunctionSymbol else null
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
val callable = IrPropertyReferenceImpl(
start, end, type,
symbol,
proto.memberAccess.typeArgumentCount,
field,
getter,
setter,
origin
)
deserializeMemberAccessCommon(callable, proto.memberAccess)
return callable
}
private fun deserializeReturn(proto: ProtoReturn, start: Int, end: Int): IrReturn {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.returnTarget) as IrReturnTargetSymbol
val value = deserializeExpression(proto.value)
return IrReturnImpl(start, end, builtIns.nothingType, symbol, value)
}
private fun deserializeSetField(proto: ProtoSetField, start: Int, end: Int): IrSetField {
val access = proto.fieldAccess
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrFieldSymbol
val superQualifier = if (access.hasSuper()) {
declarationDeserializer.deserializeIrSymbolAndRemap(access.symbol) as IrClassSymbol
} else null
val receiver = if (access.hasReceiver()) {
deserializeExpression(access.receiver)
} else null
val value = deserializeExpression(proto.value)
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
return IrSetFieldImpl(start, end, symbol, receiver, value, builtIns.unitType, origin, superQualifier)
}
private fun deserializeSetValue(proto: ProtoSetValue, start: Int, end: Int): IrSetValue {
val symbol = declarationDeserializer.deserializeIrSymbolAndRemap(proto.symbol) as IrVariableSymbol
val value = deserializeExpression(proto.value)
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
return IrSetValueImpl(start, end, builtIns.unitType, symbol, value, origin)
}
private fun deserializeSpreadElement(proto: ProtoSpreadElement): IrSpreadElement {
val expression = deserializeExpression(proto.expression)
val coordinates = BinaryCoordinates.decode(proto.coordinates)
return IrSpreadElementImpl(coordinates.startOffset, coordinates.endOffset, expression)
}
private fun deserializeStringConcat(proto: ProtoStringConcat, start: Int, end: Int, type: IrType): IrStringConcatenation {
val argumentProtos = proto.argumentList
val arguments = mutableListOf<IrExpression>()
argumentProtos.forEach {
arguments.add(deserializeExpression(it))
}
return IrStringConcatenationImpl(start, end, type, arguments)
}
private fun deserializeThrow(proto: ProtoThrow, start: Int, end: Int): IrThrowImpl {
return IrThrowImpl(start, end, builtIns.nothingType, deserializeExpression(proto.value))
}
private fun deserializeTry(proto: ProtoTry, start: Int, end: Int, type: IrType): IrTryImpl {
val result = deserializeExpression(proto.result)
val catches = mutableListOf<IrCatch>()
proto.catchList.forEach {
catches.add(deserializeStatement(it) as IrCatch)
}
val finallyExpression =
if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null
return IrTryImpl(start, end, type, result, catches, finallyExpression)
}
private fun deserializeTypeOperator(operator: ProtoTypeOperator) = when (operator) {
ProtoTypeOperator.CAST ->
IrTypeOperator.CAST
ProtoTypeOperator.IMPLICIT_CAST ->
IrTypeOperator.IMPLICIT_CAST
ProtoTypeOperator.IMPLICIT_NOTNULL ->
IrTypeOperator.IMPLICIT_NOTNULL
ProtoTypeOperator.IMPLICIT_COERCION_TO_UNIT ->
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
ProtoTypeOperator.IMPLICIT_INTEGER_COERCION ->
IrTypeOperator.IMPLICIT_INTEGER_COERCION
ProtoTypeOperator.SAFE_CAST ->
IrTypeOperator.SAFE_CAST
ProtoTypeOperator.INSTANCEOF ->
IrTypeOperator.INSTANCEOF
ProtoTypeOperator.NOT_INSTANCEOF ->
IrTypeOperator.NOT_INSTANCEOF
ProtoTypeOperator.SAM_CONVERSION ->
IrTypeOperator.SAM_CONVERSION
ProtoTypeOperator.IMPLICIT_DYNAMIC_CAST ->
IrTypeOperator.IMPLICIT_DYNAMIC_CAST
}
private fun deserializeTypeOp(proto: ProtoTypeOp, start: Int, end: Int, type: IrType): IrTypeOperatorCall {
val operator = deserializeTypeOperator(proto.operator)
val operand = declarationDeserializer.deserializeIrType(proto.operand)//.brokenIr
val argument = deserializeExpression(proto.argument)
return IrTypeOperatorCallImpl(start, end, type, operator, operand, argument)
}
private fun deserializeVararg(proto: ProtoVararg, start: Int, end: Int, type: IrType): IrVararg {
val elementType = declarationDeserializer.deserializeIrType(proto.elementType)
val elements = mutableListOf<IrVarargElement>()
proto.elementList.forEach {
elements.add(deserializeVarargElement(it))
}
return IrVarargImpl(start, end, type, elementType, elements)
}
private fun deserializeVarargElement(element: ProtoVarargElement): IrVarargElement {
return when (element.varargElementCase) {
VarargElementCase.EXPRESSION
-> deserializeExpression(element.expression)
VarargElementCase.SPREAD_ELEMENT
-> deserializeSpreadElement(element.spreadElement)
else
-> TODO("Unexpected vararg element")
}
}
private fun deserializeWhen(proto: ProtoWhen, start: Int, end: Int, type: IrType): IrWhen {
val branches = mutableListOf<IrBranch>()
val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null
proto.branchList.forEach {
branches.add(deserializeStatement(it) as IrBranch)
}
// TODO: provide some origin!
return IrWhenImpl(start, end, type, origin, branches)
}
private fun deserializeLoop(proto: ProtoLoop, loop: IrLoop): IrLoop {
val label = if (proto.hasLabel()) fileReader.deserializeString(proto.label) else null
val body = if (proto.hasBody()) deserializeExpression(proto.body) else null
val condition = deserializeExpression(proto.condition)
loop.label = label
loop.condition = condition
loop.body = body
return loop
}
// we create the loop before deserializing the body, so that
// IrBreak statements have something to put into 'loop' field.
private fun deserializeDoWhile(proto: ProtoDoWhile, start: Int, end: Int, type: IrType) =
deserializeLoop(
proto.loop,
deserializeLoopHeader(proto.loop.loopId) {
val origin = if (proto.loop.hasOriginName()) deserializeIrStatementOrigin(proto.loop.originName) else null
IrDoWhileLoopImpl(start, end, type, origin)
}
)
private fun deserializeWhile(proto: ProtoWhile, start: Int, end: Int, type: IrType) =
deserializeLoop(
proto.loop,
deserializeLoopHeader(proto.loop.loopId) {
val origin = if (proto.loop.hasOriginName()) deserializeIrStatementOrigin(proto.loop.originName) else null
IrWhileLoopImpl(start, end, type, origin)
}
)
private fun deserializeDynamicMemberExpression(
proto: ProtoDynamicMemberExpression,
start: Int,
end: Int,
type: IrType
) =
IrDynamicMemberExpressionImpl(
start,
end,
type,
fileReader.deserializeString(proto.memberName),
deserializeExpression(proto.receiver)
)
private fun deserializeDynamicOperatorExpression(
proto: ProtoDynamicOperatorExpression,
start: Int,
end: Int,
type: IrType
) =
IrDynamicOperatorExpressionImpl(start, end, type, deserializeDynamicOperator(proto.operator)).apply {
receiver = deserializeExpression(proto.receiver)
proto.argumentList.mapTo(arguments) { deserializeExpression(it) }
}
private fun deserializeDynamicOperator(operator: ProtoDynamicOperatorExpression.IrDynamicOperator) =
when (operator) {
ProtoDynamicOperatorExpression.IrDynamicOperator.UNARY_PLUS -> IrDynamicOperator.UNARY_PLUS
ProtoDynamicOperatorExpression.IrDynamicOperator.UNARY_MINUS -> IrDynamicOperator.UNARY_MINUS
ProtoDynamicOperatorExpression.IrDynamicOperator.EXCL -> IrDynamicOperator.EXCL
ProtoDynamicOperatorExpression.IrDynamicOperator.PREFIX_INCREMENT -> IrDynamicOperator.PREFIX_INCREMENT
ProtoDynamicOperatorExpression.IrDynamicOperator.PREFIX_DECREMENT -> IrDynamicOperator.PREFIX_DECREMENT
ProtoDynamicOperatorExpression.IrDynamicOperator.POSTFIX_INCREMENT -> IrDynamicOperator.POSTFIX_INCREMENT
ProtoDynamicOperatorExpression.IrDynamicOperator.POSTFIX_DECREMENT -> IrDynamicOperator.POSTFIX_DECREMENT
ProtoDynamicOperatorExpression.IrDynamicOperator.BINARY_PLUS -> IrDynamicOperator.BINARY_PLUS
ProtoDynamicOperatorExpression.IrDynamicOperator.BINARY_MINUS -> IrDynamicOperator.BINARY_MINUS
ProtoDynamicOperatorExpression.IrDynamicOperator.MUL -> IrDynamicOperator.MUL
ProtoDynamicOperatorExpression.IrDynamicOperator.DIV -> IrDynamicOperator.DIV
ProtoDynamicOperatorExpression.IrDynamicOperator.MOD -> IrDynamicOperator.MOD
ProtoDynamicOperatorExpression.IrDynamicOperator.GT -> IrDynamicOperator.GT
ProtoDynamicOperatorExpression.IrDynamicOperator.LT -> IrDynamicOperator.LT
ProtoDynamicOperatorExpression.IrDynamicOperator.GE -> IrDynamicOperator.GE
ProtoDynamicOperatorExpression.IrDynamicOperator.LE -> IrDynamicOperator.LE
ProtoDynamicOperatorExpression.IrDynamicOperator.EQEQ -> IrDynamicOperator.EQEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.EXCLEQ -> IrDynamicOperator.EXCLEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.EQEQEQ -> IrDynamicOperator.EQEQEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.EXCLEQEQ -> IrDynamicOperator.EXCLEQEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.ANDAND -> IrDynamicOperator.ANDAND
ProtoDynamicOperatorExpression.IrDynamicOperator.OROR -> IrDynamicOperator.OROR
ProtoDynamicOperatorExpression.IrDynamicOperator.EQ -> IrDynamicOperator.EQ
ProtoDynamicOperatorExpression.IrDynamicOperator.PLUSEQ -> IrDynamicOperator.PLUSEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.MINUSEQ -> IrDynamicOperator.MINUSEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.MULEQ -> IrDynamicOperator.MULEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.DIVEQ -> IrDynamicOperator.DIVEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.MODEQ -> IrDynamicOperator.MODEQ
ProtoDynamicOperatorExpression.IrDynamicOperator.ARRAY_ACCESS -> IrDynamicOperator.ARRAY_ACCESS
ProtoDynamicOperatorExpression.IrDynamicOperator.INVOKE -> IrDynamicOperator.INVOKE
}
private fun deserializeBreak(proto: ProtoBreak, start: Int, end: Int, type: IrType): IrBreak {
val label = if (proto.hasLabel()) fileReader.deserializeString(proto.label) else null
val loopId = proto.loopId
val loop = deserializeLoopHeader(loopId) { error("break clause before loop header") }
val irBreak = IrBreakImpl(start, end, type, loop)
irBreak.label = label
return irBreak
}
private fun deserializeContinue(proto: ProtoContinue, start: Int, end: Int, type: IrType): IrContinue {
val label = if (proto.hasLabel()) fileReader.deserializeString(proto.label) else null
val loopId = proto.loopId
val loop = deserializeLoopHeader(loopId) { error("continue clause before loop header") }
val irContinue = IrContinueImpl(start, end, type, loop)
irContinue.label = label
return irContinue
}
private fun deserializeConst(proto: ProtoConst, start: Int, end: Int, type: IrType): IrExpression =
when (proto.valueCase!!) {
NULL
-> IrConstImpl.constNull(start, end, type)
BOOLEAN
-> IrConstImpl.boolean(start, end, type, proto.boolean)
BYTE
-> IrConstImpl.byte(start, end, type, proto.byte.toByte())
CHAR
-> IrConstImpl.char(start, end, type, proto.char.toChar())
SHORT
-> IrConstImpl.short(start, end, type, proto.short.toShort())
INT
-> IrConstImpl.int(start, end, type, proto.int)
LONG
-> IrConstImpl.long(start, end, type, proto.long)
STRING
-> IrConstImpl.string(start, end, type, fileReader.deserializeString(proto.string))
FLOAT_BITS
-> IrConstImpl.float(start, end, type, Float.fromBits(proto.floatBits))
DOUBLE_BITS
-> IrConstImpl.double(start, end, type, Double.fromBits(proto.doubleBits))
VALUE_NOT_SET
-> error("Const deserialization error: ${proto.valueCase} ")
}
private fun deserializeOperation(proto: ProtoOperation, start: Int, end: Int, type: IrType): IrExpression =
when (proto.operationCase!!) {
BLOCK -> deserializeBlock(proto.block, start, end, type)
BREAK -> deserializeBreak(proto.`break`, start, end, type)
CLASS_REFERENCE -> deserializeClassReference(proto.classReference, start, end, type)
CALL -> deserializeCall(proto.call, start, end, type)
COMPOSITE -> deserializeComposite(proto.composite, start, end, type)
CONST -> deserializeConst(proto.const, start, end, type)
CONTINUE -> deserializeContinue(proto.`continue`, start, end, type)
DELEGATING_CONSTRUCTOR_CALL -> deserializeDelegatingConstructorCall(proto.delegatingConstructorCall, start, end)
DO_WHILE -> deserializeDoWhile(proto.doWhile, start, end, type)
ENUM_CONSTRUCTOR_CALL -> deserializeEnumConstructorCall(proto.enumConstructorCall, start, end)
FUNCTION_REFERENCE -> deserializeFunctionReference(proto.functionReference, start, end, type)
GET_ENUM_VALUE -> deserializeGetEnumValue(proto.getEnumValue, start, end, type)
GET_CLASS -> deserializeGetClass(proto.getClass, start, end, type)
GET_FIELD -> deserializeGetField(proto.getField, start, end, type)
GET_OBJECT -> deserializeGetObject(proto.getObject, start, end, type)
GET_VALUE -> deserializeGetValue(proto.getValue, start, end, type)
LOCAL_DELEGATED_PROPERTY_REFERENCE -> deserializeIrLocalDelegatedPropertyReference(
proto.localDelegatedPropertyReference,
start,
end,
type
)
INSTANCE_INITIALIZER_CALL -> deserializeInstanceInitializerCall(proto.instanceInitializerCall, start, end)
PROPERTY_REFERENCE -> deserializePropertyReference(proto.propertyReference, start, end, type)
RETURN -> deserializeReturn(proto.`return`, start, end)
SET_FIELD -> deserializeSetField(proto.setField, start, end)
SET_VALUE -> deserializeSetValue(proto.setValue, start, end)
STRING_CONCAT -> deserializeStringConcat(proto.stringConcat, start, end, type)
THROW -> deserializeThrow(proto.`throw`, start, end)
TRY -> deserializeTry(proto.`try`, start, end, type)
TYPE_OP -> deserializeTypeOp(proto.typeOp, start, end, type)
VARARG -> deserializeVararg(proto.vararg, start, end, type)
WHEN -> deserializeWhen(proto.`when`, start, end, type)
WHILE -> deserializeWhile(proto.`while`, start, end, type)
DYNAMIC_MEMBER -> deserializeDynamicMemberExpression(proto.dynamicMember, start, end, type)
DYNAMIC_OPERATOR -> deserializeDynamicOperatorExpression(proto.dynamicOperator, start, end, type)
CONSTRUCTOR_CALL -> deserializeConstructorCall(proto.constructorCall, start, end, type)
FUNCTION_EXPRESSION -> deserializeFunctionExpression(proto.functionExpression, start, end, type)
ERROR_EXPRESSION -> deserializeErrorExpression(proto.errorExpression, start, end, type)
ERROR_CALL_EXPRESSION -> deserializeErrorCallExpression(proto.errorCallExpression, start, end, type)
OPERATION_NOT_SET -> error("Expression deserialization not implemented: ${proto.operationCase}")
}
fun deserializeExpression(proto: ProtoExpression): IrExpression {
val coordinates = BinaryCoordinates.decode(proto.coordinates)
val start = coordinates.startOffset
val end = coordinates.endOffset
val type = declarationDeserializer.deserializeIrType(proto.type)
val operation = proto.operation
val expression = deserializeOperation(operation, start, end, type)
return expression
}
fun deserializeIrStatementOrigin(protoName: Int): IrStatementOrigin {
return fileReader.deserializeString(protoName).let {
val componentPrefix = "COMPONENT_"
when {
it.startsWith(componentPrefix) -> {
IrStatementOrigin.COMPONENT_N.withIndex(it.removePrefix(componentPrefix).toInt())
}
else -> statementOriginIndex[it] ?: error("Unexpected statement origin: $it")
}
}
}
companion object {
private val allKnownStatementOrigins = IrStatementOrigin::class.nestedClasses.toList()
private val statementOriginIndex =
allKnownStatementOrigins.mapNotNull { it.objectInstance as? IrStatementOriginImpl }.associateBy { it.debugName }
}
}
@@ -0,0 +1,695 @@
/*
* 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.lower.InnerClassesSupport
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter
import org.jetbrains.kotlin.backend.common.serialization.encodings.*
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration.DeclaratorCase.*
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType.KindCase.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.backend.common.serialization.proto.IrAnonymousInit as ProtoAnonymousInit
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructor as ProtoConstructor
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.IrDeclarationBase as ProtoDeclarationBase
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDynamicType as ProtoDynamicType
import org.jetbrains.kotlin.backend.common.serialization.proto.IrEnumEntry as ProtoEnumEntry
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorType as ProtoErrorType
import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunction as ProtoFunction
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunctionBase as ProtoFunctionBase
import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorDeclaration as ProtoErrorDeclaration
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement
import org.jetbrains.kotlin.backend.common.serialization.proto.IrLocalDelegatedProperty as ProtoLocalDelegatedProperty
import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty
import org.jetbrains.kotlin.backend.common.serialization.proto.IrSimpleType as ProtoSimpleType
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType as ProtoType
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeAbbreviation as ProtoTypeAbbreviation
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeAlias as ProtoTypeAlias
import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeParameter as ProtoTypeParameter
import org.jetbrains.kotlin.backend.common.serialization.proto.IrValueParameter as ProtoValueParameter
import org.jetbrains.kotlin.backend.common.serialization.proto.IrVariable as ProtoVariable
class IrDeclarationDeserializer(
builtIns: IrBuiltIns,
private val symbolTable: SymbolTable,
private val irFactory: IrFactory,
private val fileReader: IrLibraryFile,
file: IrFile,
private val allowErrorNodes: Boolean,
private val deserializeInlineFunctions: Boolean,
private var deserializeBodies: Boolean,
private val symbolDeserializer: IrSymbolDeserializer,
private val platformFakeOverrideClassFilter: FakeOverrideClassFilter,
private val fakeOverrideBuilder: FakeOverrideBuilder,
) {
private val bodyDeserializer = IrBodyDeserializer(builtIns, allowErrorNodes, irFactory, fileReader, this)
private fun deserializeName(index: Int): Name {
val name = fileReader.deserializeString(index)
return Name.guessByFirstCharacter(name)
}
private val irTypeCache = mutableMapOf<Int, IrType>()
private fun readType(index: Int): CodedInputStream =
fileReader.type(index).codedInputStream
private fun loadTypeProto(index: Int): ProtoType {
return ProtoType.parseFrom(readType(index), ExtensionRegistryLite.newInstance())
}
internal fun deserializeIrType(index: Int): IrType {
return irTypeCache.getOrPut(index) {
val typeData = loadTypeProto(index)
deserializeIrTypeData(typeData)
}
}
private fun deserializeIrTypeArgument(proto: Long): IrTypeArgument {
val encoding = BinaryTypeProjection.decode(proto)
if (encoding.isStarProjection) return IrStarProjectionImpl
return makeTypeProjection(deserializeIrType(encoding.typeIndex), encoding.variance)
}
internal fun deserializeAnnotations(annotations: List<ProtoConstructorCall>): List<IrConstructorCall> {
return annotations.map {
bodyDeserializer.deserializeAnnotation(it)
}
}
private fun deserializeSimpleType(proto: ProtoSimpleType): IrSimpleType {
val symbol = deserializeIrSymbolAndRemap(proto.classifier) as? IrClassifierSymbol
?: error("could not convert sym to ClassifierSymbol")
val arguments = proto.argumentList.map { deserializeIrTypeArgument(it) }
val annotations = deserializeAnnotations(proto.annotationList)
val result: IrSimpleType = IrSimpleTypeImpl(
null,
symbol,
proto.hasQuestionMark,
arguments,
annotations,
if (proto.hasAbbreviation()) deserializeTypeAbbreviation(proto.abbreviation) else null
)
return result
}
private fun deserializeTypeAbbreviation(proto: ProtoTypeAbbreviation): IrTypeAbbreviation =
IrTypeAbbreviationImpl(
deserializeIrSymbolAndRemap(proto.typeAlias).let {
it as? IrTypeAliasSymbol
?: error("IrTypeAliasSymbol expected: $it")
},
proto.hasQuestionMark,
proto.argumentList.map { deserializeIrTypeArgument(it) },
deserializeAnnotations(proto.annotationList)
)
private fun deserializeDynamicType(proto: ProtoDynamicType): IrDynamicType {
val annotations = deserializeAnnotations(proto.annotationList)
return IrDynamicTypeImpl(null, annotations, Variance.INVARIANT)
}
private fun deserializeErrorType(proto: ProtoErrorType): IrErrorType {
require(allowErrorNodes) { "IrErrorType found but error code is not allowed" }
val annotations = deserializeAnnotations(proto.annotationList)
return IrErrorTypeImpl(null, annotations, Variance.INVARIANT)
}
private fun deserializeIrTypeData(proto: ProtoType): IrType {
return when (proto.kindCase) {
SIMPLE -> deserializeSimpleType(proto.simple)
DYNAMIC -> deserializeDynamicType(proto.dynamic)
ERROR -> deserializeErrorType(proto.error)
else -> error("Unexpected IrType kind: ${proto.kindCase}")
}
}
private var currentParent: IrDeclarationParent = file
private inline fun <T : IrDeclarationParent> T.usingParent(block: T.() -> Unit): T =
this.apply {
val oldParent = currentParent
currentParent = this
try {
block(this)
} finally {
currentParent = oldParent
}
}
// Delegating symbol maps to it's delegate only inside the declaration the symbol belongs to.
private val delegatedSymbolMap = mutableMapOf<IrSymbol, IrSymbol>()
internal fun deserializeIrSymbolAndRemap(code: Long): IrSymbol {
// TODO: could be simplified
return symbolDeserializer.deserializeIrSymbol(code).let {
delegatedSymbolMap[it] ?: it
}
}
private fun recordDelegatedSymbol(symbol: IrSymbol) {
if (symbol is IrDelegatingSymbol<*, *, *>) {
delegatedSymbolMap[symbol] = symbol.delegate
}
}
private fun eraseDelegatedSymbol(symbol: IrSymbol) {
if (symbol is IrDelegatingSymbol<*, *, *>) {
delegatedSymbolMap.remove(symbol)
}
}
private inline fun <T> withDeserializedIrDeclarationBase(
proto: ProtoDeclarationBase,
block: (IrSymbol, IdSignature, Int, Int, IrDeclarationOrigin, Long) -> T
): T where T : IrDeclaration, T : IrSymbolOwner {
val (s, uid) = symbolDeserializer.deserializeIrSymbolToDeclare(proto.symbol)
val coordinates = BinaryCoordinates.decode(proto.coordinates)
try {
recordDelegatedSymbol(s)
val result = block(
s,
uid,
coordinates.startOffset, coordinates.endOffset,
deserializeIrDeclarationOrigin(proto.originName), proto.flags
)
result.annotations += deserializeAnnotations(proto.annotationList)
result.parent = currentParent
return result
} finally {
eraseDelegatedSymbol(s)
}
}
private fun deserializeIrTypeParameter(proto: ProtoTypeParameter, index: Int, isGlobal: Boolean): IrTypeParameter {
val name = deserializeName(proto.name)
val coordinates = BinaryCoordinates.decode(proto.base.coordinates)
val flags = TypeParameterFlags.decode(proto.base.flags)
val factory = { symbol: IrTypeParameterSymbol ->
irFactory.createTypeParameter(
coordinates.startOffset,
coordinates.endOffset,
deserializeIrDeclarationOrigin(proto.base.originName),
symbol,
name,
index,
flags.isReified,
flags.variance
)
}
val sig: IdSignature
val result = symbolTable.run {
if (isGlobal) {
val p = symbolDeserializer.deserializeIrSymbolToDeclare(proto.base.symbol)
val symbol = p.first as IrTypeParameterSymbol
sig = p.second
declareGlobalTypeParameter(sig, { symbol }, factory)
} else {
val symbolData = BinarySymbolData
.decode(proto.base.symbol)
sig = symbolDeserializer.deserializeIdSignature(symbolData.signatureId)
declareScopedTypeParameter(sig, { IrTypeParameterSymbolImpl() }, factory)
}
}
// make sure this symbol is known to linker
symbolDeserializer.referenceLocalIrSymbol(result.symbol, sig)
result.annotations += deserializeAnnotations(proto.base.annotationList)
result.parent = currentParent
return result
}
private fun deserializeIrValueParameter(proto: ProtoValueParameter, index: Int): IrValueParameter =
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, fcode ->
val flags = ValueParameterFlags.decode(fcode)
val nameAndType = BinaryNameAndType.decode(proto.nameType)
irFactory.createValueParameter(
startOffset, endOffset, origin,
symbol as IrValueParameterSymbol,
deserializeName(nameAndType.nameIndex),
index,
deserializeIrType(nameAndType.typeIndex),
if (proto.hasVarargElementType()) deserializeIrType(proto.varargElementType) else null,
flags.isCrossInline,
flags.isNoInline,
flags.isHidden,
flags.isAssignable
).apply {
if (proto.hasDefaultValue())
defaultValue = deserializeExpressionBody(proto.defaultValue)
}
}
private fun deserializeIrClass(proto: ProtoClass): IrClass =
withDeserializedIrDeclarationBase(proto.base) { symbol, signature, startOffset, endOffset, origin, fcode ->
val flags = ClassFlags.decode(fcode)
symbolTable.declareClass(signature, { symbol as IrClassSymbol }) {
irFactory.createClass(
startOffset, endOffset, origin,
it,
deserializeName(proto.name),
flags.kind,
flags.visibility,
flags.modality,
flags.isCompanion,
flags.isInner,
flags.isData,
flags.isExternal,
flags.isInline,
flags.isExpect,
flags.isFun,
)
}.usingParent {
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
superTypes = proto.superTypeList.map { deserializeIrType(it) }
proto.declarationList
.filterNot { isSkippableFakeOverride(it, this) }
.mapTo(declarations) { deserializeDeclaration(it) }
thisReceiver = deserializeIrValueParameter(proto.thisReceiver, -1)
fakeOverrideBuilder.enqueueClass(this, signature)
}
}
private fun deserializeIrTypeAlias(proto: ProtoTypeAlias): IrTypeAlias =
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode ->
require(symbol is IrTypeAliasSymbol)
symbolTable.declareTypeAlias(uniqId, { symbol }) {
val flags = TypeAliasFlags.decode(fcode)
val nameType = BinaryNameAndType.decode(proto.nameType)
irFactory.createTypeAlias(
startOffset, endOffset,
it,
deserializeName(nameType.nameIndex),
flags.visibility,
deserializeIrType(nameType.typeIndex),
flags.isActual,
origin
)
}.usingParent {
typeParameters = deserializeTypeParameters(proto.typeParameterList, true)
}
}
private fun deserializeErrorDeclaration(proto: ProtoErrorDeclaration): IrErrorDeclaration {
require(allowErrorNodes) { "IrErrorDeclaration found but error code is not allowed" }
val coordinates = BinaryCoordinates.decode(proto.coordinates)
return irFactory.createErrorDeclaration(coordinates.startOffset, coordinates.endOffset).also {
it.parent = currentParent
}
}
private fun deserializeTypeParameters(protos: List<ProtoTypeParameter>, isGlobal: Boolean): List<IrTypeParameter> {
// NOTE: fun <C : MutableCollection<in T>, T : Any> Array<out T?>.filterNotNullTo(destination: C): C
val result = ArrayList<IrTypeParameter>(protos.size)
for (index in protos.indices) {
val proto = protos[index]
result.add(deserializeIrTypeParameter(proto, index, isGlobal))
}
for (i in protos.indices) {
result[i].superTypes = protos[i].superTypeList.map { deserializeIrType(it) }
}
return result
}
private fun deserializeValueParameters(protos: List<ProtoValueParameter>): List<IrValueParameter> {
val result = ArrayList<IrValueParameter>(protos.size)
for (i in protos.indices) {
result.add(deserializeIrValueParameter(protos[i], i))
}
return result
}
/**
* In `declarations-only` mode in case of private property/function with inferred anonymous private type like this
* class C {
* private val p = object {
* fun foo() = 42
* }
*
* private fun f() = object {
* fun bar() = "42"
* }
*
* private val pp = p.foo()
* private fun ff() = f().bar()
* }
* object's classifier is leaked outside p/f scopes and accessible on C's level so
* if their initializer/body weren't read we have unbound `foo/bar` symbol and unbound `object` symbols.
* To fix this make sure that such declaration forced to be deserialized completely.
*
* For more information see `anonymousClassLeak.kt` test and issue KT-40216
*/
private fun IrType.checkObjectLeak(): Boolean {
return if (this is IrSimpleType) {
classifier.let { !it.isPublicApi && it !is IrTypeParameterSymbol } || arguments.any { it.typeOrNull?.checkObjectLeak() == true }
} else false
}
private fun <T : IrFunction> T.withBodyGuard(block: T.() -> Unit) {
val oldBodiesPolicy = deserializeBodies
fun checkInlineBody(): Boolean = deserializeInlineFunctions && this is IrSimpleFunction && isInline
try {
deserializeBodies = oldBodiesPolicy || checkInlineBody() || returnType.checkObjectLeak()
block()
} finally {
deserializeBodies = oldBodiesPolicy
}
}
private fun IrField.withInitializerGuard(f: IrField.() -> Unit) {
val oldBodiesPolicy = deserializeBodies
try {
deserializeBodies = oldBodiesPolicy || type.checkObjectLeak()
f()
} finally {
deserializeBodies = oldBodiesPolicy
}
}
private fun readBody(index: Int): CodedInputStream =
fileReader.body(index).codedInputStream
private fun loadStatementBodyProto(index: Int): ProtoStatement {
return ProtoStatement.parseFrom(readBody(index), ExtensionRegistryLite.newInstance())
}
private fun loadExpressionBodyProto(index: Int): ProtoExpression {
return ProtoExpression.parseFrom(readBody(index), ExtensionRegistryLite.newInstance())
}
private fun deserializeExpressionBody(index: Int): IrExpressionBody {
return irFactory.createExpressionBody(
if (deserializeBodies) {
val bodyData = loadExpressionBodyProto(index)
bodyDeserializer.deserializeExpression(bodyData)
} else {
val errorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
IrErrorExpressionImpl(-1, -1, errorType, "Expression body is not deserialized yet")
}
)
}
private fun deserializeStatementBody(index: Int): IrElement {
return if (deserializeBodies) {
val bodyData = loadStatementBodyProto(index)
bodyDeserializer.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"))
)
}
}
private inline fun <T : IrFunction> withDeserializedIrFunctionBase(
proto: ProtoFunctionBase,
block: (IrFunctionSymbol, IdSignature, Int, Int, IrDeclarationOrigin, Long) -> T
): T = withDeserializedIrDeclarationBase(proto.base) { symbol, idSig, startOffset, endOffset, origin, fcode ->
symbolTable.withScope(symbol) {
block(symbol as IrFunctionSymbol, idSig, startOffset, endOffset, origin, fcode).usingParent {
typeParameters = deserializeTypeParameters(proto.typeParameterList, false)
val nameType = BinaryNameAndType.decode(proto.nameType)
returnType = deserializeIrType(nameType.typeIndex)
withBodyGuard {
valueParameters = deserializeValueParameters(proto.valueParameterList)
if (proto.hasDispatchReceiver())
dispatchReceiverParameter = deserializeIrValueParameter(proto.dispatchReceiver, -1)
if (proto.hasExtensionReceiver())
extensionReceiverParameter = deserializeIrValueParameter(proto.extensionReceiver, -1)
if (proto.hasBody()) {
body = deserializeStatementBody(proto.body) as IrBody
}
}
}
}
}
internal fun deserializeIrFunction(proto: ProtoFunction): IrSimpleFunction {
return withDeserializedIrFunctionBase(proto.base) { symbol, idSig, startOffset, endOffset, origin, fcode ->
val flags = FunctionFlags.decode(fcode)
symbolTable.declareSimpleFunction(idSig, { symbol as IrSimpleFunctionSymbol }) {
val nameType = BinaryNameAndType.decode(proto.base.nameType)
irFactory.createFunction(
startOffset, endOffset, origin,
it,
deserializeName(nameType.nameIndex),
flags.visibility,
flags.modality,
IrUninitializedType,
flags.isInline,
flags.isExternal,
flags.isTailrec,
flags.isSuspend,
flags.isOperator,
flags.isInfix,
flags.isExpect,
flags.isFakeOverride
)
}.apply {
overriddenSymbols = proto.overriddenList.map { deserializeIrSymbolAndRemap(it) as IrSimpleFunctionSymbol }
}
}
}
internal fun deserializeIrVariable(proto: ProtoVariable): IrVariable =
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, fcode ->
val flags = LocalVariableFlags.decode(fcode)
val nameType = BinaryNameAndType.decode(proto.nameType)
IrVariableImpl(
startOffset, endOffset, origin,
symbol as IrVariableSymbol,
deserializeName(nameType.nameIndex),
deserializeIrType(nameType.typeIndex),
flags.isVar,
flags.isConst,
flags.isLateinit
).apply {
if (proto.hasInitializer())
initializer = bodyDeserializer.deserializeExpression(proto.initializer)
}
}
private fun deserializeIrEnumEntry(proto: ProtoEnumEntry): IrEnumEntry =
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, _ ->
symbolTable.declareEnumEntry(uniqId, { symbol as IrEnumEntrySymbol }) {
irFactory.createEnumEntry(startOffset, endOffset, origin, it, deserializeName(proto.name))
}.apply {
if (proto.hasCorrespondingClass())
correspondingClass = deserializeIrClass(proto.correspondingClass)
if (proto.hasInitializer())
initializerExpression = deserializeExpressionBody(proto.initializer)
}
}
private fun deserializeIrAnonymousInit(proto: ProtoAnonymousInit): IrAnonymousInitializer =
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, _ ->
irFactory.createAnonymousInitializer(startOffset, endOffset, origin, symbol as IrAnonymousInitializerSymbol).apply {
body = deserializeStatementBody(proto.body) as IrBlockBody
}
}
private fun deserializeIrConstructor(proto: ProtoConstructor): IrConstructor =
withDeserializedIrFunctionBase(proto.base) { symbol, idSig, startOffset, endOffset, origin, fcode ->
require(symbol is IrConstructorSymbol)
val flags = FunctionFlags.decode(fcode)
val nameType = BinaryNameAndType.decode(proto.base.nameType)
symbolTable.declareConstructor(idSig, { symbol }) {
irFactory.createConstructor(
startOffset, endOffset, origin,
it,
deserializeName(nameType.nameIndex),
flags.visibility,
IrUninitializedType,
flags.isInline,
flags.isExternal,
flags.isPrimary,
flags.isExpect
)
}
}
private fun deserializeIrField(proto: ProtoField): IrField =
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode ->
require(symbol is IrFieldSymbol)
val nameType = BinaryNameAndType.decode(proto.nameType)
val type = deserializeIrType(nameType.typeIndex)
val flags = FieldFlags.decode(fcode)
symbolTable.declareField(uniqId, { symbol }) {
irFactory.createField(
startOffset, endOffset, origin,
it,
deserializeName(nameType.nameIndex),
type,
flags.visibility,
flags.isFinal,
flags.isExternal,
flags.isStatic,
)
}.usingParent {
if (proto.hasInitializer()) {
withInitializerGuard {
initializer = deserializeExpressionBody(proto.initializer)
}
}
}
}
private fun deserializeIrLocalDelegatedProperty(proto: ProtoLocalDelegatedProperty): IrLocalDelegatedProperty =
withDeserializedIrDeclarationBase(proto.base) { symbol, _, startOffset, endOffset, origin, fcode ->
val flags = LocalVariableFlags.decode(fcode)
val nameAndType = BinaryNameAndType.decode(proto.nameType)
irFactory.createLocalDelegatedProperty(
startOffset, endOffset, origin,
symbol as IrLocalDelegatedPropertySymbol,
deserializeName(nameAndType.nameIndex),
deserializeIrType(nameAndType.typeIndex),
flags.isVar
).apply {
delegate = deserializeIrVariable(proto.delegate)
getter = deserializeIrFunction(proto.getter)
if (proto.hasSetter())
setter = deserializeIrFunction(proto.setter)
}
}
private fun deserializeIrProperty(proto: ProtoProperty): IrProperty =
withDeserializedIrDeclarationBase(proto.base) { symbol, uniqId, startOffset, endOffset, origin, fcode ->
require(symbol is IrPropertySymbol)
val flags = PropertyFlags.decode(fcode)
symbolTable.declareProperty(uniqId, { symbol }) {
irFactory.createProperty(
startOffset, endOffset, origin,
it,
deserializeName(proto.name),
flags.visibility,
flags.modality,
flags.isVar,
flags.isConst,
flags.isLateinit,
flags.isDelegated,
flags.isExternal,
flags.isExpect,
flags.isFakeOverride
)
}.apply {
if (proto.hasGetter()) {
getter = deserializeIrFunction(proto.getter).also {
it.correspondingPropertySymbol = symbol
}
}
if (proto.hasSetter()) {
setter = deserializeIrFunction(proto.setter).also {
it.correspondingPropertySymbol = symbol
}
}
if (proto.hasBackingField()) {
backingField = deserializeIrField(proto.backingField).also {
it.correspondingPropertySymbol = symbol
}
}
}
}
companion object {
private val allKnownDeclarationOrigins =
IrDeclarationOrigin::class.nestedClasses.toList() + InnerClassesSupport.FIELD_FOR_OUTER_THIS::class
private val declarationOriginIndex =
allKnownDeclarationOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name }
}
private fun deserializeIrDeclarationOrigin(protoName: Int): IrDeclarationOriginImpl {
val originName = fileReader.deserializeString(protoName)
return declarationOriginIndex[originName] ?: object : IrDeclarationOriginImpl(originName) {}
}
fun deserializeDeclaration(proto: ProtoDeclaration): IrDeclaration {
val declaration: IrDeclaration = when (proto.declaratorCase!!) {
IR_ANONYMOUS_INIT -> deserializeIrAnonymousInit(proto.irAnonymousInit)
IR_CONSTRUCTOR -> deserializeIrConstructor(proto.irConstructor)
IR_FIELD -> deserializeIrField(proto.irField)
IR_CLASS -> deserializeIrClass(proto.irClass)
IR_FUNCTION -> deserializeIrFunction(proto.irFunction)
IR_PROPERTY -> deserializeIrProperty(proto.irProperty)
IR_TYPE_PARAMETER -> error("Unreachable execution Type Parameter") // deserializeIrTypeParameter(proto.irTypeParameter)
IR_VARIABLE -> deserializeIrVariable(proto.irVariable)
IR_VALUE_PARAMETER -> error("Unreachable execution Value Parameter") // deserializeIrValueParameter(proto.irValueParameter)
IR_ENUM_ENTRY -> deserializeIrEnumEntry(proto.irEnumEntry)
IR_LOCAL_DELEGATED_PROPERTY -> deserializeIrLocalDelegatedProperty(proto.irLocalDelegatedProperty)
IR_TYPE_ALIAS -> deserializeIrTypeAlias(proto.irTypeAlias)
IR_ERROR_DECLARATION -> deserializeErrorDeclaration(proto.irErrorDeclaration)
DECLARATOR_NOT_SET -> error("Declaration deserialization not implemented: ${proto.declaratorCase}")
}
return declaration
}
// Depending on deserialization strategy we either deserialize public api fake overrides
// or reconstruct them after IR linker completes.
private fun isSkippableFakeOverride(proto: ProtoDeclaration, parent: IrClass): Boolean {
if (!platformFakeOverrideClassFilter.needToConstructFakeOverrides(parent)) return false
val symbol = when (proto.declaratorCase!!) {
IR_FUNCTION -> symbolDeserializer.deserializeIrSymbol(proto.irFunction.base.base.symbol)
IR_PROPERTY -> symbolDeserializer.deserializeIrSymbol(proto.irProperty.base.symbol)
// Don't consider IR_FIELDS here.
else -> return false
}
if (symbol !is IrPublicSymbolBase<*>) return false
if (!symbol.signature.isPublic) return false
return when (proto.declaratorCase!!) {
IR_FUNCTION -> FunctionFlags.decode(proto.irFunction.base.base.flags).isFakeOverride
IR_PROPERTY -> PropertyFlags.decode(proto.irProperty.base.flags).isFakeOverride
// Don't consider IR_FIELDS here.
else -> false
}
}
}
@@ -55,8 +55,6 @@ abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor) {
open fun addModuleReachableTopLevel(idSig: IdSignature) { error("Unsupported Operation (sig: $idSig") }
open fun deserializeReachableDeclarations() { error("Unsupported Operation") }
abstract val moduleFragment: IrModuleFragment
abstract val moduleDependencies: Collection<IrModuleDeserializer>
@@ -103,10 +101,6 @@ class IrModuleDeserializerWithBuiltIns(
override fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
delegate.referencePropertyByLocalSignature(file, idSignature)
override fun deserializeReachableDeclarations() {
delegate.deserializeReachableDeclarations()
}
private fun computeFunctionDescriptor(className: String): FunctionClassDescriptor {
val isK = className[0] == 'K'
val isSuspend = (if (isK) className[1] else className[0]) == 'S'
@@ -0,0 +1,156 @@
/*
* 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.serialization.encodings.*
import org.jetbrains.kotlin.backend.common.serialization.proto.Actual
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature.IdsigCase.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrLocalDelegatedPropertySymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.backend.common.serialization.proto.AccessorIdSignature as ProtoAccessorIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.FileLocalIdSignature as ProtoFileLocalIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature
import org.jetbrains.kotlin.backend.common.serialization.proto.PublicIdSignature as ProtoPublicIdSignature
class IrSymbolDeserializer(
val symbolTable: ReferenceSymbolTable,
val fileReader: IrLibraryFile,
val actuals: List<Actual>,
val enqueueLocalTopLevelDeclaration: (IdSignature) -> Unit,
val handleExpectActualMapping: (IdSignature, IrSymbol) -> IrSymbol,
val deserializePublicSymbol: (IdSignature, BinarySymbolData.SymbolKind) -> IrSymbol,
) {
val deserializedSymbols = mutableMapOf<IdSignature, IrSymbol>()
fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
return deserializedSymbols.getOrPut(idSig) {
val symbol = referenceDeserializedSymbol(symbolKind, idSig)
handleExpectActualMapping(idSig, symbol)
}
}
private fun referenceDeserializedSymbol(symbolKind: BinarySymbolData.SymbolKind, idSig: IdSignature): IrSymbol = symbolTable.run {
when (symbolKind) {
BinarySymbolData.SymbolKind.ANONYMOUS_INIT_SYMBOL -> IrAnonymousInitializerSymbolImpl()
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(idSig)
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(idSig)
BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL -> referenceTypeParameterFromLinker(idSig)
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(idSig)
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
BinarySymbolData.SymbolKind.FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(idSig)
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(idSig)
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(idSig)
BinarySymbolData.SymbolKind.VARIABLE_SYMBOL -> IrVariableSymbolImpl()
BinarySymbolData.SymbolKind.VALUE_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
BinarySymbolData.SymbolKind.RECEIVER_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
BinarySymbolData.SymbolKind.LOCAL_DELEGATED_PROPERTY_SYMBOL ->
IrLocalDelegatedPropertySymbolImpl()
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
}
}
fun referenceLocalIrSymbol(symbol: IrSymbol, signature: IdSignature) {
assert(signature.isLocal)
deserializedSymbols.putIfAbsent(signature, symbol)
}
fun referenceSimpleFunctionByLocalSignature(idSignature: IdSignature) : IrSimpleFunctionSymbol =
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.FUNCTION_SYMBOL) as IrSimpleFunctionSymbol
fun referencePropertyByLocalSignature(idSignature: IdSignature): IrPropertySymbol =
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.PROPERTY_SYMBOL) as IrPropertySymbol
private fun deserializeIrSymbolData(idSignature: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
if (idSignature.isLocal) {
if (idSignature.hasTopLevel) {
enqueueLocalTopLevelDeclaration(idSignature.topLevelSignature())
}
return deserializedSymbols.getOrPut(idSignature) {
referenceDeserializedSymbol(symbolKind, idSignature)
}
}
return deserializePublicSymbol(idSignature, symbolKind)
}
fun deserializeIrSymbolToDeclare(code: Long): Pair<IrSymbol, IdSignature> {
val symbolData = parseSymbolData(code)
val signature = deserializeIdSignature(symbolData.signatureId)
return Pair(deserializeIrSymbolData(signature, symbolData.kind), signature)
}
fun parseSymbolData(code: Long): BinarySymbolData = BinarySymbolData.decode(code)
fun deserializeIrSymbol(code: Long): IrSymbol {
val symbolData = parseSymbolData(code)
val signature = deserializeIdSignature(symbolData.signatureId)
return deserializeIrSymbolData(signature, symbolData.kind)
}
private fun readSignature(index: Int): CodedInputStream =
fileReader.signature(index).codedInputStream
private fun loadSignatureProto(index: Int): ProtoIdSignature {
return ProtoIdSignature.parseFrom(readSignature(index), ExtensionRegistryLite.newInstance())
}
fun deserializeIdSignature(index: Int): IdSignature {
val sigData = loadSignatureProto(index)
return deserializeSignatureData(sigData)
}
/* -------------------------------------------------------------- */
// TODO: Think about isolating id signature related logic behind corresponding interface
private fun deserializePublicIdSignature(proto: ProtoPublicIdSignature): IdSignature.PublicSignature {
val pkg = fileReader.deserializeFqName(proto.packageFqNameList)
val cls = fileReader.deserializeFqName(proto.declarationFqNameList)
val memberId = if (proto.hasMemberUniqId()) proto.memberUniqId else null
return IdSignature.PublicSignature(pkg, cls, memberId, proto.flags)
}
private fun deserializeAccessorIdSignature(proto: ProtoAccessorIdSignature): IdSignature.AccessorSignature {
val propertySignature = deserializeIdSignature(proto.propertySignature)
require(propertySignature is IdSignature.PublicSignature) { "For public accessor corresponding property supposed to be public as well" }
val name = fileReader.deserializeString(proto.name)
val hash = proto.accessorHashId
val mask = proto.flags
val accessorSignature =
IdSignature.PublicSignature(propertySignature.packageFqName, "${propertySignature.declarationFqName}.$name", hash, mask)
return IdSignature.AccessorSignature(propertySignature, accessorSignature)
}
private fun deserializeFileLocalIdSignature(proto: ProtoFileLocalIdSignature): IdSignature.FileLocalSignature {
return IdSignature.FileLocalSignature(deserializeIdSignature(proto.container), proto.localId)
}
private fun deserializeScopeLocalIdSignature(proto: Int): IdSignature.ScopeLocalDeclaration {
return IdSignature.ScopeLocalDeclaration(proto)
}
fun deserializeSignatureData(proto: ProtoIdSignature): IdSignature {
return when (proto.idsigCase) {
PUBLIC_SIG -> deserializePublicIdSignature(proto.publicSig)
ACCESSOR_SIG -> deserializeAccessorIdSignature(proto.accessorSig)
PRIVATE_SIG -> deserializeFileLocalIdSignature(proto.privateSig)
SCOPED_LOCAL_SIG -> deserializeScopeLocalIdSignature(proto.scopedLocalSig)
else -> error("Unexpected IdSignature kind: ${proto.idsigCase}")
}
}
}
@@ -11,25 +11,15 @@ import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolD
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.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.IrAbstractFunctionFactory
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
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.descriptors.*
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
import org.jetbrains.kotlin.ir.linkage.KotlinIrLinkerInternalException
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.*
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.library.KotlinLibrary
@@ -38,32 +28,23 @@ import org.jetbrains.kotlin.name.Name
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 messageLogger: IrMessageLogger,
val builtIns: IrBuiltIns,
val symbolTable: SymbolTable,
private val exportedDependencies: List<ModuleDescriptor>
private val exportedDependencies: List<ModuleDescriptor>,
) : IrDeserializer, FileLocalAwareLinker {
// Kotlin-MPP related data. Consider some refactoring
private val expectUniqIdToActualUniqId = mutableMapOf<IdSignature, IdSignature>()
private val topLevelActualUniqItToDeserializer = mutableMapOf<IdSignature, IrModuleDeserializer>()
private val expectSymbols = mutableMapOf<IdSignature, IrSymbol>()
private val actualSymbols = mutableMapOf<IdSignature, IrSymbol>()
internal val expectUniqIdToActualUniqId = mutableMapOf<IdSignature, IdSignature>()
internal val topLevelActualUniqItToDeserializer = mutableMapOf<IdSignature, IrModuleDeserializer>()
internal val expectSymbols = mutableMapOf<IdSignature, IrSymbol>()
internal val actualSymbols = mutableMapOf<IdSignature, IrSymbol>()
private val modulesWithReachableTopLevels = mutableSetOf<IrModuleDeserializer>()
internal val modulesWithReachableTopLevels = mutableSetOf<ModuleDeserializationState>()
// TODO: replace with Map<Name, IrModuleDeserializer>
protected val deserializersForModules = mutableMapOf<ModuleDescriptor, IrModuleDeserializer>()
@@ -72,411 +53,12 @@ abstract class KotlinIrLinker(
abstract val translationPluginContext: TranslationPluginContext?
private val haveSeen = mutableSetOf<IrSymbol>()
internal val triedToDeserializeDeclarationForSymbol = mutableSetOf<IrSymbol>()
internal val deserializedSymbols = mutableSetOf<IrSymbol>()
private lateinit var linkerExtensions: Collection<IrDeserializer.IrLinkerExtension>
abstract inner class BasicIrModuleDeserializer(moduleDescriptor: ModuleDescriptor, override val klib: IrLibrary, override val strategy: DeserializationStrategy, private val containsErrorCode: Boolean = false) :
IrModuleDeserializer(moduleDescriptor) {
private val fileToDeserializerMap = mutableMapOf<IrFile, IrDeserializerForFile>()
private inner class ModuleDeserializationState {
private val filesWithPendingTopLevels = mutableSetOf<IrDeserializerForFile>()
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)
}
}
override fun toString(): String = klib.toString()
}
private val moduleDeserializationState = ModuleDeserializationState()
private val moduleReversedFileIndex = mutableMapOf<IdSignature, IrDeserializerForFile>()
override val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { resolveModuleDeserializer(it, null) }
}
override fun init(delegate: IrModuleDeserializer) {
val fileCount = klib.fileCount()
val files = ArrayList<IrFile>(fileCount)
for (i in 0 until fileCount) {
val fileStream = klib.file(i).codedInputStream
files.add(deserializeIrFile(ProtoFile.parseFrom(fileStream, newInstance()), i, delegate, containsErrorCode))
}
moduleFragment.files.addAll(files)
fileToDeserializerMap.values.forEach { it.deserializeExpectActualMapping() }
}
override fun referenceSimpleFunctionByLocalSignature(file: IrFile, idSignature: IdSignature): IrSimpleFunctionSymbol =
fileToDeserializerMap[file]?.referenceSimpleFunctionByLocalSignature(idSignature)
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
override fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
fileToDeserializerMap[file]?.referencePropertyByLocalSignature(idSignature)
?: error("No deserializer for file $file in module ${moduleDescriptor.name}")
// 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, allowErrorNodes: Boolean): 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,
moduleDeserializer, allowErrorNodes
).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<ProtoConstructorCall>?,
private val actuals: List<ProtoActual>,
private val fileIndex: Int,
onlyHeaders: Boolean,
inlineBodies: Boolean,
private val moduleDeserializer: IrModuleDeserializer,
allowErrorNodes: Boolean
) :
IrFileDeserializer(
messageLogger,
builtIns,
symbolTable,
!onlyHeaders,
fakeOverrideBuilder,
allowErrorNodes
)
{
private var fileLoops = mutableMapOf<Int, IrLoop>()
lateinit var file: IrFile
private val irTypeCache = mutableMapOf<Int, IrType>()
override val deserializeInlineFunctions: Boolean = inlineBodies
override val platformFakeOverrideClassFilter = fakeOverrideBuilder.platformSpecificClassFilter
var reversedSignatureIndex = emptyMap<IdSignature, Int>()
inner class FileDeserializationState {
private val reachableTopLevels = LinkedHashSet<IdSignature>()
val deserializedSymbols = mutableMapOf<IdSignature, IrSymbol>()
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,
moduleDeserializer.moduleDescriptor,
moduleDeserializer.moduleDependencies
)
}
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)
}
}
fun referenceSimpleFunctionByLocalSignature(idSignature: IdSignature) : IrSimpleFunctionSymbol =
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.FUNCTION_SYMBOL) as IrSimpleFunctionSymbol
fun referencePropertyByLocalSignature(idSignature: IdSignature): IrPropertySymbol =
deserializeIrSymbolData(idSignature, BinarySymbolData.SymbolKind.PROPERTY_SYMBOL) as IrPropertySymbol
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<IrSymbol, IdSignature> {
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, currentModule: ModuleDescriptor, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer {
public open fun handleNoModuleDeserializerFound(idSignature: IdSignature, currentModule: ModuleDescriptor, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer {
val message = buildString {
append("Module $currentModule has reference $idSignature, unfortunately neither itself nor its dependencies ")
dependencies.joinTo(this, "\n\t", "[\n\t", "\n]")
@@ -489,7 +71,7 @@ abstract class KotlinIrLinker(
throw KotlinIrLinkerInternalException
}
protected open fun resolveModuleDeserializer(module: ModuleDescriptor, signature: IdSignature?): IrModuleDeserializer {
public open fun resolveModuleDeserializer(module: ModuleDescriptor, signature: IdSignature?): IrModuleDeserializer {
return deserializersForModules[module] ?: run {
val message = buildString {
append("Could not load module ")
@@ -515,58 +97,22 @@ abstract class KotlinIrLinker(
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()
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(idSig)
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(idSig)
BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL -> referenceTypeParameterFromLinker(idSig)
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(idSig)
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
BinarySymbolData.SymbolKind.FIELD_SYMBOL -> referenceFieldFromLinker(idSig)
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(idSig)
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(idSig)
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(idSig)
BinarySymbolData.SymbolKind.VARIABLE_SYMBOL -> IrVariableSymbolImpl()
BinarySymbolData.SymbolKind.VALUE_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
BinarySymbolData.SymbolKind.RECEIVER_PARAMETER_SYMBOL -> IrValueParameterSymbolImpl()
BinarySymbolData.SymbolKind.LOCAL_DELEGATED_PROPERTY_SYMBOL ->
IrLocalDelegatedPropertySymbolImpl()
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig")
}
}
private fun deserializeAllReachableTopLevels() {
while (modulesWithReachableTopLevels.isNotEmpty()) {
val moduleDeserializer = modulesWithReachableTopLevels.first()
modulesWithReachableTopLevels.remove(moduleDeserializer)
val moduleDeserializationState = modulesWithReachableTopLevels.first()
modulesWithReachableTopLevels.remove(moduleDeserializationState)
moduleDeserializer.deserializeReachableDeclarations()
moduleDeserializationState.deserializeReachableDeclarations()
}
}
private fun findDeserializedDeclarationForSymbol(symbol: IrSymbol): DeclarationDescriptor? {
assert(symbol.isPublicApi || symbol.descriptor.module === currentModule || platformSpecificSymbol(symbol))
if (haveSeen.contains(symbol)) {
if (symbol in triedToDeserializeDeclarationForSymbol || symbol in deserializedSymbols) {
return null
}
haveSeen.add(symbol)
triedToDeserializeDeclarationForSymbol.add(symbol)
val descriptor = symbol.descriptor
@@ -586,6 +132,7 @@ abstract class KotlinIrLinker(
if (!symbol.hasDescriptor) return null
val descriptor = symbol.descriptor
if (descriptor is CallableMemberDescriptor) {
if (descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
// skip fake overrides
@@ -661,12 +208,43 @@ abstract class KotlinIrLinker(
override fun postProcess() {
finalizeExpectActualLinker()
fakeOverrideBuilder.provideFakeOverrides()
haveSeen.clear()
triedToDeserializeDeclarationForSymbol.clear()
deserializedSymbols.clear()
// TODO: fix IrPluginContext to make it not produce additional external reference
// symbolTable.noUnboundLeft("unbound after fake overrides:")
}
fun handleExpectActualMapping(idSig: IdSignature, rawSymbol: IrSymbol): IrSymbol {
// Actual signature
if (idSig in expectUniqIdToActualUniqId.values) {
actualSymbols[idSig] = rawSymbol
}
// Expect signature
expectUniqIdToActualUniqId[idSig]?.let { actualSig ->
assert(idSig.run { IdSignature.Flags.IS_EXPECT.test() })
val referencingSymbol = wrapInDelegatedSymbol(rawSymbol)
expectSymbols[idSig] = referencingSymbol
// Trigger actual symbol deserialization
topLevelActualUniqItToDeserializer[actualSig]?.let { moduleDeserializer -> // Not null if top-level
val actualSymbol = actualSymbols[actualSig]
// Check if
if (actualSymbol == null || !actualSymbol.isBound) {
moduleDeserializer.addModuleReachableTopLevel(actualSig)
}
}
return referencingSymbol
}
return rawSymbol
}
private fun topLevelKindToSymbolKind(kind: IrDeserializer.TopLevelSymbolKind): BinarySymbolData.SymbolKind {
return when (kind) {
IrDeserializer.TopLevelSymbolKind.CLASS_SYMBOL -> BinarySymbolData.SymbolKind.CLASS_SYMBOL
@@ -690,16 +268,7 @@ abstract class KotlinIrLinker(
// 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.
// All actuals have been deserialized, retarget delegating symbols from expects to actuals.
expectUniqIdToActualUniqId.forEach {
val expectSymbol = expectSymbols[it.key]
val actualSymbol = actualSymbols[it.value]
@@ -773,4 +342,4 @@ enum class DeserializationStrategy(
EXPLICITLY_EXPORTED(true, true, false, true),
ONLY_DECLARATION_HEADERS(false, false, false, false),
WITH_INLINE_BODIES(false, false, false, true)
}
}
@@ -41,7 +41,7 @@ class JsIrLinker(
JsModuleDeserializer(moduleDescriptor, klib ?: error("Expecting kotlin library"), strategy, klib.libContainsErrorCode)
private inner class JsModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary, strategy: DeserializationStrategy, allowErrorCode: Boolean) :
KotlinIrLinker.BasicIrModuleDeserializer(moduleDescriptor, klib, strategy, allowErrorCode)
BasicIrModuleDeserializer(this, moduleDescriptor, klib, strategy, allowErrorCode)
override fun createCurrentModuleDeserializer(moduleFragment: IrModuleFragment, dependencies: Collection<IrModuleDeserializer>): IrModuleDeserializer {
val currentModuleDeserializer = super.createCurrentModuleDeserializer(moduleFragment, dependencies)
@@ -61,7 +61,7 @@ class JvmIrLinker(
}
private inner class JvmModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary, strategy: DeserializationStrategy) :
KotlinIrLinker.BasicIrModuleDeserializer(moduleDescriptor, klib, strategy)
BasicIrModuleDeserializer(this, moduleDescriptor, klib, strategy)
private fun DeclarationDescriptor.isJavaDescriptor(): Boolean {
if (this is PackageFragmentDescriptor) {