[KLIB] Introduce compatible mode for klibs.

Based on library ABI version linker could decide which signature mode
to be used to guarantee backward compatibility.
This commit is contained in:
Roman Artemev
2021-05-26 19:42:06 +03:00
committed by TeamCityServer
parent 3e99951a66
commit b5c28c1912
38 changed files with 343 additions and 256 deletions
@@ -5,7 +5,10 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrOverridableMember
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -41,7 +44,7 @@ class FakeOverrideChecker(
.filterNot { it.visibility == DescriptorVisibilities.PRIVATE || it.visibility == DescriptorVisibilities.INVISIBLE_FAKE }
val descriptorSignatures = descriptorFakeOverrides
.map { with(descriptorMangler) { it.signatureString }}
.map { with(descriptorMangler) { it.signatureString() } }
.sorted()
val irFakeOverrides = clazz.declarations
@@ -53,7 +56,7 @@ class FakeOverrideChecker(
}
val irSignatures = irFakeOverrides
.map { with(irMangler) { it.signatureString }}
.map { with(irMangler) { it.signatureString() } }
.sorted()
// We can't have equality here because dependency libraries could have
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.backend.common.overrides
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.backend.common.serialization.GlobalDeclarationTable
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
@@ -31,6 +32,7 @@ import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.fileOrNull
import org.jetbrains.kotlin.ir.util.parentAsClass
class FakeOverrideGlobalDeclarationTable(
@@ -77,13 +79,15 @@ class FakeOverrideBuilder(
// TODO: The declaration table is needed for the signaturer.
private val fakeOverrideDeclarationTable = FakeOverrideDeclarationTable(mangler)
private val fakeOverrideClassQueue = mutableListOf<IrClass>()
fun enqueueClass(clazz: IrClass, signature: IdSignature) {
// private class CompatibilityMode(val oldSignatures: Boolean)
private val fakeOverrideCandidates = mutableMapOf<IrClass, CompatibilityMode>()
fun enqueueClass(clazz: IrClass, signature: IdSignature, compatibilityMode: CompatibilityMode) {
fakeOverrideDeclarationTable.assumeDeclarationSignature(clazz, signature)
fakeOverrideClassQueue.add(clazz)
fakeOverrideCandidates[clazz] = compatibilityMode
}
private fun buildFakeOverrideChainsForClass(clazz: IrClass) {
private fun buildFakeOverrideChainsForClass(clazz: IrClass, compatibilityMode: CompatibilityMode) {
if (haveFakeOverrides.contains(clazz)) return
if (!platformSpecificClassFilter.needToConstructFakeOverrides(clazz)) return
@@ -93,20 +97,25 @@ class FakeOverrideBuilder(
it.getClass() ?: error("Unexpected super type: $it")
}
superClasses.forEach {
buildFakeOverrideChainsForClass(it)
haveFakeOverrides.add(it)
superClasses.forEach { superClass ->
val mode = fakeOverrideCandidates[superClass] ?: compatibilityMode
buildFakeOverrideChainsForClass(superClass, mode)
haveFakeOverrides.add(superClass)
}
irOverridingUtil.buildFakeOverridesForClass(clazz)
fakeOverrideDeclarationTable.run {
inFile(clazz.fileOrNull) {
irOverridingUtil.buildFakeOverridesForClass(clazz, compatibilityMode.oldSignatures)
}
}
}
override fun linkFunctionFakeOverride(declaration: IrFakeOverrideFunction) {
val signature = composeSignature(declaration)
override fun linkFunctionFakeOverride(declaration: IrFakeOverrideFunction, compatibilityMode: Boolean) {
val signature = composeSignature(declaration, compatibilityMode)
declareFunctionFakeOverride(declaration, signature)
}
override fun linkPropertyFakeOverride(declaration: IrFakeOverrideProperty) {
override fun linkPropertyFakeOverride(declaration: IrFakeOverrideProperty, compatibilityMode: Boolean) {
// To compute a signature for a property with type parameters,
// we must have its accessor's correspondingProperty pointing to the property's symbol.
// See IrMangleComputer.mangleTypeParameterReference() for details.
@@ -123,21 +132,21 @@ class FakeOverrideBuilder(
it.correspondingPropertySymbol = tempSymbol
}
val signature = composeSignature(declaration)
val signature = composeSignature(declaration, compatibilityMode)
declarePropertyFakeOverride(declaration, signature)
declaration.getter?.let {
it.correspondingPropertySymbol = declaration.symbol
linkFunctionFakeOverride(it as? IrFakeOverrideFunction ?: error("Unexpected fake override getter: $it"))
linkFunctionFakeOverride(it as? IrFakeOverrideFunction ?: error("Unexpected fake override getter: $it"), compatibilityMode)
}
declaration.setter?.let {
it.correspondingPropertySymbol = declaration.symbol
linkFunctionFakeOverride(it as? IrFakeOverrideFunction ?: error("Unexpected fake override setter: $it"))
linkFunctionFakeOverride(it as? IrFakeOverrideFunction ?: error("Unexpected fake override setter: $it"), compatibilityMode)
}
}
private fun composeSignature(declaration: IrDeclaration) =
fakeOverrideDeclarationTable.signaturer.composeSignatureForDeclaration(declaration)
private fun composeSignature(declaration: IrDeclaration, compatibleMode: Boolean) =
fakeOverrideDeclarationTable.signaturer.composeSignatureForDeclaration(declaration, compatibleMode)
private fun declareFunctionFakeOverride(declaration: IrFakeOverrideFunction, signature: IdSignature) {
val parent = declaration.parentAsClass
@@ -159,16 +168,18 @@ class FakeOverrideBuilder(
}
}
private fun provideFakeOverrides(klass: IrClass) {
buildFakeOverrideChainsForClass(klass)
private fun provideFakeOverrides(klass: IrClass, compatibleMode: CompatibilityMode) {
buildFakeOverrideChainsForClass(klass, compatibleMode)
irOverridingUtil.clear()
haveFakeOverrides.add(klass)
}
fun provideFakeOverrides() {
while (fakeOverrideClassQueue.isNotEmpty()) {
val klass = fakeOverrideClassQueue.removeLast()
provideFakeOverrides(klass)
val entries = fakeOverrideCandidates.entries
while (entries.isNotEmpty()) {
val candidate = entries.last()
entries.remove(candidate)
provideFakeOverrides(candidate.key, candidate.value)
}
}
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
@@ -25,9 +26,10 @@ abstract class BasicIrModuleDeserializer(
moduleDescriptor: ModuleDescriptor,
override val klib: IrLibrary,
override val strategy: DeserializationStrategy,
private val containsErrorCode: Boolean = false,
libraryAbiVersion: KotlinAbiVersion,
private val containsErrorCode: Boolean = false
) :
IrModuleDeserializer(moduleDescriptor) {
IrModuleDeserializer(moduleDescriptor, libraryAbiVersion) {
private val fileToDeserializerMap = mutableMapOf<IrFile, IrFileDeserializer>()
@@ -6,14 +6,19 @@
package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.backend.common.serialization.signature.PublicIdSignatureComputer
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
interface IdSignatureClashTracker {
@@ -43,13 +48,13 @@ abstract class GlobalDeclarationTable(
}
}
open fun computeSignatureByDeclaration(declaration: IrDeclaration): IdSignature {
open fun computeSignatureByDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature {
return table.getOrPut(declaration) {
publicIdSignatureComputer.composePublicIdSignature(declaration).also { clashTracker.commit(declaration, it) }
publicIdSignatureComputer.composePublicIdSignature(declaration, compatibleMode).also { clashTracker.commit(declaration, it) }
}
}
fun isExportedDeclaration(declaration: IrDeclaration): Boolean = with(mangler) { declaration.isExported() }
fun isExportedDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): Boolean = with(mangler) { declaration.isExported(compatibleMode) }
}
open class DeclarationTable(globalTable: GlobalDeclarationTable) {
@@ -62,24 +67,34 @@ open class DeclarationTable(globalTable: GlobalDeclarationTable) {
signaturer.inFile(file?.symbol, block)
}
fun isExportedDeclaration(declaration: IrDeclaration) = globalDeclarationTable.isExportedDeclaration(declaration)
private fun IrDeclaration.isLocalDeclaration(compatibleMode: Boolean): Boolean {
return !isExportedDeclaration(this, compatibleMode)
}
fun isExportedDeclaration(declaration: IrDeclaration, compatibleMode: Boolean) =
globalDeclarationTable.isExportedDeclaration(declaration, compatibleMode)
protected open fun tryComputeBackendSpecificSignature(declaration: IrDeclaration): IdSignature? = null
private fun computeSignatureByDeclaration(declaration: IrDeclaration): IdSignature {
tryComputeBackendSpecificSignature(declaration)?.let { return it }
return if (declaration.isLocalDeclaration()) {
table.getOrPut(declaration) { signaturer.composeFileLocalIdSignature(declaration) }
} else globalDeclarationTable.computeSignatureByDeclaration(declaration)
private fun allocateIndexedSignature(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature {
return table.getOrPut(declaration) { signaturer.composeFileLocalIdSignature(declaration, compatibleMode) }
}
fun privateDeclarationSignature(declaration: IrDeclaration, builder: () -> IdSignature): IdSignature {
assert(declaration.isLocalDeclaration())
private fun computeSignatureByDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature {
tryComputeBackendSpecificSignature(declaration)?.let { return it }
return if (declaration.isLocalDeclaration(compatibleMode)) {
allocateIndexedSignature(declaration, compatibleMode)
} else globalDeclarationTable.computeSignatureByDeclaration(declaration, compatibleMode)
}
fun privateDeclarationSignature(declaration: IrDeclaration, compatibleMode: Boolean, builder: () -> IdSignature): IdSignature {
assert(declaration.isLocalDeclaration(compatibleMode))
return table.getOrPut(declaration) { builder() }
}
fun signatureByDeclaration(declaration: IrDeclaration): IdSignature {
return computeSignatureByDeclaration(declaration)
fun signatureByDeclaration(declaration: IrDeclaration, compatibleMode: Boolean): IdSignature {
return computeSignatureByDeclaration(declaration, compatibleMode)
}
fun assumeDeclarationSignature(declaration: IrDeclaration, signature: IdSignature) {
@@ -140,7 +140,7 @@ class DescriptorByIdSignatureFinder(
// We don't compute id for typealiases and classes.
candidate is ClassDescriptor || candidate is TypeAliasDescriptor
} else {
val candidateHash = with(mangler) { candidate.signatureMangle }
val candidateHash = with(mangler) { candidate.signatureMangle() }
candidateHash == id
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.library.SerializedIrFile
import org.jetbrains.kotlin.library.impl.*
@@ -79,7 +80,7 @@ class CurrentModuleWithICDeserializer(
private val irBuiltIns: IrBuiltIns,
icData: List<SerializedIrFile>,
icReaderFactory: (IrLibrary) -> IrModuleDeserializer) :
IrModuleDeserializer(delegate.moduleDescriptor) {
IrModuleDeserializer(delegate.moduleDescriptor, KotlinAbiVersion.CURRENT) {
private val dirtyDeclarations = mutableMapOf<IdSignature, IrSymbol>()
private val icKlib = ICKotlinLibrary(icData)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrBody
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.*
@@ -32,6 +34,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.CodedInputStream
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.types.Variance
import kotlin.collections.set
import org.jetbrains.kotlin.backend.common.serialization.proto.IrAnonymousInit as ProtoAnonymousInit
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass
import org.jetbrains.kotlin.backend.common.serialization.proto.IrConstructor as ProtoConstructor
@@ -73,6 +76,7 @@ class IrDeclarationDeserializer(
private val skipMutableState: Boolean = false,
additionalStatementOriginIndex: Map<String, IrStatementOrigin> = emptyMap(),
allowErrorStatementOrigins: Boolean = false,
private val compatibilityMode: CompatibilityMode
) {
val bodyDeserializer = IrBodyDeserializer(builtIns, allowErrorNodes, irFactory, fileReader, this, statementOriginIndex + additionalStatementOriginIndex, allowErrorStatementOrigins)
@@ -334,7 +338,7 @@ class IrDeclarationDeserializer(
else -> computeMissingInlineClassRepresentationForCompatibility(this)
}
fakeOverrideBuilder.enqueueClass(this, signature)
fakeOverrideBuilder.enqueueClass(this, signature, compatibilityMode)
}
}
}
@@ -71,9 +71,7 @@ class FileDeserializationState(
val symbolDeserializer =
IrSymbolDeserializer(
linker.symbolTable,
fileReader,
file.symbol,
linker.symbolTable, fileReader, file.symbol,
fileProto.actualList,
::addIdSignature,
linker::handleExpectActualMapping,
@@ -102,6 +100,7 @@ class FileDeserializationState(
symbolDeserializer,
linker.fakeOverrideBuilder.platformSpecificClassFilter,
linker.fakeOverrideBuilder,
compatibilityMode = moduleDeserializer.compatibilityMode
)
val fileDeserializer = IrFileDeserializer(file, fileReader, fileProto, symbolDeserializer, declarationDeserializer)
@@ -120,6 +120,7 @@ open class IrFileSerializer(
val messageLogger: IrMessageLogger,
private val declarationTable: DeclarationTable,
private val expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>,
private val compatibilityMode: CompatibilityMode,
private val bodiesOnlyForInlines: Boolean = false,
private val skipExpects: Boolean = false,
// required for JS IC caches
@@ -312,7 +313,7 @@ open class IrFileSerializer(
}
private fun protoIdSignature(declaration: IrDeclaration): Int {
val idSig = declarationTable.signatureByDeclaration(declaration)
val idSig = declarationTable.signatureByDeclaration(declaration, compatibilityMode.oldSignatures)
return protoIdSignature(idSig)
}
@@ -1470,7 +1471,7 @@ open class IrFileSerializer(
for (declaration in declarations) {
val byteArray = serializeDeclaration(declaration).toByteArray()
val idSig = declarationTable.signatureByDeclaration(declaration)
val idSig = declarationTable.signatureByDeclaration(declaration, compatibleMode = false)
// TODO: keep order similar
// ^ TODO what does that mean?
@@ -1521,8 +1522,8 @@ open class IrFileSerializer(
}
val byteArray = serializeDeclaration(it).toByteArray()
val idSig = declarationTable.signatureByDeclaration(it)
require(idSig === idSig.topLevelSignature()) { "IdSig: $idSig\ntopLevel: ${idSig.topLevelSignature()}" }
val idSig = declarationTable.signatureByDeclaration(it, compatibilityMode.oldSignatures)
require(idSig == idSig.topLevelSignature()) { "IdSig: $idSig\ntopLevel: ${idSig.topLevelSignature()}" }
require(!idSig.isPackageSignature()) { "IsSig: $idSig\nDeclaration: ${it.render()}" }
// TODO: keep order similar
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.library.KotlinAbiVersion
internal fun IrSymbol.kind(): BinarySymbolData.SymbolKind {
return when (this) {
@@ -28,11 +29,35 @@ internal fun IrSymbol.kind(): BinarySymbolData.SymbolKind {
}
}
abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor) {
class CompatibilityMode(val abiVersion: KotlinAbiVersion) {
init {
assert(abiVersion.isCompatible())
}
val oldSignatures: Boolean
get() {
if (abiVersion.minor == LAST_PRIVATE_SIG_ABI_VERSION.minor) {
return abiVersion.patch <= LAST_PRIVATE_SIG_ABI_VERSION.patch
}
return abiVersion.minor < LAST_PRIVATE_SIG_ABI_VERSION.minor
}
companion object {
val LAST_PRIVATE_SIG_ABI_VERSION = KotlinAbiVersion(1, 5, 0)
val WITH_PRIVATE_SIG = CompatibilityMode(LAST_PRIVATE_SIG_ABI_VERSION)
val WITH_COMMON_SIG = CompatibilityMode(KotlinAbiVersion.CURRENT)
val CURRENT = WITH_COMMON_SIG
}
}
abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor, val libraryAbiVersion: KotlinAbiVersion) {
abstract operator fun contains(idSig: IdSignature): Boolean
abstract fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol
open fun referenceSimpleFunctionByLocalSignature(file: IrFile, idSignature: IdSignature) : IrSimpleFunctionSymbol =
open fun referenceSimpleFunctionByLocalSignature(file: IrFile, idSignature: IdSignature): IrSimpleFunctionSymbol =
error("Unsupported operation")
open fun referencePropertyByLocalSignature(file: IrFile, idSignature: IdSignature): IrPropertySymbol =
@@ -53,7 +78,9 @@ abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor) {
open fun init(delegate: IrModuleDeserializer) {}
open fun addModuleReachableTopLevel(idSig: IdSignature) { error("Unsupported Operation (sig: $idSig") }
open fun addModuleReachableTopLevel(idSig: IdSignature) {
error("Unsupported Operation (sig: $idSig")
}
open fun deserializeReachableDeclarations() { error("Unsupported Operation") }
@@ -64,14 +91,16 @@ abstract class IrModuleDeserializer(val moduleDescriptor: ModuleDescriptor) {
open val strategy: DeserializationStrategy = DeserializationStrategy.ONLY_DECLARATION_HEADERS
open val isCurrent = false
val compatibilityMode: CompatibilityMode get() = CompatibilityMode(libraryAbiVersion)
}
// Used to resolve built in symbols like `kotlin.ir.internal.*` or `kotlin.FunctionN`
class IrModuleDeserializerWithBuiltIns(
builtIns: IrBuiltIns,
private val functionFactory: IrAbstractFunctionFactory,
private val delegate: IrModuleDeserializer
) : IrModuleDeserializer(delegate.moduleDescriptor) {
private val delegate: IrModuleDeserializer,
) : IrModuleDeserializer(delegate.moduleDescriptor, delegate.libraryAbiVersion) {
init {
// TODO: figure out how it should work for K/N
@@ -205,7 +234,7 @@ class IrModuleDeserializerWithBuiltIns(
open class CurrentModuleDeserializer(
override val moduleFragment: IrModuleFragment,
override val moduleDependencies: Collection<IrModuleDeserializer>
) : IrModuleDeserializer(moduleFragment.descriptor) {
) : IrModuleDeserializer(moduleFragment.descriptor, KotlinAbiVersion.CURRENT) {
override fun contains(idSig: IdSignature): Boolean = false // TODO:
override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.library.SerializedIrFile
import org.jetbrains.kotlin.library.SerializedIrModule
abstract class IrModuleSerializer<F : IrFileSerializer>(protected val messageLogger: IrMessageLogger) {
abstract class IrModuleSerializer<F : IrFileSerializer>(protected val messageLogger: IrMessageLogger, protected val compatibilityMode: CompatibilityMode) {
abstract fun createSerializerForFile(file: IrFile): F
/**
@@ -22,11 +22,6 @@ import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.library.IrLibrary
import org.jetbrains.kotlin.ir.util.IdSignature
import org.jetbrains.kotlin.ir.util.IrMessageLogger
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -90,7 +85,7 @@ abstract class KotlinIrLinker(
protected abstract fun createModuleDeserializer(
moduleDescriptor: ModuleDescriptor,
klib: IrLibrary?,
klib: KotlinLibrary?,
strategy: DeserializationStrategy,
): IrModuleDeserializer
@@ -11,6 +11,6 @@ import org.jetbrains.kotlin.ir.util.KotlinMangler
abstract class AbstractKotlinMangler<D : Any> : KotlinMangler<D> {
override val String.hashMangle get() = cityHash64()
abstract fun getExportChecker(): KotlinExportChecker<D>
abstract fun getExportChecker(compatibleMode: Boolean): KotlinExportChecker<D>
abstract fun getMangleComputer(mode: MangleMode): KotlinMangleComputer<D>
}
@@ -9,11 +9,11 @@ import org.jetbrains.kotlin.backend.common.serialization.mangle.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.ir.declarations.IrAnonymousInitializer
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.types.KotlinType
abstract class DescriptorBasedKotlinManglerImpl : AbstractKotlinMangler<DeclarationDescriptor>(), KotlinMangler.DescriptorMangler {
private fun withMode(mode: MangleMode, descriptor: DeclarationDescriptor): String =
@@ -21,23 +21,15 @@ abstract class DescriptorBasedKotlinManglerImpl : AbstractKotlinMangler<Declarat
override fun ClassDescriptor.mangleEnumEntryString(): String = withMode(MangleMode.FQNAME, this)
override fun ClassDescriptor.isExportEnumEntry(): Boolean =
getExportChecker().check(this, SpecialDeclarationType.ENUM_ENTRY)
override fun PropertyDescriptor.mangleFieldString(): String = mangleString()
override fun PropertyDescriptor.isExportField(): Boolean = false
override fun DeclarationDescriptor.mangleString(): String = withMode(MangleMode.FULL, this)
override fun PropertyDescriptor.mangleFieldString(): String = error("Fields supposed to be non-exporting")
override fun DeclarationDescriptor.signatureString(): String = withMode(MangleMode.SIGNATURE, this)
override val DeclarationDescriptor.mangleString: String
get() = withMode(MangleMode.FULL, this)
override fun DeclarationDescriptor.fqnString(): String = withMode(MangleMode.FQNAME, this)
override val DeclarationDescriptor.signatureString: String
get() = withMode(MangleMode.SIGNATURE, this)
override val DeclarationDescriptor.fqnString: String
get() = withMode(MangleMode.FQNAME, this)
override fun DeclarationDescriptor.isExported(): Boolean = getExportChecker().check(this, SpecialDeclarationType.REGULAR)
override fun DeclarationDescriptor.isExported(compatibleMode: Boolean): Boolean = getExportChecker(compatibleMode).check(this, SpecialDeclarationType.REGULAR)
}
class Ir2DescriptorManglerAdapter(private val delegate: DescriptorBasedKotlinManglerImpl) : AbstractKotlinMangler<IrDeclaration>(),
@@ -45,31 +37,26 @@ class Ir2DescriptorManglerAdapter(private val delegate: DescriptorBasedKotlinMan
override val manglerName: String
get() = delegate.manglerName
override fun IrDeclaration.isExported(): Boolean {
override fun IrDeclaration.isExported(compatibleMode: Boolean): Boolean {
return delegate.run { descriptor.isExported(compatibleMode) }
}
override fun IrDeclaration.mangleString(): String {
return when (this) {
is IrAnonymousInitializer -> false
is IrEnumEntry -> delegate.run { descriptor.isExportEnumEntry() }
is IrField -> delegate.run { descriptor.isExportField() }
else -> delegate.run { descriptor.isExported() }
is IrEnumEntry -> delegate.run { descriptor.mangleEnumEntryString() }
is IrField -> delegate.run { descriptor.mangleFieldString() }
else -> delegate.run { descriptor.mangleString() }
}
}
override val IrDeclaration.mangleString: String
get() {
return when (this) {
is IrEnumEntry -> delegate.run { descriptor.mangleEnumEntryString() }
is IrField -> delegate.run { descriptor.mangleFieldString() }
else -> delegate.run { descriptor.mangleString }
}
}
override fun IrDeclaration.signatureString(): String = delegate.run { descriptor.signatureString() }
override val IrDeclaration.signatureString: String
get() = delegate.run { descriptor.signatureString }
override fun IrDeclaration.fqnString(): String = delegate.run { descriptor.fqnString() }
override val IrDeclaration.fqnString: String
get() = delegate.run { descriptor.fqnString }
override fun getMangleComputer(mode: MangleMode): KotlinMangleComputer<IrDeclaration> =
error("Should not have been reached")
override fun getExportChecker() = error("Should not have been reached")
override fun getMangleComputer(mode: MangleMode): KotlinMangleComputer<IrDeclaration> = error("Should not have been reached")
override fun getExportChecker(compatibleMode: Boolean): KotlinExportChecker<IrDeclaration> {
error("Should not be called")
}
}
@@ -12,14 +12,13 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.util.KotlinMangler
abstract class IrBasedKotlinManglerImpl : AbstractKotlinMangler<IrDeclaration>(), KotlinMangler.IrMangler {
override val IrDeclaration.mangleString: String
get() = getMangleComputer(MangleMode.FULL).computeMangle(this)
override val IrDeclaration.signatureString: String
get() = getMangleComputer(MangleMode.SIGNATURE).computeMangle(this)
override fun IrDeclaration.mangleString(): String = getMangleComputer(MangleMode.FULL).computeMangle(this)
override val IrDeclaration.fqnString: String
get() = getMangleComputer(MangleMode.FQNAME).computeMangle(this)
override fun IrDeclaration.signatureString(): String = getMangleComputer(MangleMode.SIGNATURE).computeMangle(this)
override fun IrDeclaration.isExported(): Boolean = getExportChecker().check(this, SpecialDeclarationType.REGULAR)
override fun IrDeclaration.fqnString(): String = getMangleComputer(MangleMode.FQNAME).computeMangle(this)
override fun IrDeclaration.isExported(compatibleMode: Boolean): Boolean =
getExportChecker(compatibleMode).check(this, SpecialDeclarationType.REGULAR)
}
@@ -23,15 +23,23 @@ import org.jetbrains.kotlin.name.SpecialNames
abstract class IrExportCheckerVisitor(private val compatibleMode: Boolean) : KotlinExportChecker<IrDeclaration> {
private val compatibleChecker = CompatibleChecker()
private val newChecker = NewChecker()
private val checker = Checker()
/**
* @return true if [declaration] is exportable from klib point of view.
* Depending on [compatibleMode] option the same declaration could have FileLocal or Common signature.
*/
override fun check(declaration: IrDeclaration, type: SpecialDeclarationType): Boolean {
return declaration.accept(if (compatibleMode) compatibleChecker else newChecker, null)
return declaration.accept(if (compatibleMode) compatibleChecker else checker, null)
}
abstract override fun IrDeclaration.isPlatformSpecificExported(): Boolean
private class NewChecker : IrElementVisitor<Boolean, Nothing?> {
/**
* Corresponding to export policy of klib ABI >= 1.6.0.
* In that case any non-local declaration (including type parameter and field) is exportable and could be navigated between modules
*/
private class Checker : IrElementVisitor<Boolean, Nothing?> {
override fun visitElement(element: IrElement, data: Nothing?): Boolean {
error("Should bot reach here ${element.render()}")
}
@@ -68,6 +76,14 @@ abstract class IrExportCheckerVisitor(private val compatibleMode: Boolean) : Kot
override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): Boolean = false
}
/**
* Was using for klib ABI version <= 1.5.0. In that case declaration which has itself or in their hierarchy private or local parent
* is considered non-exportable.
*
* Also type parameters and fields are not exportable.
*
* Is used to link libraries with ABI level <= 1.5.0
*/
private inner class CompatibleChecker : IrElementVisitor<Boolean, Nothing?> {
private fun IrDeclaration.isExported(annotations: List<IrConstructorCall>, visibility: DescriptorVisibility?): Boolean {
val speciallyExported = annotations.hasAnnotation(publishedApiAnnotation) || isPlatformSpecificExported()