[KLIB] Fix explicitlyExported mode

- Refactor deserialization pipeline
 - Fix K/N test
This commit is contained in:
Roman Artemev
2019-10-11 21:47:52 +03:00
committed by romanart
parent 43e855150c
commit 2cde7f2402
7 changed files with 110 additions and 51 deletions
@@ -55,50 +55,59 @@ abstract class KotlinIrLinker(
) : DescriptorUniqIdAware, IrDeserializer { ) : DescriptorUniqIdAware, IrDeserializer {
sealed class DeserializationState { sealed class DeserializationState<T> {
val deserializedSymbols = mutableMapOf<UniqId, IrSymbol>() val deserializedSymbols = mutableMapOf<UniqId, IrSymbol>()
val reachableTopLevels = mutableSetOf<UniqId>()
val deserializedTopLevels = mutableSetOf<UniqId>()
operator fun contains(key: UniqId) = key in deserializedSymbols operator fun contains(key: UniqId) = key in deserializedSymbols
operator fun get(key: UniqId): IrSymbol = deserializedSymbols[key] ?: error("No deserialized symbol found for $key") operator fun get(key: UniqId): IrSymbol = deserializedSymbols[key] ?: error("No deserialized symbol found for $key")
abstract fun addUniqID(key: UniqId) abstract fun addUniqID(key: UniqId)
protected open fun peekReachableKey(): UniqId? = reachableTopLevels.firstOrNull() abstract fun processPendingDeclarations(processor: (T) -> Unit)
class ModuleDeserializationState(val module: IrModuleDeserializer): DeserializationState<IrModuleDeserializer.IrDeserializerForFile>() {
private val filesWithPendingTopLevels = mutableSetOf<IrModuleDeserializer.IrDeserializerForFile>()
fun enqueueFile(fileDeserializer: IrModuleDeserializer.IrDeserializerForFile) {
filesWithPendingTopLevels.add(fileDeserializer)
module.enqueueModule()
}
class ModuleDeserializationState(val module: IrModuleDeserializer): DeserializationState() {
override fun addUniqID(key: UniqId) { override fun addUniqID(key: UniqId) {
module.addModuleReachableTopLevel(key) val fileDeserializer = module.moduleReversedFileIndex[key] ?: error("No file found for key $key")
fileDeserializer.fileLocalDeserializationState.addUniqID(key)
enqueueFile(fileDeserializer)
}
override fun processPendingDeclarations(processor: (IrModuleDeserializer.IrDeserializerForFile) -> Unit) {
while (filesWithPendingTopLevels.isNotEmpty()) {
val pendingDeserializer = filesWithPendingTopLevels.first()
processor(pendingDeserializer)
filesWithPendingTopLevels.remove(pendingDeserializer)
}
} }
} }
class SimpleDeserializationState: DeserializationState() { class SimpleDeserializationState: DeserializationState<UniqId>() {
private val reachableTopLevels = mutableSetOf<UniqId>()
override fun addUniqID(key: UniqId) { override fun addUniqID(key: UniqId) {
reachableTopLevels.add(key) reachableTopLevels.add(key)
} }
override fun peekReachableKey(): UniqId { override fun processPendingDeclarations(processor: (UniqId) -> Unit) {
return reachableTopLevels.firstOrNull() ?: error("Expecting non-empty set") while (reachableTopLevels.isNotEmpty()) {
} val reachableKey = reachableTopLevels.first()
}
fun processPendingDeclaration(processor: (UniqId) -> Unit) { if (deserializedSymbols[reachableKey]?.isBound != true) {
do { processor(reachableKey)
}
val reachableKey = peekReachableKey() ?: return
if (deserializedSymbols[reachableKey]?.isBound == true) {
reachableTopLevels.remove(reachableKey) reachableTopLevels.remove(reachableKey)
deserializedTopLevels.add(reachableKey)
continue
} }
}
processor(reachableKey)
reachableTopLevels.remove(reachableKey)
deserializedTopLevels.add(reachableKey)
} while (reachableTopLevels.isNotEmpty())
} }
} }
@@ -123,7 +132,7 @@ abstract class KotlinIrLinker(
protected val moduleResolvedForwardDeclarations = mutableMapOf<UniqId, UniqId>() protected val moduleResolvedForwardDeclarations = mutableMapOf<UniqId, UniqId>()
private val moduleDeserializationState = DeserializationState.ModuleDeserializationState(this) private val moduleDeserializationState = DeserializationState.ModuleDeserializationState(this)
private val moduleReversedFileIndex = mutableMapOf<UniqId, IrDeserializerForFile>() val moduleReversedFileIndex = mutableMapOf<UniqId, IrDeserializerForFile>()
private val moduleDependencies by lazy { private val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { deserializersForModules[it]!! } moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { deserializersForModules[it]!! }
} }
@@ -131,7 +140,7 @@ abstract class KotlinIrLinker(
// This is a heavy initializer // This is a heavy initializer
val module = deserializeIrModuleHeader() val module = deserializeIrModuleHeader()
inner class IrDeserializerForFile(private var annotations: List<ProtoConstructorCall>?, private val fileIndex: Int, onlyHeaders: Boolean) : inner class IrDeserializerForFile(private var annotations: List<ProtoConstructorCall>?, private var forcedDeclarations: List<UniqId>?, private val fileIndex: Int, onlyHeaders: Boolean) :
IrFileDeserializer(logger, builtIns, symbolTable) { IrFileDeserializer(logger, builtIns, symbolTable) {
private var fileLoops = mutableMapOf<Int, IrLoopBase>() private var fileLoops = mutableMapOf<Int, IrLoopBase>()
@@ -281,7 +290,7 @@ abstract class KotlinIrLinker(
return moduleDependencies.firstOrNull { key in it.moduleReversedFileIndex } return moduleDependencies.firstOrNull { key in it.moduleReversedFileIndex }
} }
private fun getStateForID(key: UniqId): DeserializationState { private fun getStateForID(key: UniqId): DeserializationState<*> {
if (key.isLocal) return fileLocalDeserializationState if (key.isLocal) return fileLocalDeserializationState
if (isGlobalUniqID(key)) return globalDeserializationState if (isGlobalUniqID(key)) return globalDeserializationState
return getModuleForTopLevelId(key)?.moduleDeserializationState ?: handleNoModuleDeserializerFound(key) return getModuleForTopLevelId(key)?.moduleDeserializationState ?: handleNoModuleDeserializerFound(key)
@@ -371,18 +380,19 @@ abstract class KotlinIrLinker(
} }
} }
fun deserializeFileAnnotationsIfFirstUse() { fun deserializeFileImplicitDataIfFirstUse() {
annotations?.let { annotations?.let {
file.annotations.addAll(deserializeAnnotations(it)) file.annotations.addAll(deserializeAnnotations(it))
annotations = null annotations = null
} }
forcedDeclarations?.let {
it.forEach { fileLocalDeserializationState.addUniqID(it) }
forcedDeclarations = null
}
} }
fun deserializeFileTopLevelDeclaration(key: UniqId) { fun deserializeAllFileReachableTopLevel() {
fileLocalDeserializationState.processPendingDeclarations {
fileLocalDeserializationState.addUniqID(key)
fileLocalDeserializationState.processPendingDeclaration {
val declaration = deserializeDeclaration(it) val declaration = deserializeDeclaration(it)
file.declarations.add(declaration) file.declarations.add(declaration)
} }
@@ -395,7 +405,10 @@ abstract class KotlinIrLinker(
val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray()) val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray())
val fileDeserializer = IrDeserializerForFile(fileProto.annotationList, fileIndex, !deserializationStrategy.needBodies) val explicitlyExported = mutableListOf<UniqId>()
val fileDeserializer =
IrDeserializerForFile(fileProto.annotationList, explicitlyExported, fileIndex, !deserializationStrategy.needBodies)
val fqName = fileDeserializer.deserializeFqName(fileProto.fqNameList) val fqName = fileDeserializer.deserializeFqName(fileProto.fqNameList)
@@ -413,10 +426,8 @@ abstract class KotlinIrLinker(
moduleReversedFileIndex.getOrPut(it) { fileDeserializer } moduleReversedFileIndex.getOrPut(it) { fileDeserializer }
} }
for (d in fileProto.explicitlyExportedToCompilerList) { fileProto.explicitlyExportedToCompilerList.mapTo(explicitlyExported) {
fileDeserializer.run { UniqId(fileDeserializer.loadSymbolData(it).topLevelUniqIdIndex)
fileLocalDeserializationState.addUniqID(UniqId(loadSymbolData(d).topLevelUniqIdIndex))
}
} }
if (deserializationStrategy.theWholeWorld) { if (deserializationStrategy.theWholeWorld) {
@@ -425,7 +436,7 @@ abstract class KotlinIrLinker(
moduleDeserializationState.addUniqID(id) moduleDeserializationState.addUniqID(id)
} }
} else if (deserializationStrategy.explicitlyExported) { } else if (deserializationStrategy.explicitlyExported) {
modulesWithReachableTopLevels.add(this) moduleDeserializationState.enqueueFile(fileDeserializer)
} }
return file return file
@@ -444,20 +455,19 @@ abstract class KotlinIrLinker(
} }
fun deserializeAllModuleReachableTopLevels() { fun deserializeAllModuleReachableTopLevels() {
moduleDeserializationState.processPendingDeclarations { fileDeserializer ->
moduleDeserializationState.processPendingDeclaration { fileDeserializer.deserializeFileImplicitDataIfFirstUse()
val fileDeserializer = moduleReversedFileIndex[it] fileDeserializer.deserializeAllFileReachableTopLevel()
?: error("No file deserializer for key $it")
fileDeserializer.deserializeFileTopLevelDeclaration(it)
fileDeserializer.deserializeFileAnnotationsIfFirstUse()
} }
} }
fun addModuleReachableTopLevel(topLevelKey: UniqId) { fun enqueueModule() {
moduleDeserializationState.reachableTopLevels.add(topLevelKey)
modulesWithReachableTopLevels.add(this) modulesWithReachableTopLevels.add(this)
} }
fun addModuleReachableTopLevel(key: UniqId) {
moduleDeserializationState.addUniqID(key)
}
} }
protected abstract val descriptorReferenceDeserializer: DescriptorReferenceDeserializer protected abstract val descriptorReferenceDeserializer: DescriptorReferenceDeserializer
@@ -492,7 +502,7 @@ abstract class KotlinIrLinker(
protected abstract fun readFileCount(moduleDescriptor: ModuleDescriptor): Int protected abstract fun readFileCount(moduleDescriptor: ModuleDescriptor): Int
protected abstract fun checkAccessibility(declarationDescriptor: DeclarationDescriptor): Boolean protected abstract fun checkAccessibility(declarationDescriptor: DeclarationDescriptor): Boolean
protected open fun handleNoModuleDeserializerFound(key: UniqId): DeserializationState { protected open fun handleNoModuleDeserializerFound(key: UniqId): DeserializationState<*> {
error("Deserializer for declaration $key is not found") error("Deserializer for declaration $key is not found")
} }
@@ -515,7 +525,6 @@ abstract class KotlinIrLinker(
"Locally accessible declarations should not be accessed here $topLevelDescriptor" "Locally accessible declarations should not be accessed here $topLevelDescriptor"
} }
if (topLevelDescriptor !is DeserializedClassDescriptor && topLevelDescriptor !is DeserializedCallableMemberDescriptor) { if (topLevelDescriptor !is DeserializedClassDescriptor && topLevelDescriptor !is DeserializedCallableMemberDescriptor) {
return null return null
} }
@@ -0,0 +1,25 @@
// IGNORE_BACKEND: JVM, JVM_IR
// IGNORE_LIGHT_ANALYSIS
// MODULE: lib1
// FILE: lib1.kt
// KT-34273
var foo = "Fail"
// MODULE: lib2(lib1)
// FILE: lib2.kt
private val bar = run {
foo = "OK"
42
}
// MODULE: main(lib1, lib2)
// FILE: main.kt
// TODO: the proper behaviour of this test is still open design issue
// K/N & K/JS used to go like this when JVM fails
fun box(): String = foo
@@ -18674,6 +18674,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt"); runTest("compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt");
} }
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("substituteJavaSuperField.kt") @TestMetadata("substituteJavaSuperField.kt")
public void testSubstituteJavaSuperField() throws Exception { public void testSubstituteJavaSuperField() throws Exception {
runTest("compiler/testData/codegen/box/properties/substituteJavaSuperField.kt"); runTest("compiler/testData/codegen/box/properties/substituteJavaSuperField.kt");
@@ -18336,6 +18336,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/properties/augmentedAssignmentsAndIncrements.kt"); runTest("compiler/testData/codegen/box/properties/augmentedAssignmentsAndIncrements.kt");
} }
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void ignoreSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
private void runTest(String testDataFilePath) throws Exception { private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
} }
@@ -17554,6 +17554,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt"); runTest("compiler/testData/codegen/box/properties/protectedJavaPropertyInCompanion.kt");
} }
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("substituteJavaSuperField.kt") @TestMetadata("substituteJavaSuperField.kt")
public void testSubstituteJavaSuperField() throws Exception { public void testSubstituteJavaSuperField() throws Exception {
runTest("compiler/testData/codegen/box/properties/substituteJavaSuperField.kt"); runTest("compiler/testData/codegen/box/properties/substituteJavaSuperField.kt");
@@ -14494,6 +14494,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/properties/privatePropertyWithoutBackingField.kt"); runTest("compiler/testData/codegen/box/properties/privatePropertyWithoutBackingField.kt");
} }
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt") @TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt")
public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception { public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception {
runTest("compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt"); runTest("compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt");
@@ -15649,6 +15649,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/properties/privatePropertyWithoutBackingField.kt"); runTest("compiler/testData/codegen/box/properties/privatePropertyWithoutBackingField.kt");
} }
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt") @TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt")
public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception { public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception {
runTest("compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt"); runTest("compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt");