[Native][IR] Partial linkage support for cached inline functions
- Support partial linkage for declarations from inline functions that are lazily deserialized from a KLIB with static cache - Linker API: Split IrModuleDeserializer.deserializeIrSymbol() into deserializeIrSymbolOrFail() and tryDeserializeIrSymbol() - Linker API: Refactor KotlinIrLinker.handleSignatureIdNotFoundInModuleWithDependencies() to deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled() ^KT-52478
This commit is contained in:
@@ -13,6 +13,7 @@ dependencies {
|
|||||||
compileOnly(project(":kotlin-reflect-api"))
|
compileOnly(project(":kotlin-reflect-api"))
|
||||||
|
|
||||||
compileOnly(intellijCore())
|
compileOnly(intellijCore())
|
||||||
|
compileOnly(commonDependency("org.jetbrains.intellij.deps:trove4j"))
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
|||||||
+4
-4
@@ -97,7 +97,7 @@ abstract class BasicIrModuleDeserializer(
|
|||||||
// TODO: fix to topLevel checker
|
// TODO: fix to topLevel checker
|
||||||
override fun contains(idSig: IdSignature): Boolean = idSig in moduleReversedFileIndex
|
override fun contains(idSig: IdSignature): Boolean = idSig in moduleReversedFileIndex
|
||||||
|
|
||||||
open fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||||
val topLevelSignature = idSig.topLevelSignature()
|
val topLevelSignature = idSig.topLevelSignature()
|
||||||
val fileLocalDeserializationState = moduleReversedFileIndex[topLevelSignature] ?: return null
|
val fileLocalDeserializationState = moduleReversedFileIndex[topLevelSignature] ?: return null
|
||||||
|
|
||||||
@@ -107,9 +107,9 @@ abstract class BasicIrModuleDeserializer(
|
|||||||
return fileLocalDeserializationState.fileDeserializer.symbolDeserializer.deserializeIrSymbol(idSig, symbolKind)
|
return fileLocalDeserializationState.fileDeserializer.symbolDeserializer.deserializeIrSymbol(idSig, symbolKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
final override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind) =
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing {
|
||||||
tryDeserializeIrSymbol(idSig, symbolKind)
|
error("No file for ${idSig.topLevelSignature()} (@ $idSig) in module $moduleDescriptor")
|
||||||
?: error("No file for ${idSig.topLevelSignature()} (@ $idSig) in module $moduleDescriptor")
|
}
|
||||||
|
|
||||||
override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, linker.builtIns, emptyList())
|
override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, linker.builtIns, emptyList())
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -113,14 +113,16 @@ class CurrentModuleWithICDeserializer(
|
|||||||
return idSig in dirtyDeclarations || idSig.topLevelSignature() in icDeserializer || idSig in delegate
|
return idSig in dirtyDeclarations || idSig.topLevelSignature() in icDeserializer || idSig in delegate
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
||||||
dirtyDeclarations[idSig]?.let { return it }
|
dirtyDeclarations[idSig]?.let { return it }
|
||||||
|
|
||||||
if (idSig.topLevelSignature() in icDeserializer) return icDeserializer.deserializeIrSymbol(idSig, symbolKind)
|
if (idSig.topLevelSignature() in icDeserializer) return icDeserializer.deserializeIrSymbolOrFail(idSig, symbolKind)
|
||||||
|
|
||||||
return delegate.deserializeIrSymbol(idSig, symbolKind)
|
return delegate.deserializeIrSymbolOrFail(idSig, symbolKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = delegate.deserializedSymbolNotFound(idSig)
|
||||||
|
|
||||||
override fun addModuleReachableTopLevel(idSig: IdSignature) {
|
override fun addModuleReachableTopLevel(idSig: IdSignature) {
|
||||||
assert(idSig in icDeserializer)
|
assert(idSig in icDeserializer)
|
||||||
icDeserializer.addModuleReachableTopLevel(idSig)
|
icDeserializer.addModuleReachableTopLevel(idSig)
|
||||||
|
|||||||
+2
-12
@@ -74,18 +74,8 @@ class FileDeserializationState(
|
|||||||
::addIdSignature,
|
::addIdSignature,
|
||||||
linker::handleExpectActualMapping,
|
linker::handleExpectActualMapping,
|
||||||
symbolProcessor = linker.symbolProcessor,
|
symbolProcessor = linker.symbolProcessor,
|
||||||
) { idSig, symbolKind ->
|
) { idSignature, symbolKind ->
|
||||||
|
linker.deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled(idSignature, symbolKind, moduleDeserializer)
|
||||||
val topLevelSig = idSig.topLevelSignature()
|
|
||||||
val actualModuleDeserializer = moduleDeserializer.findModuleDeserializerForTopLevelId(topLevelSig)
|
|
||||||
?: run {
|
|
||||||
// The symbol might be gone in newer version of dependency KLIB. Then the KLIB that was compiled against
|
|
||||||
// the older version of dependency KLIB will still have a reference to non-existing symbol. And the linker will have to
|
|
||||||
// handle such situation appropriately. See KT-41378.
|
|
||||||
linker.handleSignatureIdNotFoundInModuleWithDependencies(idSig, moduleDeserializer)
|
|
||||||
}
|
|
||||||
|
|
||||||
actualModuleDeserializer.deserializeIrSymbol(idSig, symbolKind)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val declarationDeserializer = IrDeclarationDeserializer(
|
val declarationDeserializer = IrDeclarationDeserializer(
|
||||||
|
|||||||
+15
-8
@@ -58,7 +58,8 @@ enum class IrModuleDeserializerKind {
|
|||||||
|
|
||||||
abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescriptor?, val libraryAbiVersion: KotlinAbiVersion) {
|
abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescriptor?, val libraryAbiVersion: KotlinAbiVersion) {
|
||||||
abstract operator fun contains(idSig: IdSignature): Boolean
|
abstract operator fun contains(idSig: IdSignature): Boolean
|
||||||
abstract fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol
|
abstract fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol?
|
||||||
|
abstract fun deserializedSymbolNotFound(idSig: IdSignature): Nothing
|
||||||
|
|
||||||
val moduleDescriptor: ModuleDescriptor get() = _moduleDescriptor ?: error("No ModuleDescriptor provided")
|
val moduleDescriptor: ModuleDescriptor get() = _moduleDescriptor ?: error("No ModuleDescriptor provided")
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescrip
|
|||||||
val signature = symbol.signature
|
val signature = symbol.signature
|
||||||
require(signature != null) { "Symbol is not public API: ${symbol.descriptor}" }
|
require(signature != null) { "Symbol is not public API: ${symbol.descriptor}" }
|
||||||
assert(symbol.hasDescriptor)
|
assert(symbol.hasDescriptor)
|
||||||
deserializeIrSymbol(signature, symbol.kind())
|
deserializeIrSymbolOrFail(signature, symbol.kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
open val klib: IrLibrary get() = error("Unsupported operation")
|
open val klib: IrLibrary get() = error("Unsupported operation")
|
||||||
@@ -104,6 +105,9 @@ abstract class IrModuleDeserializer(private val _moduleDescriptor: ModuleDescrip
|
|||||||
open fun signatureDeserializerForFile(fileName: String): IdSignatureDeserializer = error("Unsupported")
|
open fun signatureDeserializerForFile(fileName: String): IdSignatureDeserializer = error("Unsupported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun IrModuleDeserializer.deserializeIrSymbolOrFail(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol =
|
||||||
|
tryDeserializeIrSymbol(idSig, symbolKind) ?: deserializedSymbolNotFound(idSig)
|
||||||
|
|
||||||
// Used to resolve built in symbols like `kotlin.ir.internal.*` or `kotlin.FunctionN`
|
// Used to resolve built in symbols like `kotlin.ir.internal.*` or `kotlin.FunctionN`
|
||||||
class IrModuleDeserializerWithBuiltIns(
|
class IrModuleDeserializerWithBuiltIns(
|
||||||
private val builtIns: IrBuiltIns,
|
private val builtIns: IrBuiltIns,
|
||||||
@@ -199,16 +203,17 @@ class IrModuleDeserializerWithBuiltIns(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||||
irBuiltInsMap[idSig]?.let { return it }
|
irBuiltInsMap[idSig]?.let { return it }
|
||||||
|
|
||||||
val topLevel = idSig.topLevelSignature()
|
val topLevel = idSig.topLevelSignature()
|
||||||
|
|
||||||
if (checkIsFunctionInterface(topLevel)) return resolveFunctionalInterface(idSig, symbolKind)
|
if (checkIsFunctionInterface(topLevel)) return resolveFunctionalInterface(idSig, symbolKind)
|
||||||
|
|
||||||
return delegate.deserializeIrSymbol(idSig, symbolKind)
|
return delegate.tryDeserializeIrSymbol(idSig, symbolKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = delegate.deserializedSymbolNotFound(idSig)
|
||||||
|
|
||||||
override fun declareIrSymbol(symbol: IrSymbol) {
|
override fun declareIrSymbol(symbol: IrSymbol) {
|
||||||
val signature = symbol.signature
|
val signature = symbol.signature
|
||||||
if (signature != null && checkIsFunctionInterface(signature))
|
if (signature != null && checkIsFunctionInterface(signature))
|
||||||
@@ -253,11 +258,13 @@ open class CurrentModuleDeserializer(
|
|||||||
) : IrModuleDeserializer(moduleFragment.descriptor, KotlinAbiVersion.CURRENT) {
|
) : IrModuleDeserializer(moduleFragment.descriptor, KotlinAbiVersion.CURRENT) {
|
||||||
override fun contains(idSig: IdSignature): Boolean = false // TODO:
|
override fun contains(idSig: IdSignature): Boolean = false // TODO:
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): Nothing =
|
||||||
error("Unreachable execution: there could not be back-links (sig: $idSig)")
|
error("Unreachable execution: there could not be back-links (sig: $idSig)")
|
||||||
}
|
|
||||||
|
|
||||||
override fun declareIrSymbol(symbol: IrSymbol) {}
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing =
|
||||||
|
error("Unreachable execution: there could not be back-links (sig: $idSig)")
|
||||||
|
|
||||||
|
override fun declareIrSymbol(symbol: IrSymbol) = Unit
|
||||||
|
|
||||||
override val kind get() = IrModuleDeserializerKind.CURRENT
|
override val kind get() = IrModuleDeserializerKind.CURRENT
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-112
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
|
|||||||
import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker
|
import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.linkerissues.*
|
import org.jetbrains.kotlin.backend.common.serialization.linkerissues.*
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsProcessor
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
@@ -19,14 +18,7 @@ import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.types.IrErrorType
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
|
||||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
import org.jetbrains.kotlin.library.uniqueName
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -59,34 +51,36 @@ abstract class KotlinIrLinker(
|
|||||||
|
|
||||||
private lateinit var linkerExtensions: Collection<IrDeserializer.IrLinkerExtension>
|
private lateinit var linkerExtensions: Collection<IrDeserializer.IrLinkerExtension>
|
||||||
|
|
||||||
protected open val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = UnlinkedDeclarationsSupport.DISABLED
|
protected open val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport get() = UnlinkedDeclarationsSupport.DISABLED
|
||||||
protected open val userVisibleIrModulesSupport: UserVisibleIrModulesSupport = UserVisibleIrModulesSupport.DEFAULT
|
protected open val userVisibleIrModulesSupport: UserVisibleIrModulesSupport get() = UserVisibleIrModulesSupport.DEFAULT
|
||||||
|
|
||||||
fun handleSignatureIdNotFoundInModuleWithDependencies(
|
fun deserializeOrReturnUnboundIrSymbolIfPartialLinkageEnabled(
|
||||||
idSignature: IdSignature,
|
idSignature: IdSignature,
|
||||||
|
symbolKind: BinarySymbolData.SymbolKind,
|
||||||
moduleDeserializer: IrModuleDeserializer
|
moduleDeserializer: IrModuleDeserializer
|
||||||
): IrModuleDeserializer {
|
): IrSymbol {
|
||||||
if (unlinkedDeclarationsSupport.allowUnboundSymbols) {
|
val topLevelSignature: IdSignature = idSignature.topLevelSignature()
|
||||||
return object : IrModuleDeserializer(null, KotlinAbiVersion.CURRENT) {
|
|
||||||
override fun contains(idSig: IdSignature): Boolean = false
|
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
// Note: The top-level symbol might be gone in newer version of dependency KLIB. Then the KLIB that was compiled against
|
||||||
return referenceDeserializedSymbol(symbolTable, null, symbolKind, idSig)
|
// the older version of dependency KLIB will still have a reference to non-existing symbol. And the linker will have to
|
||||||
}
|
// handle such situation appropriately. See KT-41378.
|
||||||
|
val actualModuleDeserializer: IrModuleDeserializer? = moduleDeserializer.findModuleDeserializerForTopLevelId(topLevelSignature)
|
||||||
|
|
||||||
override val moduleFragment: IrModuleFragment
|
// Note: It might happen that the top-level symbol still exists in KLIB, but nested symbol has been removed.
|
||||||
get() = TODO("Not yet implemented")
|
// Then the `actualModuleDeserializer` will be non-null, but `actualModuleDeserializer.tryDeserializeIrSymbol()` call
|
||||||
override val moduleDependencies: Collection<IrModuleDeserializer> get() = emptyList()
|
// will return null.
|
||||||
override val kind: IrModuleDeserializerKind
|
val symbol: IrSymbol? = actualModuleDeserializer?.tryDeserializeIrSymbol(idSignature, symbolKind)
|
||||||
get() = TODO("Not yet implemented")
|
|
||||||
}
|
return symbol ?: run {
|
||||||
} else {
|
if (unlinkedDeclarationsSupport.allowUnboundSymbols)
|
||||||
throw SignatureIdNotFoundInModuleWithDependencies(
|
referenceDeserializedSymbol(symbolTable, null, symbolKind, idSignature)
|
||||||
idSignature = idSignature,
|
else
|
||||||
problemModuleDeserializer = moduleDeserializer,
|
throw SignatureIdNotFoundInModuleWithDependencies(
|
||||||
allModuleDeserializers = deserializersForModules.values,
|
idSignature = idSignature,
|
||||||
userVisibleIrModulesSupport = userVisibleIrModulesSupport
|
problemModuleDeserializer = moduleDeserializer,
|
||||||
).raiseIssue(messageLogger)
|
allModuleDeserializers = deserializersForModules.values,
|
||||||
|
userVisibleIrModulesSupport = userVisibleIrModulesSupport
|
||||||
|
).raiseIssue(messageLogger)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,93 +215,16 @@ abstract class KotlinIrLinker(
|
|||||||
deserializersForModules.values.forEach { it.init() }
|
deserializersForModules.values.forEach { it.init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun markUnlinkedClassifiers(): Set<IrClassifierSymbol> {
|
|
||||||
if (!unlinkedDeclarationsSupport.allowUnboundSymbols) return emptySet()
|
|
||||||
val entries = fakeOverrideBuilder.fakeOverrideCandidates
|
|
||||||
val result = mutableSetOf<IrClassifierSymbol>()
|
|
||||||
|
|
||||||
fun IrType.isUnlinked(visited: MutableSet<IrClassifierSymbol>): Boolean {
|
|
||||||
val simpleType = this as? IrSimpleType ?: return this !is IrErrorType
|
|
||||||
|
|
||||||
val classifier = simpleType.classifier
|
|
||||||
|
|
||||||
if (!classifier.isBound) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (classifier in result) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!visited.add(classifier)) return false
|
|
||||||
|
|
||||||
val superTypes = when (val decl = classifier.owner) {
|
|
||||||
is IrClass -> decl.superTypes
|
|
||||||
is IrTypeParameter -> decl.superTypes
|
|
||||||
else -> emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superTypes.any { it.isUnlinked(visited) }) {
|
|
||||||
result.add(classifier)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ta in simpleType.arguments) {
|
|
||||||
if (ta is IrTypeProjection) {
|
|
||||||
val projected = ta.type
|
|
||||||
if (projected.isUnlinked(visited)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun IrClass.isUnlinked(visited: MutableSet<IrClassifierSymbol>): Boolean {
|
|
||||||
if (symbol in result) return true
|
|
||||||
for (s in superTypes) {
|
|
||||||
if (s.isUnlinked(visited)) {
|
|
||||||
result.add(symbol)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val toRemove = mutableListOf<IrClass>()
|
|
||||||
|
|
||||||
for (e in entries) {
|
|
||||||
val klass = e.key
|
|
||||||
if (klass.isUnlinked(mutableSetOf())) {
|
|
||||||
toRemove.add(klass)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toRemove.forEach { entries.remove(it) }
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyToModules(transformer: IrElementTransformerVoid) {
|
|
||||||
deserializersForModules.values.forEach { it.moduleFragment.transformChildrenVoid(transformer) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun postProcess() {
|
override fun postProcess() {
|
||||||
finalizeExpectActualLinker()
|
finalizeExpectActualLinker()
|
||||||
|
|
||||||
val unlinkedClassifiers = markUnlinkedClassifiers()
|
unlinkedDeclarationsSupport.markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder)
|
||||||
|
|
||||||
fakeOverrideBuilder.provideFakeOverrides()
|
fakeOverrideBuilder.provideFakeOverrides()
|
||||||
triedToDeserializeDeclarationForSymbol.clear()
|
triedToDeserializeDeclarationForSymbol.clear()
|
||||||
|
|
||||||
unlinkedDeclarationsSupport.whenUnboundSymbolsAllowed { unlinkedMarkerTypeHandler ->
|
unlinkedDeclarationsSupport.processUnlinkedDeclarations(messageLogger) {
|
||||||
val t = UnlinkedDeclarationsProcessor(builtIns, unlinkedClassifiers, unlinkedMarkerTypeHandler, messageLogger)
|
deserializersForModules.values.map { it.moduleFragment }
|
||||||
t.addLinkageErrorIntoUnlinkedClasses()
|
|
||||||
|
|
||||||
applyToModules(t.signatureTransformer())
|
|
||||||
applyToModules(t.usageTransformer())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix IrPluginContext to make it not produce additional external reference
|
// TODO: fix IrPluginContext to make it not produce additional external reference
|
||||||
@@ -359,7 +276,7 @@ abstract class KotlinIrLinker(
|
|||||||
?: error("No module for name '$moduleName' found")
|
?: error("No module for name '$moduleName' found")
|
||||||
assert(signature == signature.topLevelSignature()) { "Signature '$signature' has to be top level" }
|
assert(signature == signature.topLevelSignature()) { "Signature '$signature' has to be top level" }
|
||||||
if (signature !in moduleDeserializer) error("No signature $signature in module $moduleName")
|
if (signature !in moduleDeserializer) error("No signature $signature in module $moduleName")
|
||||||
return moduleDeserializer.deserializeIrSymbol(signature, topLevelKindToSymbolKind(kind)).also {
|
return moduleDeserializer.deserializeIrSymbolOrFail(signature, topLevelKindToSymbolKind(kind)).also {
|
||||||
deserializeAllReachableTopLevels()
|
deserializeAllReachableTopLevels()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+176
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.unlinked
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||||
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConstantObject
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrErrorType
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||||
|
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
abstract class BasicUnlinkedDeclarationsSupport : UnlinkedDeclarationsSupport {
|
||||||
|
protected abstract val handler: UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
||||||
|
protected abstract val builtIns: IrBuiltIns
|
||||||
|
|
||||||
|
private val usedClassifierSymbols = UsedClassifierSymbols()
|
||||||
|
|
||||||
|
final override fun markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder: FakeOverrideBuilder) {
|
||||||
|
if (!allowUnboundSymbols) return
|
||||||
|
|
||||||
|
val entries = fakeOverrideBuilder.fakeOverrideCandidates
|
||||||
|
if (entries.isEmpty()) return
|
||||||
|
|
||||||
|
val toRemove = hashSetOf<IrClass>()
|
||||||
|
for (clazz in entries.keys) {
|
||||||
|
if (clazz.symbol.isUnlinkedClassifier(visited = hashSetOf())) {
|
||||||
|
toRemove += clazz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entries -= toRemove
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrType.isUnlinkedType(visited: MutableSet<IrClassifierSymbol>): Boolean {
|
||||||
|
val simpleType = this as? IrSimpleType ?: return this !is IrErrorType
|
||||||
|
|
||||||
|
if (simpleType.classifier.isUnlinkedClassifier(visited))
|
||||||
|
return true
|
||||||
|
|
||||||
|
for (argument in simpleType.arguments) {
|
||||||
|
if (argument is IrTypeProjection) {
|
||||||
|
if (argument.type.isUnlinkedType(visited))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrClassifierSymbol.isUnlinkedClassifier(visited: MutableSet<IrClassifierSymbol>): Boolean {
|
||||||
|
when (val status = usedClassifierSymbols[this]) {
|
||||||
|
UNLINKED, LINKED -> return status.isUnlinked
|
||||||
|
null -> {
|
||||||
|
// Unknown classifier. Continue.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isBound || (hasDescriptor && descriptor is NotFoundClasses.MockClassDescriptor))
|
||||||
|
return usedClassifierSymbols.register(this, UNLINKED)
|
||||||
|
|
||||||
|
if (!visited.add(this))
|
||||||
|
return false // Recursion avoidance.
|
||||||
|
|
||||||
|
when (val classifier = owner) {
|
||||||
|
is IrClass -> {
|
||||||
|
if (classifier.parentClassOrNull?.symbol?.isUnlinkedClassifier(visited) == true)
|
||||||
|
return usedClassifierSymbols.register(this, UNLINKED)
|
||||||
|
|
||||||
|
for (typeParameter in classifier.typeParameters) {
|
||||||
|
if (typeParameter.superTypes.any { it.isUnlinkedType(visited) })
|
||||||
|
return usedClassifierSymbols.register(this, UNLINKED)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (classifier.superTypes.any { it.isUnlinkedType(visited) })
|
||||||
|
return usedClassifierSymbols.register(this, UNLINKED)
|
||||||
|
}
|
||||||
|
is IrTypeParameter -> {
|
||||||
|
if (classifier.superTypes.any { it.isUnlinkedType(visited) })
|
||||||
|
return usedClassifierSymbols.register(this, UNLINKED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return usedClassifierSymbols.register(this, LINKED)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun markUsedClassifiersInInlineLazyIrFunction(function: IrFunction) {
|
||||||
|
if (!allowUnboundSymbols) return
|
||||||
|
|
||||||
|
function.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun visitType(type: IrType?) {
|
||||||
|
type?.isUnlinkedType(visited = hashSetOf())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||||
|
visitType(declaration.type)
|
||||||
|
super.visitValueParameter(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTypeParameter(declaration: IrTypeParameter) {
|
||||||
|
declaration.superTypes.forEach(::visitType)
|
||||||
|
super.visitTypeParameter(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
visitType(declaration.returnType)
|
||||||
|
super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField) {
|
||||||
|
visitType(declaration.type)
|
||||||
|
super.visitField(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
|
visitType(declaration.type)
|
||||||
|
super.visitVariable(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitExpression(expression: IrExpression) {
|
||||||
|
visitType(expression.type)
|
||||||
|
super.visitExpression(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClassReference(expression: IrClassReference) {
|
||||||
|
visitType(expression.classType)
|
||||||
|
super.visitClassReference(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitConstantObject(expression: IrConstantObject) {
|
||||||
|
expression.typeArguments.forEach(::visitType)
|
||||||
|
super.visitConstantObject(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall) {
|
||||||
|
visitType(expression.typeOperand)
|
||||||
|
super.visitTypeOperator(expression)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processUnlinkedDeclarations(messageLogger: IrMessageLogger, lazyRoots: () -> List<IrElement>) {
|
||||||
|
if (!allowUnboundSymbols) return
|
||||||
|
|
||||||
|
val processor = UnlinkedDeclarationsProcessor(builtIns, usedClassifierSymbols, handler, messageLogger)
|
||||||
|
processor.addLinkageErrorIntoUnlinkedClasses()
|
||||||
|
|
||||||
|
val roots = lazyRoots()
|
||||||
|
|
||||||
|
val signatureTransformer = processor.signatureTransformer()
|
||||||
|
roots.forEach { it.transformChildrenVoid(signatureTransformer) }
|
||||||
|
|
||||||
|
val usageTransformer = processor.usageTransformer()
|
||||||
|
roots.forEach { it.transformChildrenVoid(usageTransformer) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
-27
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.common.serialization.unlinked
|
package org.jetbrains.kotlin.backend.common.serialization.unlinked
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.Companion.isUnlinked
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
@@ -27,39 +28,34 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
|
|
||||||
internal class UnlinkedDeclarationsProcessor(
|
internal class UnlinkedDeclarationsProcessor(
|
||||||
private val builtIns: IrBuiltIns,
|
private val builtIns: IrBuiltIns,
|
||||||
private val unlinkedClassifiers: Set<IrClassifierSymbol>,
|
private val usedClassifierSymbols: UsedClassifierSymbols,
|
||||||
private val unlinkedMarkerTypeHandler: UnlinkedMarkerTypeHandler,
|
private val unlinkedMarkerTypeHandler: UnlinkedMarkerTypeHandler,
|
||||||
private val messageLogger: IrMessageLogger
|
private val messageLogger: IrMessageLogger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val errorOrigin = object : IrStatementOriginImpl("LINKAGE ERROR") {}
|
private val ERROR_ORIGIN = object : IrStatementOriginImpl("LINKAGE ERROR") {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addLinkageErrorIntoUnlinkedClasses() {
|
fun addLinkageErrorIntoUnlinkedClasses() {
|
||||||
for (u in unlinkedClassifiers) {
|
usedClassifierSymbols.forEachClassSymbolToPatch { unlinkedSymbol ->
|
||||||
if (u is IrClassSymbol) {
|
val clazz = unlinkedSymbol.owner
|
||||||
val klass = u.owner
|
clazz.reportUnlinkedSymbolsWarning("Class", clazz.fqNameForIrSerialization)
|
||||||
val anonInitializer = klass.declarations.firstOrNull { it is IrAnonymousInitializer } as IrAnonymousInitializer? ?: run {
|
|
||||||
builtIns.irFactory.createAnonymousInitializer(
|
val anonInitializer = clazz.declarations.firstNotNullOfOrNull { it as? IrAnonymousInitializer }
|
||||||
klass.startOffset,
|
?: builtIns.irFactory.createAnonymousInitializer(
|
||||||
klass.endOffset,
|
clazz.startOffset,
|
||||||
IrDeclarationOrigin.DEFINED,
|
clazz.endOffset,
|
||||||
IrAnonymousInitializerSymbolImpl()
|
IrDeclarationOrigin.DEFINED,
|
||||||
).also {
|
IrAnonymousInitializerSymbolImpl()
|
||||||
it.body = builtIns.irFactory.createBlockBody(klass.startOffset, klass.endOffset)
|
).also {
|
||||||
it.parent = klass
|
it.body = builtIns.irFactory.createBlockBody(clazz.startOffset, clazz.endOffset)
|
||||||
klass.declarations.add(it)
|
it.parent = clazz
|
||||||
}
|
clazz.declarations.add(it)
|
||||||
}
|
}
|
||||||
anonInitializer.body.statements.clear()
|
anonInitializer.body.statements.clear()
|
||||||
|
anonInitializer.body.statements.add(clazz.throwLinkageError(clazz.symbol))
|
||||||
|
|
||||||
klass.reportUnlinkedSymbolsWarning("Class", klass.fqNameForIrSerialization)
|
clazz.superTypes = clazz.superTypes.filter { !it.isUnlinked() }
|
||||||
|
|
||||||
anonInitializer.body.statements.add(klass.throwLinkageError(klass.symbol))
|
|
||||||
|
|
||||||
klass.superTypes = klass.superTypes.filter { !it.isUnlinked() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +251,7 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrClassifierSymbol.isUnlinked(): Boolean = !isBound || this in unlinkedClassifiers
|
private fun IrClassifierSymbol.isUnlinked(): Boolean = !isBound || usedClassifierSymbols[this].isUnlinked
|
||||||
|
|
||||||
private fun IrType.isUnlinked(): Boolean {
|
private fun IrType.isUnlinked(): Boolean {
|
||||||
val simpleType = this as? IrSimpleType ?: return false
|
val simpleType = this as? IrSimpleType ?: return false
|
||||||
@@ -287,7 +283,7 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
private fun IrElement.throwLinkageError(unlinkedSymbol: IrSymbol?, message: String = "Unlinked IR symbol"): IrCall {
|
private fun IrElement.throwLinkageError(unlinkedSymbol: IrSymbol?, message: String = "Unlinked IR symbol"): IrCall {
|
||||||
val messageLiteral = message + unlinkedSymbol?.signature?.render()?.let { " $it" }.orEmpty()
|
val messageLiteral = message + unlinkedSymbol?.signature?.render()?.let { " $it" }.orEmpty()
|
||||||
|
|
||||||
val irCall = IrCallImpl(startOffset, endOffset, builtIns.nothingType, builtIns.linkageErrorSymbol, 0, 1, errorOrigin)
|
val irCall = IrCallImpl(startOffset, endOffset, builtIns.nothingType, builtIns.linkageErrorSymbol, 0, 1, ERROR_ORIGIN)
|
||||||
irCall.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, messageLiteral))
|
irCall.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, builtIns.stringType, messageLiteral))
|
||||||
return irCall
|
return irCall
|
||||||
}
|
}
|
||||||
@@ -338,7 +334,7 @@ internal class UnlinkedDeclarationsProcessor(
|
|||||||
if (!symbol.isUnlinked() && !expression.type.isUnlinked()) return expression
|
if (!symbol.isUnlinked() && !expression.type.isUnlinked()) return expression
|
||||||
|
|
||||||
reportWarning(
|
reportWarning(
|
||||||
"Accessing declaration contains unlinked symbol ${symbol.signature?.render() ?: ""}",
|
"Accessing declaration with unlinked symbol ${symbol.signature?.render() ?: ""}",
|
||||||
currentFile?.location(expression.startOffset)
|
currentFile?.location(expression.startOffset)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+15
-2
@@ -5,11 +5,22 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.serialization.unlinked
|
package org.jetbrains.kotlin.backend.common.serialization.unlinked
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
|
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||||
|
|
||||||
interface UnlinkedDeclarationsSupport {
|
interface UnlinkedDeclarationsSupport {
|
||||||
val allowUnboundSymbols: Boolean
|
val allowUnboundSymbols: Boolean
|
||||||
fun <T : Any> whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T?
|
|
||||||
|
/** For general use in IR linker. */
|
||||||
|
fun markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder: FakeOverrideBuilder)
|
||||||
|
|
||||||
|
/** For local use only in inline lazy-IR functions. */
|
||||||
|
fun markUsedClassifiersInInlineLazyIrFunction(function: IrFunction)
|
||||||
|
|
||||||
|
fun processUnlinkedDeclarations(messageLogger: IrMessageLogger, lazyRoots: () -> List<IrElement>)
|
||||||
|
|
||||||
interface UnlinkedMarkerTypeHandler {
|
interface UnlinkedMarkerTypeHandler {
|
||||||
val unlinkedMarkerType: IrType
|
val unlinkedMarkerType: IrType
|
||||||
@@ -19,7 +30,9 @@ interface UnlinkedDeclarationsSupport {
|
|||||||
companion object {
|
companion object {
|
||||||
val DISABLED = object : UnlinkedDeclarationsSupport {
|
val DISABLED = object : UnlinkedDeclarationsSupport {
|
||||||
override val allowUnboundSymbols get() = false
|
override val allowUnboundSymbols get() = false
|
||||||
override fun <T : Any> whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? = null
|
override fun markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder: FakeOverrideBuilder) = Unit
|
||||||
|
override fun markUsedClassifiersInInlineLazyIrFunction(function: IrFunction) = Unit
|
||||||
|
override fun processUnlinkedDeclarations(messageLogger: IrMessageLogger, lazyRoots: () -> List<IrElement>) = Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 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.unlinked
|
||||||
|
|
||||||
|
import gnu.trove.THashSet
|
||||||
|
import gnu.trove.TObjectByteHashMap
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||||
|
|
||||||
|
internal enum class UsedClassifierSymbolStatus(val isUnlinked: Boolean) {
|
||||||
|
/** IR symbol of unlinked classifier. */
|
||||||
|
UNLINKED(true),
|
||||||
|
|
||||||
|
/** IR symbol of linked classifier. */
|
||||||
|
LINKED(false);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val UsedClassifierSymbolStatus?.isUnlinked: Boolean get() = this?.isUnlinked == true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class UsedClassifierSymbols {
|
||||||
|
private val symbols = TObjectByteHashMap<IrClassifierSymbol>()
|
||||||
|
private val patchedSymbols = THashSet<IrClassSymbol>() // To avoid re-patching what already has been patched.
|
||||||
|
|
||||||
|
fun forEachClassSymbolToPatch(patchAction: (IrClassSymbol) -> Unit) {
|
||||||
|
symbols.forEachEntry { symbol, code ->
|
||||||
|
if (symbol.isBound && code.status == UNLINKED && symbol is IrClassSymbol && patchedSymbols.add(symbol)) {
|
||||||
|
patchAction(symbol)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(symbol: IrClassifierSymbol): UsedClassifierSymbolStatus? = symbols[symbol].status
|
||||||
|
|
||||||
|
fun register(symbol: IrClassifierSymbol, status: UsedClassifierSymbolStatus): Boolean {
|
||||||
|
symbols.put(symbol, status.code)
|
||||||
|
return status.isUnlinked
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private inline val Byte.status: UsedClassifierSymbolStatus?
|
||||||
|
get() = when (this) {
|
||||||
|
1.toByte() -> UNLINKED
|
||||||
|
2.toByte() -> LINKED
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline val UsedClassifierSymbolStatus.code: Byte
|
||||||
|
get() = when (this) {
|
||||||
|
UNLINKED -> 1.toByte()
|
||||||
|
LINKED -> 2.toByte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -376,7 +376,7 @@ fun getIrModuleInfoForKlib(
|
|||||||
val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
||||||
|
|
||||||
val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false
|
val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false
|
||||||
val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols)
|
val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(irBuiltIns, allowUnboundSymbols)
|
||||||
|
|
||||||
val irLinker = JsIrLinker(
|
val irLinker = JsIrLinker(
|
||||||
currentModule = null,
|
currentModule = null,
|
||||||
@@ -435,7 +435,7 @@ fun getIrModuleInfoForSourceFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false
|
val allowUnboundSymbols = configuration[JSConfigurationKeys.PARTIAL_LINKAGE] ?: false
|
||||||
val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols)
|
val unlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(irBuiltIns, allowUnboundSymbols)
|
||||||
|
|
||||||
val irLinker = JsIrLinker(
|
val irLinker = JsIrLinker(
|
||||||
currentModule = psi2IrContext.moduleDescriptor,
|
currentModule = psi2IrContext.moduleDescriptor,
|
||||||
|
|||||||
+4
-1
@@ -30,7 +30,10 @@ class JsIrLinker(
|
|||||||
override val translationPluginContext: TranslationPluginContext?,
|
override val translationPluginContext: TranslationPluginContext?,
|
||||||
private val icData: ICData? = null,
|
private val icData: ICData? = null,
|
||||||
friendModules: Map<String, Collection<String>> = emptyMap(),
|
friendModules: Map<String, Collection<String>> = emptyMap(),
|
||||||
override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols = false),
|
override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(
|
||||||
|
builtIns,
|
||||||
|
allowUnboundSymbols = false
|
||||||
|
),
|
||||||
private val stubGenerator: DeclarationStubGenerator? = null
|
private val stubGenerator: DeclarationStubGenerator? = null
|
||||||
) : KotlinIrLinker(
|
) : KotlinIrLinker(
|
||||||
currentModule = currentModule,
|
currentModule = currentModule,
|
||||||
|
|||||||
+4
-6
@@ -35,12 +35,8 @@ class JsLazyIrModuleDeserializer(
|
|||||||
|
|
||||||
private val descriptorFinder = DescriptorByIdSignatureFinderImpl(moduleDescriptor, JsManglerDesc)
|
private val descriptorFinder = DescriptorByIdSignatureFinderImpl(moduleDescriptor, JsManglerDesc)
|
||||||
|
|
||||||
private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||||
return descriptorFinder.findDescriptorBySignature(idSig) ?: error("No descriptor found for $idSig")
|
val descriptor = descriptorFinder.findDescriptorBySignature(idSig) ?: return null
|
||||||
}
|
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
|
||||||
val descriptor = resolveDescriptor(idSig)
|
|
||||||
|
|
||||||
val declaration = stubGenerator.run {
|
val declaration = stubGenerator.run {
|
||||||
when (symbolKind) {
|
when (symbolKind) {
|
||||||
@@ -57,6 +53,8 @@ class JsLazyIrModuleDeserializer(
|
|||||||
return declaration.symbol
|
return declaration.symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig")
|
||||||
|
|
||||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||||
override fun declareIrSymbol(symbol: IrSymbol) {
|
override fun declareIrSymbol(symbol: IrSymbol) {
|
||||||
if (symbol is IrFieldSymbol) {
|
if (symbol is IrFieldSymbol) {
|
||||||
|
|||||||
+7
-6
@@ -5,19 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.BasicUnlinkedDeclarationsSupport
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
||||||
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.types.IrErrorType
|
import org.jetbrains.kotlin.ir.types.IrErrorType
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
class JsUnlinkedDeclarationsSupport(override val allowUnboundSymbols: Boolean) : UnlinkedDeclarationsSupport {
|
class JsUnlinkedDeclarationsSupport(
|
||||||
private val handler = object : UnlinkedMarkerTypeHandler {
|
override val builtIns: IrBuiltIns,
|
||||||
|
override val allowUnboundSymbols: Boolean
|
||||||
|
) : BasicUnlinkedDeclarationsSupport() {
|
||||||
|
override val handler = object : UnlinkedMarkerTypeHandler {
|
||||||
override val unlinkedMarkerType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
|
override val unlinkedMarkerType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
|
||||||
override fun IrType.isUnlinkedMarkerType() = this is IrErrorType
|
override fun IrType.isUnlinkedMarkerType() = this is IrErrorType
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? =
|
|
||||||
if (allowUnboundSymbols) action(handler) else null
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -134,12 +134,10 @@ class JvmIrLinker(
|
|||||||
DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY
|
DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor {
|
private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor? = descriptorFinder.findDescriptorBySignature(idSig)
|
||||||
return descriptorFinder.findDescriptorBySignature(idSig) ?: error("No descriptor found for $idSig")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||||
val descriptor = resolveDescriptor(idSig)
|
val descriptor = resolveDescriptor(idSig) ?: return null
|
||||||
|
|
||||||
val declaration = stubGenerator.run {
|
val declaration = stubGenerator.run {
|
||||||
when (symbolKind) {
|
when (symbolKind) {
|
||||||
@@ -156,6 +154,8 @@ class JvmIrLinker(
|
|||||||
return declaration.symbol
|
return declaration.symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig")
|
||||||
|
|
||||||
override fun declareIrSymbol(symbol: IrSymbol) {
|
override fun declareIrSymbol(symbol: IrSymbol) {
|
||||||
if (symbol is IrFieldSymbol) {
|
if (symbol is IrFieldSymbol) {
|
||||||
declareJavaFieldStub(symbol)
|
declareJavaFieldStub(symbol)
|
||||||
|
|||||||
+1
@@ -112,6 +112,7 @@ internal class IrProviderForCEnumAndCStructStubs(
|
|||||||
generateIrIfNeeded(s, file)
|
generateIrIfNeeded(s, file)
|
||||||
s.owner
|
s.owner
|
||||||
}
|
}
|
||||||
|
// TODO: better error message?
|
||||||
else -> error("Unexpected symbol kind $symbolKind for sig $idSignature")
|
else -> error("Unexpected symbol kind $symbolKind for sig $idSignature")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-7
@@ -606,8 +606,8 @@ internal class KonanIrLinker(
|
|||||||
return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol
|
return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||||
val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: error("Expecting descriptor for $idSig")
|
val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null
|
||||||
// If library is cached we don't need to create an IrClass for struct or enum.
|
// If library is cached we don't need to create an IrClass for struct or enum.
|
||||||
if (!isLibraryCached && descriptor.isCEnumsOrCStruct()) return resolveCEnumsOrStruct(descriptor, idSig, symbolKind)
|
if (!isLibraryCached && descriptor.isCEnumsOrCStruct()) return resolveCEnumsOrStruct(descriptor, idSig, symbolKind)
|
||||||
|
|
||||||
@@ -616,6 +616,8 @@ internal class KonanIrLinker(
|
|||||||
return symbolOwner.symbol
|
return symbolOwner.symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig")
|
||||||
|
|
||||||
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
|
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
|
||||||
override val moduleDependencies: Collection<IrModuleDeserializer> = listOfNotNull(forwardDeclarationDeserializer)
|
override val moduleDependencies: Collection<IrModuleDeserializer> = listOfNotNull(forwardDeclarationDeserializer)
|
||||||
|
|
||||||
@@ -664,6 +666,8 @@ internal class KonanIrLinker(
|
|||||||
return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol
|
return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig")
|
||||||
|
|
||||||
private val inlineFunctionReferences by lazy {
|
private val inlineFunctionReferences by lazy {
|
||||||
cachedLibraries.getLibraryCache(klib)!!.serializedInlineFunctionBodies.associateBy {
|
cachedLibraries.getLibraryCache(klib)!!.serializedInlineFunctionBodies.associateBy {
|
||||||
fileDeserializationStates[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature)
|
fileDeserializationStates[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature)
|
||||||
@@ -673,7 +677,7 @@ internal class KonanIrLinker(
|
|||||||
fun deserializeInlineFunction(function: IrFunction): InlineFunctionOriginInfo {
|
fun deserializeInlineFunction(function: IrFunction): InlineFunctionOriginInfo {
|
||||||
val packageFragment = function.getPackageFragment() as? IrExternalPackageFragment
|
val packageFragment = function.getPackageFragment() as? IrExternalPackageFragment
|
||||||
?: error("Expected an external package fragment for ${function.render()}")
|
?: error("Expected an external package fragment for ${function.render()}")
|
||||||
if (function.parents.any { (it as? IrFunction)?.isInline == true}) {
|
if (function.parents.any { (it as? IrFunction)?.isInline == true }) {
|
||||||
// Already deserialized by the top-most inline function.
|
// Already deserialized by the top-most inline function.
|
||||||
return InlineFunctionOriginInfo(
|
return InlineFunctionOriginInfo(
|
||||||
function,
|
function,
|
||||||
@@ -742,8 +746,13 @@ internal class KonanIrLinker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlinkedDeclarationsSupport.markUsedClassifiersExcludingUnlinkedFromFakeOverrideBuilding(fakeOverrideBuilder)
|
||||||
|
unlinkedDeclarationsSupport.markUsedClassifiersInInlineLazyIrFunction(function)
|
||||||
|
|
||||||
fakeOverrideBuilder.provideFakeOverrides()
|
fakeOverrideBuilder.provideFakeOverrides()
|
||||||
|
|
||||||
|
unlinkedDeclarationsSupport.processUnlinkedDeclarations(linker.messageLogger) { listOf(function) }
|
||||||
|
|
||||||
return InlineFunctionOriginInfo(function, fileDeserializationState.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset)
|
return InlineFunctionOriginInfo(function, fileDeserializationState.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,10 +838,10 @@ internal class KonanIrLinker(
|
|||||||
|
|
||||||
override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature()
|
override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature()
|
||||||
|
|
||||||
private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor =
|
private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor? =
|
||||||
with(idSig as IdSignature.CommonSignature) {
|
with(idSig as IdSignature.CommonSignature) {
|
||||||
val classId = ClassId(packageFqName(), FqName(declarationFqName), false)
|
val classId = ClassId(packageFqName(), FqName(declarationFqName), false)
|
||||||
moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig")
|
moduleDescriptor.findClassAcrossModuleDependencies(classId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass {
|
private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass {
|
||||||
@@ -841,11 +850,11 @@ internal class KonanIrLinker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
|
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||||
require(symbolKind == BinarySymbolData.SymbolKind.CLASS_SYMBOL) {
|
require(symbolKind == BinarySymbolData.SymbolKind.CLASS_SYMBOL) {
|
||||||
"Only class could be a Forward declaration $idSig (kind $symbolKind)"
|
"Only class could be a Forward declaration $idSig (kind $symbolKind)"
|
||||||
}
|
}
|
||||||
val descriptor = resolveDescriptor(idSig)
|
val descriptor = resolveDescriptor(idSig) ?: return null
|
||||||
val actualModule = descriptor.module
|
val actualModule = descriptor.module
|
||||||
if (actualModule !== moduleDescriptor) {
|
if (actualModule !== moduleDescriptor) {
|
||||||
val moduleDeserializer = resolveModuleDeserializer(actualModule, idSig)
|
val moduleDeserializer = resolveModuleDeserializer(actualModule, idSig)
|
||||||
@@ -856,6 +865,8 @@ internal class KonanIrLinker(
|
|||||||
return declaredDeclaration.getOrPut(idSig) { buildForwardDeclarationStub(descriptor) }.symbol
|
return declaredDeclaration.getOrPut(idSig) { buildForwardDeclarationStub(descriptor) }.symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deserializedSymbolNotFound(idSig: IdSignature): Nothing = error("No descriptor found for $idSig")
|
||||||
|
|
||||||
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
|
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
|
||||||
override val moduleDependencies: Collection<IrModuleDeserializer> = emptyList()
|
override val moduleDependencies: Collection<IrModuleDeserializer> = emptyList()
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan.serialization
|
package org.jetbrains.kotlin.backend.konan.serialization
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.BasicUnlinkedDeclarationsSupport
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport.UnlinkedMarkerTypeHandler
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.types.IrErrorType
|
import org.jetbrains.kotlin.ir.types.IrErrorType
|
||||||
@@ -16,10 +16,13 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
|||||||
* Kotlin/Native backend does not support [IrErrorType].
|
* Kotlin/Native backend does not support [IrErrorType].
|
||||||
* So, let's use a special instance of nullable [kotlin.Any] as a marker-type instead.
|
* So, let's use a special instance of nullable [kotlin.Any] as a marker-type instead.
|
||||||
*/
|
*/
|
||||||
class KonanUnlinkedDeclarationsSupport(irBuiltIns: IrBuiltIns, override val allowUnboundSymbols: Boolean) : UnlinkedDeclarationsSupport {
|
class KonanUnlinkedDeclarationsSupport(
|
||||||
private val handler = object : UnlinkedMarkerTypeHandler {
|
override val builtIns: IrBuiltIns,
|
||||||
|
override val allowUnboundSymbols: Boolean
|
||||||
|
) : BasicUnlinkedDeclarationsSupport() {
|
||||||
|
override val handler = object : UnlinkedMarkerTypeHandler {
|
||||||
override val unlinkedMarkerType = IrSimpleTypeImpl(
|
override val unlinkedMarkerType = IrSimpleTypeImpl(
|
||||||
classifier = irBuiltIns.anyClass,
|
classifier = builtIns.anyClass,
|
||||||
hasQuestionMark = true,
|
hasQuestionMark = true,
|
||||||
arguments = emptyList(),
|
arguments = emptyList(),
|
||||||
annotations = emptyList()
|
annotations = emptyList()
|
||||||
@@ -27,7 +30,4 @@ class KonanUnlinkedDeclarationsSupport(irBuiltIns: IrBuiltIns, override val allo
|
|||||||
|
|
||||||
override fun IrType.isUnlinkedMarkerType(): Boolean = this === unlinkedMarkerType
|
override fun IrType.isUnlinkedMarkerType(): Boolean = this === unlinkedMarkerType
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : Any> whenUnboundSymbolsAllowed(action: (UnlinkedMarkerTypeHandler) -> T): T? =
|
|
||||||
if (allowUnboundSymbols) action(handler) else null
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user