diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt new file mode 100644 index 00000000000..8f76a552f45 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt @@ -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() + + private val moduleDeserializationState = ModuleDeserializationState(linker, this) + + internal val moduleReversedFileIndex = mutableMapOf() + + 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(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() + + 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 + } \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt index b10c31c6c11..1c03e15ec86 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IncrementalCompilationSupport.kt @@ -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 diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt new file mode 100644 index 00000000000..7e7f54c1667 --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrBodyDeserializer.kt @@ -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() + + 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() + + 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() + 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() + 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() + + 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() + 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() + 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() + 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 } + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt new file mode 100644 index 00000000000..8e166151faa --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt @@ -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() + + 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): List { + 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.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() + + 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 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, isGlobal: Boolean): List { + // NOTE: fun , T : Any> Array.filterNotNullTo(destination: C): C + val result = ArrayList(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): List { + val result = ArrayList(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.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 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 + } + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt index b949cff18ac..dd2d4861c5b 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt @@ -5,1450 +5,157 @@ 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.peek -import org.jetbrains.kotlin.backend.common.pop -import org.jetbrains.kotlin.backend.common.push -import org.jetbrains.kotlin.backend.common.serialization.encodings.* -import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature.IdsigCase.* -import org.jetbrains.kotlin.backend.common.serialization.proto.IrConst.ValueCase.* -import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration.DeclaratorCase.* -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.IrType.KindCase.* -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.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor 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.* -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.declarations.impl.IrFileImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.types.Variance -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.IrAnonymousInit as ProtoAnonymousInit -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.IrClass as ProtoClass -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.IrConstructor as ProtoConstructor +import org.jetbrains.kotlin.library.IrLibrary +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.protobuf.CodedInputStream +import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite 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.IrDeclaration as ProtoDeclaration -import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclarationBase as ProtoDeclarationBase -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.IrDynamicType as ProtoDynamicType -import org.jetbrains.kotlin.backend.common.serialization.proto.IrEnumConstructorCall as ProtoEnumConstructorCall -import org.jetbrains.kotlin.backend.common.serialization.proto.IrEnumEntry as ProtoEnumEntry -import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorCallExpression as ProtoErrorCallExpression -import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorDeclaration as ProtoErrorDeclaration -import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorExpression as ProtoErrorExpression -import org.jetbrains.kotlin.backend.common.serialization.proto.IrErrorType as ProtoErrorType -import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression -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.IrFunctionExpression as ProtoFunctionExpression -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.IrLocalDelegatedProperty as ProtoLocalDelegatedProperty -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.IrProperty as ProtoProperty -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.IrSimpleType as ProtoSimpleType -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.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.IrTypeOp as ProtoTypeOp -import org.jetbrains.kotlin.backend.common.serialization.proto.IrTypeOperator as ProtoTypeOperator -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.IrVararg as ProtoVararg -import org.jetbrains.kotlin.backend.common.serialization.proto.IrVarargElement as ProtoVarargElement -import org.jetbrains.kotlin.backend.common.serialization.proto.IrVariable as ProtoVariable -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 -import org.jetbrains.kotlin.backend.common.serialization.proto.PublicIdSignature as ProtoPublicIdSignature +import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile -abstract class IrFileDeserializer( - val messageLogger: IrMessageLogger, - val builtIns: IrBuiltIns, - val symbolTable: SymbolTable, - protected var deserializeBodies: Boolean, - private val fakeOverrideBuilder: FakeOverrideBuilder, - private val allowErrorNodes: Boolean +class IrFileDeserializer( + val file: IrFile, + private val fileReader: IrLibraryFile, + fileProto: ProtoFile, + val symbolDeserializer: IrSymbolDeserializer, + val declarationDeserializer: IrDeclarationDeserializer, ) { - protected val irFactory: IrFactory get() = symbolTable.irFactory + val reversedSignatureIndex = fileProto.declarationIdList.associateBy { symbolDeserializer.deserializeIdSignature(it) } - abstract fun deserializeIrSymbolToDeclare(code: Long): Pair - abstract fun deserializeIrSymbol(code: Long): IrSymbol - abstract fun deserializeIrType(index: Int): IrType - abstract fun deserializeIdSignature(index: Int): IdSignature - abstract fun deserializeString(index: Int): String - abstract fun deserializeExpressionBody(index: Int): IrExpression - abstract fun deserializeStatementBody(index: Int): IrElement - abstract fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoop): IrLoop + private var annotations: List? = fileProto.annotationList - abstract fun referenceIrSymbol(symbol: IrSymbol, signature: IdSignature) - - private val parentsStack = mutableListOf() - private val delegatedSymbolMap = mutableMapOf() - - abstract val deserializeInlineFunctions: Boolean - abstract val platformFakeOverrideClassFilter: FakeOverrideClassFilter - - fun deserializeFqName(fqn: List): String = - fqn.joinToString(".", transform = ::deserializeString) - - private fun deserializeIrSymbolAndRemap(code: Long): IrSymbol { - // TODO: could be simplified - return deserializeIrSymbol(code).let { - delegatedSymbolMap[it] ?: it + internal fun deserializeDeclaration(idSig: IdSignature): IrDeclaration { + return declarationDeserializer.deserializeDeclaration(loadTopLevelDeclarationProto(idSig)).also { + file.declarations += it } } - private fun deserializeName(index: Int): Name { - val name = deserializeString(index) - return Name.guessByFirstCharacter(name) + private fun readDeclaration(index: Int): CodedInputStream = + fileReader.irDeclaration(index).codedInputStream + + private fun loadTopLevelDeclarationProto(idSig: IdSignature): ProtoDeclaration { + val idSigIndex = reversedSignatureIndex[idSig] ?: error("Not found Idx for $idSig") + return ProtoDeclaration.parseFrom(readDeclaration(idSigIndex), ExtensionRegistryLite.newInstance()) } - private fun deserializeIrTypeArgument(proto: Long): IrTypeArgument { - val encoding = BinaryTypeProjection.decode(proto) - - if (encoding.isStarProjection) return IrStarProjectionImpl - - return makeTypeProjection(deserializeIrType(encoding.typeIndex), encoding.variance) - } - - fun deserializeAnnotations(annotations: List): List { - return annotations.map { - deserializeConstructorCall(it, 0, 0, builtIns.unitType) // TODO: need a proper deserialization here + fun deserializeFileImplicitDataIfFirstUse() { + annotations?.let { + file.annotations += declarationDeserializer.deserializeAnnotations(it) + annotations = null } } - - 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) - } - - 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}") - } - } - - /* -------------------------------------------------------------- */ - - // TODO: Think about isolating id signature related logic behind corresponding interface - - private fun deserializePublicIdSignature(proto: ProtoPublicIdSignature): IdSignature.PublicSignature { - val pkg = deserializeFqName(proto.packageFqNameList) - val cls = 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 = 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}") - } - } - - /* -------------------------------------------------------------- */ - - private fun deserializeBlockBody( - proto: ProtoBlockBody, - start: Int, end: Int - ): IrBlockBody { - - val statements = mutableListOf() - - 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 = 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) - } - - 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() - -> 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() - 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, 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 = deserializeIrSymbolAndRemap(proto.classSymbol) as IrClassifierSymbol - val classType = deserializeIrType(proto.classType) - /** TODO: [createClassifierSymbolForClassReference] is internal function */ - return IrClassReferenceImpl(start, end, type, symbol, classType) - } - - private fun deserializeConstructorCall(proto: ProtoConstructorCall, start: Int, end: Int, type: IrType): IrConstructorCall { - val symbol = 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 = deserializeIrSymbolAndRemap(proto.symbol) as IrSimpleFunctionSymbol - - val superSymbol = if (proto.hasSuper()) { - 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() - 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 = 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 = 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, - deserializeIrFunction(functionExpression.function), - deserializeIrStatementOrigin(functionExpression.originName) - ) - - private fun deserializeErrorExpression( - proto: ProtoErrorExpression, - start: Int, end: Int, type: IrType - ): IrErrorExpression { - require(allowErrorNodes) { - "IrErrorExpression($start, $end, \"${deserializeString(proto.description)}\") found but error code is not allowed" - } - return IrErrorExpressionImpl(start, end, type, deserializeString(proto.description)) - } - - private fun deserializeErrorCallExpression( - proto: ProtoErrorCallExpression, - start: Int, end: Int, type: IrType - ): IrErrorCallExpression { - require(allowErrorNodes) { - "IrErrorCallExpressionImpl($start, $end, \"${deserializeString(proto.description)}\") found but error code is not allowed" - } - return IrErrorCallExpressionImpl(start, end, type, 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 = deserializeIrSymbolAndRemap(proto.symbol) as IrFunctionSymbol - val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null - val reflectionTarget = - if (proto.hasReflectionTargetSymbol()) 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 = deserializeIrSymbolAndRemap(access.symbol) as IrFieldSymbol - val origin = if (proto.hasOriginName()) deserializeIrStatementOrigin(proto.originName) else null - - val superQualifier = if (access.hasSuper()) { - 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 = 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 = 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 = deserializeIrSymbolAndRemap(proto.symbol) as IrClassSymbol - return IrGetObjectValueImpl(start, end, type, symbol) - } - - private fun deserializeInstanceInitializerCall( - proto: ProtoInstanceInitializerCall, - start: Int, - end: Int - ): IrInstanceInitializerCall { - val symbol = 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 = deserializeIrSymbolAndRemap(proto.delegate) as IrVariableSymbol - val getter = deserializeIrSymbolAndRemap(proto.getter) as IrSimpleFunctionSymbol - val setter = if (proto.hasSetter()) deserializeIrSymbolAndRemap(proto.setter) as IrSimpleFunctionSymbol else null - val symbol = 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 = deserializeIrSymbolAndRemap(proto.symbol) as IrPropertySymbol - - val field = if (proto.hasField()) deserializeIrSymbolAndRemap(proto.field) as IrFieldSymbol else null - val getter = if (proto.hasGetter()) deserializeIrSymbolAndRemap(proto.getter) as IrSimpleFunctionSymbol else null - val setter = if (proto.hasSetter()) 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 = 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 = deserializeIrSymbolAndRemap(access.symbol) as IrFieldSymbol - val superQualifier = if (access.hasSuper()) { - 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 = 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() - - 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() - 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 = 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 = deserializeIrType(proto.elementType) - - val elements = mutableListOf() - 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() - 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()) 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, - 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()) 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()) 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, 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 = deserializeIrType(proto.type) - val operation = proto.operation - val expression = deserializeOperation(operation, start, end, type) - - return expression - } - - private inline fun usingParent(parent: T, block: (T) -> R): R { - parentsStack.push(parent) - try { - return block(parent) - } finally { - parentsStack.pop() - } - } - - 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.usingParent(block: T.() -> Unit): T = - this.apply { usingParent(this) { block(it) } } - - private inline fun withDeserializedIrDeclarationBase( - proto: ProtoDeclarationBase, - block: (IrSymbol, IdSignature, Int, Int, IrDeclarationOrigin, Long) -> T - ): T where T : IrDeclaration, T : IrSymbolOwner { - val (s, uid) = 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 = parentsStack.peek()!! - 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 = 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 = deserializeIdSignature(symbolData.signatureId) - declareScopedTypeParameter(sig, { IrTypeParameterSymbolImpl() }, factory) - } - } - - // make sure this symbol is known to linker - referenceIrSymbol(result.symbol, sig) - result.annotations += deserializeAnnotations(proto.base.annotationList) - result.parent = parentsStack.peek()!! - 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 = irFactory.createExpressionBody(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 = parentsStack.peek()!! - } - } - - private fun deserializeTypeParameters(protos: List, isGlobal: Boolean): List { - // NOTE: fun , T : Any> Array.filterNotNullTo(destination: C): C - val result = ArrayList(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): List { - val result = ArrayList(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.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 inline fun 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 - } - } - } - } - } - - private 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 } - } - } - } - - private 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 = 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 = irFactory.createExpressionBody(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 = deserializeBlockBody(proto.body.blockBody, startOffset, endOffset) - 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 = irFactory.createExpressionBody(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 val allKnownStatementOrigins = - IrStatementOrigin::class.nestedClasses.toList() - private val statementOriginIndex = - allKnownStatementOrigins.mapNotNull { it.objectInstance as? IrStatementOriginImpl }.associateBy { it.debugName } - } - - private fun deserializeIrDeclarationOrigin(protoName: Int): IrDeclarationOriginImpl { - val originName = deserializeString(protoName) - return declarationOriginIndex[originName] ?: object : IrDeclarationOriginImpl(originName) {} - } - - fun deserializeIrStatementOrigin(protoName: Int): IrStatementOrigin { - return 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") - } - } - } - - private 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 -> deserializeIrSymbol(proto.irFunction.base.base.symbol) - IR_PROPERTY -> 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 - } - } - - fun deserializeDeclaration(proto: ProtoDeclaration, parent: IrDeclarationParent): IrDeclaration = - usingParent(parent) { - deserializeDeclaration(proto) - } } + +class FileDeserializationState( + val linker: KotlinIrLinker, + file: IrFile, + fileReader: IrLibraryFile, + fileProto: ProtoFile, + deserializeBodies: Boolean, + allowErrorNodes: Boolean, + deserializeInlineFunctions: Boolean, + moduleDeserializer: IrModuleDeserializer, + handleNoModuleDeserializerFound: (IdSignature, ModuleDescriptor, Collection) -> IrModuleDeserializer, +) { + + val symbolDeserializer = + IrSymbolDeserializer(linker.symbolTable, fileReader, fileProto.actualsList, ::addIdSignature, linker::handleExpectActualMapping) { idSig, symbolKind -> + assert(idSig.isPublic) + + val topLevelSig = idSig.topLevelSignature() + val actualModuleDeserializer = + moduleDeserializer.findModuleDeserializerForTopLevelId(topLevelSig) ?: handleNoModuleDeserializerFound( + idSig, + moduleDeserializer.moduleDescriptor, + moduleDeserializer.moduleDependencies + ) + + actualModuleDeserializer.deserializeIrSymbol(idSig, symbolKind) + } + + private val declarationDeserializer = IrDeclarationDeserializer( + linker.builtIns, + linker.symbolTable, + linker.symbolTable.irFactory, + fileReader, + file, + allowErrorNodes, + deserializeInlineFunctions, + deserializeBodies, + symbolDeserializer, + linker.fakeOverrideBuilder.platformSpecificClassFilter, + linker.fakeOverrideBuilder, + ) + + val fileDeserializer = IrFileDeserializer(file, fileReader, fileProto, symbolDeserializer, declarationDeserializer) + + private val reachableTopLevels = LinkedHashSet() + + init { + // 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 = symbolDeserializer.parseSymbolData(it) + val sig = symbolDeserializer.deserializeIdSignature(symbolData.signatureId) + assert(!sig.isPackageSignature()) + addIdSignature(sig.topLevelSignature()) + } + } + + fun addIdSignature(key: IdSignature) { + reachableTopLevels.add(key) + } + + fun enqueueAllDeclarations() { + reachableTopLevels.addAll(fileDeserializer.reversedSignatureIndex.keys) + } + + fun deserializeAllFileReachableTopLevel() { + while (reachableTopLevels.isNotEmpty()) { + val reachableKey = reachableTopLevels.first() + + val existedSymbol = symbolDeserializer.deserializedSymbols[reachableKey] + if (existedSymbol == null || !existedSymbol.isBound) { + fileDeserializer.deserializeDeclaration(reachableKey) + } + + reachableTopLevels.remove(reachableKey) + } + } +} + +abstract class IrLibraryFile { + abstract fun irDeclaration(index: Int): ByteArray + abstract fun type(index: Int): ByteArray + abstract fun signature(index: Int): ByteArray + abstract fun string(index: Int): ByteArray + abstract fun body(index: Int): ByteArray +} + +class IrLibraryFileFromKlib(private val klib: IrLibrary, private val fileIndex: Int): IrLibraryFile() { + override fun irDeclaration(index: Int): ByteArray = klib.irDeclaration(index, fileIndex) + override fun type(index: Int): ByteArray = klib.type(index, fileIndex) + override fun signature(index: Int): ByteArray = klib.signature(index, fileIndex) + override fun string(index: Int): ByteArray = klib.string(index, fileIndex) + override fun body(index: Int): ByteArray = klib.body(index, fileIndex) +} + +internal fun IrLibraryFile.deserializeString(index: Int): String = String(string(index)) + +internal fun IrLibraryFile.deserializeFqName(fqn: List): String = + fqn.joinToString(".", transform = ::deserializeString) + +internal fun IrLibraryFile.createFile(moduleDescriptor: ModuleDescriptor, fileProto: ProtoFile): IrFile { + val fileName = fileProto.fileEntry.name + val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray()) + val fqName = FqName(deserializeFqName(fileProto.fqNameList)) + val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName) + val symbol = IrFileSymbolImpl(packageFragmentDescriptor) + return IrFileImpl(fileEntry, symbol, fqName) +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt index 434cae774d3..779667dbd2c 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt @@ -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 @@ -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' diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrSymbolDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrSymbolDeserializer.kt new file mode 100644 index 00000000000..02589b2b87d --- /dev/null +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrSymbolDeserializer.kt @@ -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, + val enqueueLocalTopLevelDeclaration: (IdSignature) -> Unit, + val handleExpectActualMapping: (IdSignature, IrSymbol) -> IrSymbol, + val deserializePublicSymbol: (IdSignature, BinarySymbolData.SymbolKind) -> IrSymbol, +) { + + val deserializedSymbols = mutableMapOf() + + 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 { + 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}") + } + } +} \ No newline at end of file diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt index 6796aefbe2d..143594d75cf 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinIrLinker.kt @@ -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 + private val exportedDependencies: List, ) : IrDeserializer, FileLocalAwareLinker { // Kotlin-MPP related data. Consider some refactoring - private val expectUniqIdToActualUniqId = mutableMapOf() - private val topLevelActualUniqItToDeserializer = mutableMapOf() - private val expectSymbols = mutableMapOf() - private val actualSymbols = mutableMapOf() + internal val expectUniqIdToActualUniqId = mutableMapOf() + internal val topLevelActualUniqItToDeserializer = mutableMapOf() + internal val expectSymbols = mutableMapOf() + internal val actualSymbols = mutableMapOf() - private val modulesWithReachableTopLevels = mutableSetOf() + internal val modulesWithReachableTopLevels = mutableSetOf() // TODO: replace with Map protected val deserializersForModules = mutableMapOf() @@ -72,411 +53,12 @@ abstract class KotlinIrLinker( abstract val translationPluginContext: TranslationPluginContext? - private val haveSeen = mutableSetOf() + internal val triedToDeserializeDeclarationForSymbol = mutableSetOf() + internal val deserializedSymbols = mutableSetOf() private lateinit var linkerExtensions: Collection - 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() - - private inner class ModuleDeserializationState { - private val filesWithPendingTopLevels = mutableSetOf() - - fun enqueueFile(fileDeserializer: IrDeserializerForFile) { - filesWithPendingTopLevels.add(fileDeserializer) - enqueueModule() - } - - fun addIdSignature(key: IdSignature) { - val fileDeserializer = moduleReversedFileIndex[key] ?: error("No file found for key $key") - fileDeserializer.fileLocalDeserializationState.addIdSignature(key) - - enqueueFile(fileDeserializer) - } - - fun processPendingDeclarations() { - while (filesWithPendingTopLevels.isNotEmpty()) { - val pendingDeserializer = filesWithPendingTopLevels.first() - - pendingDeserializer.deserializeFileImplicitDataIfFirstUse() - pendingDeserializer.deserializeAllFileReachableTopLevel() - - filesWithPendingTopLevels.remove(pendingDeserializer) - } - } - - override fun toString(): String = klib.toString() - } - - private val moduleDeserializationState = ModuleDeserializationState() - private val moduleReversedFileIndex = mutableMapOf() - 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(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?, - private val actuals: List, - 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() - - lateinit var file: IrFile - - private val irTypeCache = mutableMapOf() - - override val deserializeInlineFunctions: Boolean = inlineBodies - - override val platformFakeOverrideClassFilter = fakeOverrideBuilder.platformSpecificClassFilter - - var reversedSignatureIndex = emptyMap() - - inner class FileDeserializationState { - private val reachableTopLevels = LinkedHashSet() - val deserializedSymbols = mutableMapOf() - - fun addIdSignature(key: IdSignature) { - reachableTopLevels.add(key) - } - - fun processPendingDeclarations() { - while (reachableTopLevels.isNotEmpty()) { - val reachableKey = reachableTopLevels.first() - - val existedSymbol = deserializedSymbols[reachableKey] - if (existedSymbol == null || !existedSymbol.isBound) { - val declaration = deserializeDeclaration(reachableKey) - file.declarations.add(declaration) - } - - reachableTopLevels.remove(reachableKey) - } - } - } - - val fileLocalDeserializationState = FileDeserializationState() - - fun deserializeDeclaration(idSig: IdSignature): IrDeclaration { - return deserializeDeclaration(loadTopLevelDeclarationProto(idSig), file) - } - - fun deserializeExpectActualMapping() { - actuals.forEach { - val expectSymbol = parseSymbolData(it.expectSymbol) - val actualSymbol = parseSymbolData(it.actualSymbol) - - val expect = deserializeIdSignature(expectSymbol.signatureId) - val actual = deserializeIdSignature(actualSymbol.signatureId) - - assert(expectUniqIdToActualUniqId[expect] == null) { - "Expect signature $expect is already actualized by ${expectUniqIdToActualUniqId[expect]}, while we try to record $actual" - } - expectUniqIdToActualUniqId[expect] = actual - // Non-null only for topLevel declarations. - getModuleForTopLevelId(actual)?.let { md -> topLevelActualUniqItToDeserializer[actual] = md } - } - } - - private fun resolveSignatureIndex(idSig: IdSignature): Int { - return reversedSignatureIndex[idSig] ?: error("Not found Idx for $idSig") - } - - private fun readDeclaration(index: Int): CodedInputStream = - moduleDeserializer.klib.irDeclaration(index, fileIndex).codedInputStream - - private fun loadTopLevelDeclarationProto(idSig: IdSignature): ProtoDeclaration { - val idSigIndex = resolveSignatureIndex(idSig) - return ProtoDeclaration.parseFrom(readDeclaration(idSigIndex), newInstance()) - } - - private fun readType(index: Int): CodedInputStream = - moduleDeserializer.klib.type(index, fileIndex).codedInputStream - - private fun loadTypeProto(index: Int): ProtoType { - return ProtoType.parseFrom(readType(index), newInstance()) - } - - private fun readSignature(index: Int): CodedInputStream = - moduleDeserializer.klib.signature(index, fileIndex).codedInputStream - - private fun loadSignatureProto(index: Int): ProtoIdSignature { - return ProtoIdSignature.parseFrom(readSignature(index), newInstance()) - } - - private fun readBody(index: Int): CodedInputStream = - moduleDeserializer.klib.body(index, fileIndex).codedInputStream - - private fun loadStatementBodyProto(index: Int): ProtoStatement { - return ProtoStatement.parseFrom(readBody(index), newInstance()) - } - - private fun loadExpressionBodyProto(index: Int): ProtoExpression { - return ProtoExpression.parseFrom(readBody(index), newInstance()) - } - - private fun loadStringProto(index: Int): String { - return String(moduleDeserializer.klib.string(index, fileIndex)) - } - - private fun getModuleForTopLevelId(idSignature: IdSignature): IrModuleDeserializer? { - if (idSignature in moduleDeserializer) return moduleDeserializer - return moduleDeserializer.moduleDependencies.firstOrNull { idSignature in it } - } - - private fun findModuleDeserializer(idSig: IdSignature): IrModuleDeserializer { - assert(idSig.isPublic) - - val topLevelSig = idSig.topLevelSignature() - if (topLevelSig in moduleDeserializer) return moduleDeserializer - return moduleDeserializer.moduleDependencies.firstOrNull { topLevelSig in it } ?: handleNoModuleDeserializerFound( - idSig, - 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 { - 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 { + public open fun handleNoModuleDeserializerFound(idSignature: IdSignature, currentModule: ModuleDescriptor, dependencies: Collection): 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) -} +} \ No newline at end of file diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt index 33423e36a90..ef43bab8011 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt @@ -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 { val currentModuleDeserializer = super.createCurrentModuleDeserializer(moduleFragment, dependencies) diff --git a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt index 77746c688d6..a91b54145e3 100644 --- a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt +++ b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/ir/backend/jvm/serialization/JvmIrLinker.kt @@ -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) {