[KLIB] Fix explicitlyExported mode
- Refactor deserialization pipeline - Fix K/N test
This commit is contained in:
+60
-51
@@ -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
|
||||
}
|
||||
|
||||
+25
@@ -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
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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);
|
||||
}
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user