[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 {
sealed class DeserializationState {
sealed class DeserializationState<T> {
val deserializedSymbols = mutableMapOf<UniqId, IrSymbol>()
val reachableTopLevels = mutableSetOf<UniqId>()
val deserializedTopLevels = mutableSetOf<UniqId>()
operator fun contains(key: UniqId) = key in deserializedSymbols
operator fun get(key: UniqId): IrSymbol = deserializedSymbols[key] ?: error("No deserialized symbol found for $key")
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) {
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) {
reachableTopLevels.add(key)
}
override fun peekReachableKey(): UniqId {
return reachableTopLevels.firstOrNull() ?: error("Expecting non-empty set")
}
}
override fun processPendingDeclarations(processor: (UniqId) -> Unit) {
while (reachableTopLevels.isNotEmpty()) {
val reachableKey = reachableTopLevels.first()
fun processPendingDeclaration(processor: (UniqId) -> Unit) {
do {
if (deserializedSymbols[reachableKey]?.isBound != true) {
processor(reachableKey)
}
val reachableKey = peekReachableKey() ?: return
if (deserializedSymbols[reachableKey]?.isBound == true) {
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>()
private val moduleDeserializationState = DeserializationState.ModuleDeserializationState(this)
private val moduleReversedFileIndex = mutableMapOf<UniqId, IrDeserializerForFile>()
val moduleReversedFileIndex = mutableMapOf<UniqId, IrDeserializerForFile>()
private val moduleDependencies by lazy {
moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { deserializersForModules[it]!! }
}
@@ -131,7 +140,7 @@ abstract class KotlinIrLinker(
// This is a heavy initializer
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) {
private var fileLoops = mutableMapOf<Int, IrLoopBase>()
@@ -281,7 +290,7 @@ abstract class KotlinIrLinker(
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 (isGlobalUniqID(key)) return globalDeserializationState
return getModuleForTopLevelId(key)?.moduleDeserializationState ?: handleNoModuleDeserializerFound(key)
@@ -371,18 +380,19 @@ abstract class KotlinIrLinker(
}
}
fun deserializeFileAnnotationsIfFirstUse() {
fun deserializeFileImplicitDataIfFirstUse() {
annotations?.let {
file.annotations.addAll(deserializeAnnotations(it))
annotations = null
}
forcedDeclarations?.let {
it.forEach { fileLocalDeserializationState.addUniqID(it) }
forcedDeclarations = null
}
}
fun deserializeFileTopLevelDeclaration(key: UniqId) {
fileLocalDeserializationState.addUniqID(key)
fileLocalDeserializationState.processPendingDeclaration {
fun deserializeAllFileReachableTopLevel() {
fileLocalDeserializationState.processPendingDeclarations {
val declaration = deserializeDeclaration(it)
file.declarations.add(declaration)
}
@@ -395,7 +405,10 @@ abstract class KotlinIrLinker(
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)
@@ -413,10 +426,8 @@ abstract class KotlinIrLinker(
moduleReversedFileIndex.getOrPut(it) { fileDeserializer }
}
for (d in fileProto.explicitlyExportedToCompilerList) {
fileDeserializer.run {
fileLocalDeserializationState.addUniqID(UniqId(loadSymbolData(d).topLevelUniqIdIndex))
}
fileProto.explicitlyExportedToCompilerList.mapTo(explicitlyExported) {
UniqId(fileDeserializer.loadSymbolData(it).topLevelUniqIdIndex)
}
if (deserializationStrategy.theWholeWorld) {
@@ -425,7 +436,7 @@ abstract class KotlinIrLinker(
moduleDeserializationState.addUniqID(id)
}
} else if (deserializationStrategy.explicitlyExported) {
modulesWithReachableTopLevels.add(this)
moduleDeserializationState.enqueueFile(fileDeserializer)
}
return file
@@ -444,20 +455,19 @@ abstract class KotlinIrLinker(
}
fun deserializeAllModuleReachableTopLevels() {
moduleDeserializationState.processPendingDeclaration {
val fileDeserializer = moduleReversedFileIndex[it]
?: error("No file deserializer for key $it")
fileDeserializer.deserializeFileTopLevelDeclaration(it)
fileDeserializer.deserializeFileAnnotationsIfFirstUse()
moduleDeserializationState.processPendingDeclarations { fileDeserializer ->
fileDeserializer.deserializeFileImplicitDataIfFirstUse()
fileDeserializer.deserializeAllFileReachableTopLevel()
}
}
fun addModuleReachableTopLevel(topLevelKey: UniqId) {
moduleDeserializationState.reachableTopLevels.add(topLevelKey)
fun enqueueModule() {
modulesWithReachableTopLevels.add(this)
}
fun addModuleReachableTopLevel(key: UniqId) {
moduleDeserializationState.addUniqID(key)
}
}
protected abstract val descriptorReferenceDeserializer: DescriptorReferenceDeserializer
@@ -492,7 +502,7 @@ abstract class KotlinIrLinker(
protected abstract fun readFileCount(moduleDescriptor: ModuleDescriptor): Int
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")
}
@@ -515,7 +525,6 @@ abstract class KotlinIrLinker(
"Locally accessible declarations should not be accessed here $topLevelDescriptor"
}
if (topLevelDescriptor !is DeserializedClassDescriptor && topLevelDescriptor !is DeserializedCallableMemberDescriptor) {
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");
}
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("substituteJavaSuperField.kt")
public void testSubstituteJavaSuperField() throws Exception {
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");
}
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void ignoreSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
@@ -17554,6 +17554,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
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")
public void testSubstituteJavaSuperField() throws Exception {
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");
}
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt")
public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception {
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");
}
@TestMetadata("sideEffectInTopLevelInitializerMultiModule.kt")
public void testSideEffectInTopLevelInitializerMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/properties/sideEffectInTopLevelInitializerMultiModule.kt");
}
@TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt")
public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception {
runTest("compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt");