From 7c4033f0bfd90d7767c101b3f7b9fd3bf2ed2515 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Wed, 30 Oct 2019 14:03:05 +0300 Subject: [PATCH] Deserializer: Fix initialization order Top-level initializers must be deserialized in the same order they where in the original source file. Before this patch this rule might be violated. Consider the following case: // lib1.kt val a = 5 val b = a * 5 // lib2.kt fun foo() = println(b) Compile both files into libraries and then link an application against them. During deserialization of lib2 'b' will be added to the deserialization queue of lib1. After that we will add 'a' to this queue too. Thus 'b' and 'a' will be in a wrong order in this queue resulting in a wrong order of corresponding top-level initializers in a final executable. This patch fixes this issue by adding all top-level initializers to a deserialization queue before all other declarations. --- .../common/serialization/KotlinIrLinker.kt | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) 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 909650f882e..6987de40010 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 @@ -91,7 +91,7 @@ abstract class KotlinIrLinker( } class SimpleDeserializationState: DeserializationState() { - private val reachableTopLevels = mutableSetOf() + private val reachableTopLevels = LinkedHashSet() override fun addUniqID(key: UniqId) { reachableTopLevels.add(key) @@ -140,8 +140,11 @@ abstract class KotlinIrLinker( // This is a heavy initializer val module = deserializeIrModuleHeader() - inner class IrDeserializerForFile(private var annotations: List?, private var forcedDeclarations: List?, private val fileIndex: Int, onlyHeaders: Boolean) : - IrFileDeserializer(logger, builtIns, symbolTable) { + inner class IrDeserializerForFile( + private var annotations: List?, + private val fileIndex: Int, + onlyHeaders: Boolean + ) : IrFileDeserializer(logger, builtIns, symbolTable) { private var fileLoops = mutableMapOf() @@ -385,10 +388,6 @@ abstract class KotlinIrLinker( file.annotations.addAll(deserializeAnnotations(it)) annotations = null } - forcedDeclarations?.let { - it.forEach { fileLocalDeserializationState.addUniqID(it) } - forcedDeclarations = null - } } fun deserializeAllFileReachableTopLevel() { @@ -405,10 +404,14 @@ abstract class KotlinIrLinker( val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray()) - val explicitlyExported = mutableListOf() - val fileDeserializer = - IrDeserializerForFile(fileProto.annotationList, explicitlyExported, fileIndex, !deserializationStrategy.needBodies) + IrDeserializerForFile(fileProto.annotationList, fileIndex, !deserializationStrategy.needBodies).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 { + fileLocalDeserializationState.addUniqID(UniqId(loadSymbolData(it).topLevelUniqIdIndex)) + } + } val fqName = fileDeserializer.deserializeFqName(fileProto.fqNameList) @@ -426,10 +429,6 @@ abstract class KotlinIrLinker( moduleReversedFileIndex.getOrPut(it) { fileDeserializer } } - fileProto.explicitlyExportedToCompilerList.mapTo(explicitlyExported) { - UniqId(fileDeserializer.loadSymbolData(it).topLevelUniqIdIndex) - } - if (deserializationStrategy.theWholeWorld) { for (id in fileUniqIdIndex) { assert(id.isPublic)