[Native] Move KonanPartialModuleDeserializer to a separate file
This commit is contained in:
+2
-2
@@ -12,8 +12,8 @@ import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
||||
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||
import org.jetbrains.kotlin.backend.konan.isExternalObjCClass
|
||||
import org.jetbrains.kotlin.backend.konan.isFunctionInterfaceFile
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanPartialModuleDeserializer
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.library.impl.javaFile
|
||||
|
||||
internal class CacheInfoBuilder(
|
||||
private val generationState: NativeGenerationState,
|
||||
private val moduleDeserializer: KonanIrLinker.KonanPartialModuleDeserializer,
|
||||
private val moduleDeserializer: KonanPartialModuleDeserializer,
|
||||
private val irModule: IrModuleFragment
|
||||
) {
|
||||
fun build() {
|
||||
|
||||
-486
@@ -17,9 +17,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.linkage.issues.UserVisibleIrModulesSupport
|
||||
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
|
||||
import org.jetbrains.kotlin.backend.common.linkage.partial.PartialLinkageSupportForLinker
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder
|
||||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter
|
||||
import org.jetbrains.kotlin.backend.common.serialization.*
|
||||
@@ -27,7 +25,6 @@ import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAnd
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.FunctionFlags
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
|
||||
@@ -44,10 +41,8 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -60,7 +55,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import sun.misc.Unsafe
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunction as ProtoFunction
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty
|
||||
|
||||
@@ -553,486 +547,6 @@ internal class KonanIrLinker(
|
||||
else -> error("Unknown package fragment kind ${packageFragment::class.java}")
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class KonanPartialModuleDeserializer(
|
||||
konanIrLinker: KonanIrLinker,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
override val klib: KotlinLibrary,
|
||||
private val stubGenerator: DeclarationStubGenerator,
|
||||
private val cachedLibraries: CachedLibraries,
|
||||
private val inlineFunctionFiles: MutableMap<IrExternalPackageFragment, IrFile>,
|
||||
strategyResolver: (String) -> DeserializationStrategy,
|
||||
private val cacheDeserializationStrategy: CacheDeserializationStrategy,
|
||||
containsErrorCode: Boolean = false
|
||||
) : BasicIrModuleDeserializer(konanIrLinker, moduleDescriptor, klib,
|
||||
{ fileName ->
|
||||
if (cacheDeserializationStrategy.contains(fileName))
|
||||
strategyResolver(fileName)
|
||||
else DeserializationStrategy.ON_DEMAND
|
||||
}, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT, containsErrorCode
|
||||
) {
|
||||
private val descriptorSignatures = mutableMapOf<DeclarationDescriptor, IdSignature>()
|
||||
|
||||
val files by lazy { fileDeserializationStates.map { it.file } }
|
||||
|
||||
private val idSignatureToFile by lazy {
|
||||
buildMap {
|
||||
fileDeserializationStates.forEach { fileDeserializationState ->
|
||||
fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys.forEach { idSig ->
|
||||
put(idSig, fileDeserializationState.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val fileReferenceToFileDeserializationState by lazy {
|
||||
fileDeserializationStates.associateBy { SerializedFileReference(it.file.packageFqName.asString(), it.file.path) }
|
||||
}
|
||||
|
||||
private val SerializedFileReference.deserializationState
|
||||
get() = fileReferenceToFileDeserializationState[this] ?: error("Unknown file $this")
|
||||
|
||||
private tailrec fun IdSignature.fileSignature(): IdSignature.FileSignature? = when (this) {
|
||||
is IdSignature.FileSignature -> this
|
||||
is IdSignature.CompositeSignature -> this.container.fileSignature()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val IrClass.firstNonClassParent: IrDeclarationParent
|
||||
get() {
|
||||
var parent = parent
|
||||
while (parent is IrClass) parent = parent.parent
|
||||
return parent
|
||||
}
|
||||
|
||||
fun getFileNameOf(declaration: IrDeclaration): String {
|
||||
fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor]
|
||||
|
||||
val idSig = declaration.getSignature()
|
||||
?: (declaration.parent as? IrDeclaration)?.getSignature()
|
||||
?: ((declaration as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration)?.getSignature()
|
||||
?: error("Can't find signature of ${declaration.render()}")
|
||||
val topLevelIdSig = idSig.topLevelSignature()
|
||||
return topLevelIdSig.fileSignature()?.fileName
|
||||
?: idSignatureToFile[topLevelIdSig]?.path
|
||||
?: error("No file for $idSig")
|
||||
}
|
||||
|
||||
fun getKlibFileIndexOf(irFile: IrFile) = fileDeserializationStates.first { it.file == irFile }.fileIndex
|
||||
|
||||
fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference {
|
||||
val signature = irFunction.symbol.signature
|
||||
?: error("No signature for ${irFunction.render()}")
|
||||
val topLevelSignature = signature.topLevelSignature()
|
||||
val fileDeserializationState = moduleReversedFileIndex[topLevelSignature]
|
||||
?: error("No file deserializer for ${topLevelSignature.render()}")
|
||||
val declarationIndex = fileDeserializationState.fileDeserializer.reversedSignatureIndex[topLevelSignature]
|
||||
?: error("No declaration for ${topLevelSignature.render()}")
|
||||
val fileReader = fileDeserializationState.fileReader
|
||||
val symbolDeserializer = fileDeserializationState.fileDeserializer.symbolDeserializer
|
||||
val protoDeclaration = fileReader.declaration(declarationIndex)
|
||||
|
||||
val outerClasses = (irFunction.parent as? IrClass)?.getOuterClasses(takeOnlyInner = false) ?: emptyList()
|
||||
require((outerClasses.getOrNull(0)?.parent ?: irFunction.parent) is IrFile) {
|
||||
"Local inline functions are not supported: ${irFunction.render()}"
|
||||
}
|
||||
|
||||
val typeParameterSigs = mutableListOf<Int>()
|
||||
val outerReceiverSigs = mutableListOf<Int>()
|
||||
val protoFunction = if (outerClasses.isEmpty()) {
|
||||
val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner
|
||||
if (irProperty == null)
|
||||
protoDeclaration.irFunction
|
||||
else protoDeclaration.irProperty.findAccessor(irProperty, irFunction)
|
||||
} else {
|
||||
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
|
||||
var protoClass = protoDeclaration.irClass
|
||||
outerClasses.indices.forEach { classIndex ->
|
||||
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
|
||||
(0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) {
|
||||
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
|
||||
}
|
||||
}
|
||||
if (classIndex < outerClasses.size - 1) {
|
||||
if (classIndex >= firstNotInnerClassIndex)
|
||||
outerReceiverSigs.add(BinarySymbolData.decode(protoClass.thisReceiver.base.symbol).signatureId)
|
||||
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
|
||||
}
|
||||
}
|
||||
protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer)
|
||||
}
|
||||
|
||||
val functionSignature = BinarySymbolData.decode(protoFunction.base.base.symbol).signatureId
|
||||
(0 until protoFunction.base.typeParameterCount).mapTo(typeParameterSigs) {
|
||||
BinarySymbolData.decode(protoFunction.base.getTypeParameter(it).base.symbol).signatureId
|
||||
}
|
||||
val defaultValues = mutableListOf<Int>()
|
||||
val valueParameterSigs = (0 until protoFunction.base.valueParameterCount).map {
|
||||
val valueParameter = protoFunction.base.getValueParameter(it)
|
||||
defaultValues.add(if (valueParameter.hasDefaultValue()) valueParameter.defaultValue else INVALID_INDEX)
|
||||
BinarySymbolData.decode(valueParameter.base.symbol).signatureId
|
||||
}
|
||||
val extensionReceiverSig = irFunction.extensionReceiverParameter?.let {
|
||||
BinarySymbolData.decode(protoFunction.base.extensionReceiver.base.symbol).signatureId
|
||||
} ?: INVALID_INDEX
|
||||
val dispatchReceiverSig = irFunction.dispatchReceiverParameter?.let {
|
||||
BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId
|
||||
} ?: INVALID_INDEX
|
||||
|
||||
return SerializedInlineFunctionReference(SerializedFileReference(fileDeserializationState.file),
|
||||
functionSignature, protoFunction.base.body, irFunction.startOffset, irFunction.endOffset,
|
||||
extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(),
|
||||
valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray())
|
||||
}
|
||||
|
||||
fun buildClassFields(irClass: IrClass, fields: List<ClassLayoutBuilder.FieldInfo>): SerializedClassFields {
|
||||
val signature = irClass.symbol.signature
|
||||
?: error("No signature for ${irClass.render()}")
|
||||
val topLevelSignature = signature.topLevelSignature()
|
||||
val fileDeserializationState = moduleReversedFileIndex[topLevelSignature]
|
||||
?: error("No file deserializer for ${topLevelSignature.render()}")
|
||||
val fileDeserializer = fileDeserializationState.fileDeserializer
|
||||
val declarationIndex = fileDeserializer.reversedSignatureIndex[topLevelSignature]
|
||||
?: error("No declaration for ${topLevelSignature.render()}")
|
||||
val fileReader = fileDeserializationState.fileReader
|
||||
val symbolDeserializer = fileDeserializer.symbolDeserializer
|
||||
val protoDeclaration = fileReader.declaration(declarationIndex)
|
||||
|
||||
val outerClasses = irClass.getOuterClasses(takeOnlyInner = false)
|
||||
require(outerClasses.first().parent is IrFile) { "Local classes are not supported: ${irClass.render()}" }
|
||||
|
||||
val typeParameterSigs = mutableListOf<Int>()
|
||||
var protoClass = protoDeclaration.irClass
|
||||
val protoClasses = mutableListOf(protoClass)
|
||||
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
|
||||
for (classIndex in outerClasses.indices) {
|
||||
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
|
||||
(0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) {
|
||||
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
|
||||
}
|
||||
}
|
||||
if (classIndex < outerClasses.size - 1) {
|
||||
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
|
||||
protoClasses += protoClass
|
||||
}
|
||||
}
|
||||
|
||||
val protoFields = mutableListOf<ProtoField>()
|
||||
for (i in 0 until protoClass.declarationCount) {
|
||||
val declaration = protoClass.getDeclaration(i)
|
||||
if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_FIELD)
|
||||
protoFields.add(declaration.irField)
|
||||
else if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_PROPERTY) {
|
||||
val protoProperty = declaration.irProperty
|
||||
if (protoProperty.hasBackingField())
|
||||
protoFields.add(protoProperty.backingField)
|
||||
}
|
||||
}
|
||||
val protoFieldsMap = mutableMapOf<String, ProtoField>()
|
||||
protoFields.forEach {
|
||||
val nameAndType = BinaryNameAndType.decode(it.nameType)
|
||||
val name = fileReader.string(nameAndType.nameIndex)
|
||||
val prev = protoFieldsMap[name]
|
||||
if (prev != null)
|
||||
error("Class ${irClass.render()} has two fields with same name '$name'")
|
||||
protoFieldsMap[name] = it
|
||||
}
|
||||
|
||||
val outerThisIndex = fields.indexOfFirst { it.irField?.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS }
|
||||
val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures
|
||||
return SerializedClassFields(
|
||||
SerializedFileReference(fileDeserializationState.file),
|
||||
BinarySymbolData.decode(protoClass.base.symbol).signatureId,
|
||||
typeParameterSigs.toIntArray(),
|
||||
outerThisIndex,
|
||||
Array(fields.size) {
|
||||
val field = fields[it]
|
||||
val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}")
|
||||
if (it == outerThisIndex) {
|
||||
require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" }
|
||||
require(protoClasses.size > 1) { "An inner class must have at least one outer class" }
|
||||
val outerProtoClass = protoClasses[protoClasses.size - 2]
|
||||
val nameAndType = BinaryNameAndType.decode(outerProtoClass.thisReceiver.nameType)
|
||||
|
||||
SerializedClassFieldInfo(name = INVALID_INDEX, binaryType = INVALID_INDEX, nameAndType.typeIndex, flags = 0, field.alignment)
|
||||
} else {
|
||||
val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}")
|
||||
val nameAndType = BinaryNameAndType.decode(protoField.nameType)
|
||||
var flags = 0
|
||||
if (field.isConst)
|
||||
flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST
|
||||
val classifier = irField.type.classifierOrNull
|
||||
?: error("Fields of type ${irField.type.render()} are not supported")
|
||||
val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull()
|
||||
|
||||
SerializedClassFieldInfo(
|
||||
nameAndType.nameIndex,
|
||||
primitiveBinaryType?.ordinal ?: INVALID_INDEX,
|
||||
if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false)
|
||||
INVALID_INDEX
|
||||
else nameAndType.typeIndex,
|
||||
flags,
|
||||
field.alignment
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun buildEagerInitializedFile(irFile: IrFile) =
|
||||
SerializedEagerInitializedFile(SerializedFileReference(irFile))
|
||||
|
||||
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl(
|
||||
moduleDescriptor, KonanManglerDesc,
|
||||
DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY
|
||||
)
|
||||
|
||||
private val deserializedSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
|
||||
// Need to notify the deserializing machinery that some symbols have already been created by stub generator
|
||||
// (like type parameters and receiver parameters) and there's no need to create new symbols for them.
|
||||
private fun referenceIrSymbol(symbolDeserializer: IrSymbolDeserializer, sigIndex: Int, symbol: IrSymbol) {
|
||||
val idSig = symbolDeserializer.deserializeIdSignature(sigIndex)
|
||||
symbolDeserializer.referenceLocalIrSymbol(symbol, idSig)
|
||||
if (idSig.isPubliclyVisible) {
|
||||
deserializedSymbols[idSig]?.let {
|
||||
require(it == symbol) { "Two different symbols for the same signature ${idSig.render()}" }
|
||||
}
|
||||
// Sometimes the linker would want to create a new symbol, so save actual symbol here
|
||||
// and use it in [contains] and [tryDeserializeSymbol].
|
||||
deserializedSymbols[idSig] = symbol
|
||||
}
|
||||
}
|
||||
|
||||
override fun contains(idSig: IdSignature): Boolean =
|
||||
super.contains(idSig) || deserializedSymbols.containsKey(idSig) ||
|
||||
cacheDeserializationStrategy != CacheDeserializationStrategy.WholeModule
|
||||
&& idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null
|
||||
|
||||
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||
super.tryDeserializeIrSymbol(idSig, symbolKind)?.let { return it }
|
||||
|
||||
deserializedSymbols[idSig]?.let { return it }
|
||||
|
||||
val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null
|
||||
|
||||
descriptorSignatures[descriptor] = idSig
|
||||
|
||||
return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol
|
||||
}
|
||||
|
||||
private val inlineFunctionReferences by lazy {
|
||||
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||
cache.serializedInlineFunctionBodies.associateBy {
|
||||
it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature)
|
||||
}
|
||||
}
|
||||
|
||||
private val deserializedInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||
|
||||
fun deserializeInlineFunction(function: IrFunction): DeserializedInlineFunction {
|
||||
deserializedInlineFunctions[function]?.let { return DeserializedInlineFunction(firstAccess = false, it) }
|
||||
val result = deserializeInlineFunctionInternal(function)
|
||||
deserializedInlineFunctions[function] = result
|
||||
return DeserializedInlineFunction(firstAccess = true, result)
|
||||
}
|
||||
|
||||
private fun deserializeInlineFunctionInternal(function: IrFunction): InlineFunctionOriginInfo {
|
||||
val packageFragment = function.getPackageFragment()
|
||||
if (function.parents.any { (it as? IrFunction)?.isInline == true }) {
|
||||
// Already deserialized by the top-most inline function.
|
||||
return InlineFunctionOriginInfo(
|
||||
function,
|
||||
packageFragment as? IrFile
|
||||
?: inlineFunctionFiles[packageFragment as IrExternalPackageFragment]
|
||||
?: error("${function.render()} should've been deserialized along with its parent"),
|
||||
function.startOffset, function.endOffset
|
||||
)
|
||||
}
|
||||
|
||||
val signature = function.symbol.signature
|
||||
?: descriptorSignatures[function.descriptor]
|
||||
?: error("No signature for ${function.render()}")
|
||||
val inlineFunctionReference = inlineFunctionReferences[signature]
|
||||
?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}")
|
||||
val fileDeserializationState = inlineFunctionReference.file.deserializationState
|
||||
val declarationDeserializer = fileDeserializationState.declarationDeserializer
|
||||
|
||||
if (packageFragment is IrExternalPackageFragment) {
|
||||
val symbolDeserializer = declarationDeserializer.symbolDeserializer
|
||||
|
||||
inlineFunctionFiles[packageFragment]?.let {
|
||||
require(it == fileDeserializationState.file) {
|
||||
"Different files ${it.fileEntry.name} and ${fileDeserializationState.file.fileEntry.name} have the same $packageFragment"
|
||||
}
|
||||
}
|
||||
inlineFunctionFiles[packageFragment] = fileDeserializationState.file
|
||||
|
||||
val outerClasses = (function.parent as? IrClass)?.getOuterClasses(takeOnlyInner = true) ?: emptyList()
|
||||
require((outerClasses.getOrNull(0)?.firstNonClassParent ?: function.parent) is IrPackageFragment) {
|
||||
"Local inline functions are not supported: ${function.render()}"
|
||||
}
|
||||
|
||||
var endToEndTypeParameterIndex = 0
|
||||
outerClasses.forEach { outerClass ->
|
||||
outerClass.typeParameters.forEach { parameter ->
|
||||
val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
}
|
||||
function.typeParameters.forEach { parameter ->
|
||||
val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
function.valueParameters.forEachIndexed { index, parameter ->
|
||||
val sigIndex = inlineFunctionReference.valueParameterSigs[index]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
function.extensionReceiverParameter?.let { parameter ->
|
||||
val sigIndex = inlineFunctionReference.extensionReceiverSig
|
||||
require(sigIndex != INVALID_INDEX) { "Expected a valid sig reference to the extension receiver for ${function.render()}" }
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
function.dispatchReceiverParameter?.let { parameter ->
|
||||
val sigIndex = inlineFunctionReference.dispatchReceiverSig
|
||||
require(sigIndex != INVALID_INDEX) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" }
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
for (index in 0 until outerClasses.size - 1) {
|
||||
val sigIndex = inlineFunctionReference.outerReceiverSigs[index]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, outerClasses[index].thisReceiver!!.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
with(declarationDeserializer) {
|
||||
function.withDeserializeBodies {
|
||||
body = (deserializeStatementBody(inlineFunctionReference.body) as IrBody)
|
||||
valueParameters.forEachIndexed { index, parameter ->
|
||||
val defaultValueIndex = inlineFunctionReference.defaultValues[index]
|
||||
if (defaultValueIndex != INVALID_INDEX)
|
||||
parameter.defaultValue = deserializeExpressionBody(defaultValueIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packageFragment is IrFile)
|
||||
linker.deserializeAllReachableTopLevels()
|
||||
|
||||
linker.partialLinkageSupport.exploreClassifiers(linker.fakeOverrideBuilder)
|
||||
linker.partialLinkageSupport.exploreClassifiersInInlineLazyIrFunction(function)
|
||||
|
||||
linker.fakeOverrideBuilder.provideFakeOverrides()
|
||||
|
||||
linker.partialLinkageSupport.generateStubsAndPatchUsages(linker.symbolTable, function)
|
||||
|
||||
linker.checkNoUnboundSymbols(
|
||||
linker.symbolTable,
|
||||
"after deserializing lazy-IR function ${function.name.asString()} in inline functions lowering"
|
||||
)
|
||||
|
||||
return InlineFunctionOriginInfo(function, fileDeserializationState.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset)
|
||||
}
|
||||
|
||||
private val classesFields by lazy {
|
||||
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||
cache.serializedClassFields.associateBy {
|
||||
it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature)
|
||||
}
|
||||
}
|
||||
|
||||
private val lock = Any()
|
||||
|
||||
fun deserializeClassFields(irClass: IrClass, outerThisFieldInfo: ClassLayoutBuilder.FieldInfo?): List<ClassLayoutBuilder.FieldInfo> = synchronized(lock) {
|
||||
val signature = irClass.symbol.signature
|
||||
?: error("No signature for ${irClass.render()}")
|
||||
val serializedClassFields = classesFields[signature]
|
||||
?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}")
|
||||
val fileDeserializationState = serializedClassFields.file.deserializationState
|
||||
val declarationDeserializer = fileDeserializationState.declarationDeserializer
|
||||
val symbolDeserializer = declarationDeserializer.symbolDeserializer
|
||||
|
||||
if (irClass.getPackageFragment() is IrExternalPackageFragment) {
|
||||
val outerClasses = irClass.getOuterClasses(takeOnlyInner = true)
|
||||
require(outerClasses.first().firstNonClassParent is IrExternalPackageFragment) {
|
||||
"Local classes are not supported: ${irClass.render()}"
|
||||
}
|
||||
|
||||
var endToEndTypeParameterIndex = 0
|
||||
outerClasses.forEach { outerClass ->
|
||||
outerClass.typeParameters.forEach { parameter ->
|
||||
val sigIndex = serializedClassFields.typeParameterSigs[endToEndTypeParameterIndex++]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
}
|
||||
require(endToEndTypeParameterIndex == serializedClassFields.typeParameterSigs.size) {
|
||||
"Not all type parameters have been referenced"
|
||||
}
|
||||
}
|
||||
|
||||
fun getByClassId(classId: ClassId): IrClassSymbol {
|
||||
val classIdSig = getPublicSignature(classId.packageFqName, classId.relativeClassName.asString())
|
||||
return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol
|
||||
}
|
||||
|
||||
return serializedClassFields.fields.mapIndexed { index, field ->
|
||||
val builtIns = linker.builtIns
|
||||
if (index == serializedClassFields.outerThisIndex) {
|
||||
require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" }
|
||||
require(outerThisFieldInfo != null) { "For an inner class ${irClass.render()} there should be <outer this> field" }
|
||||
outerThisFieldInfo.also {
|
||||
require(it.alignment == field.alignment) { "Mismatched align information for outer this"}
|
||||
}
|
||||
} else {
|
||||
val name = fileDeserializationState.fileReader.string(field.name)
|
||||
val type = when {
|
||||
field.type != INVALID_INDEX -> declarationDeserializer.deserializeIrType(field.type)
|
||||
field.binaryType == INVALID_INDEX -> builtIns.anyNType
|
||||
else -> when (PrimitiveBinaryType.values().getOrNull(field.binaryType)) {
|
||||
PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType
|
||||
PrimitiveBinaryType.BYTE -> builtIns.byteType
|
||||
PrimitiveBinaryType.SHORT -> builtIns.shortType
|
||||
PrimitiveBinaryType.INT -> builtIns.intType
|
||||
PrimitiveBinaryType.LONG -> builtIns.longType
|
||||
PrimitiveBinaryType.FLOAT -> builtIns.floatType
|
||||
PrimitiveBinaryType.DOUBLE -> builtIns.doubleType
|
||||
PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType
|
||||
PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType
|
||||
else -> error("Bad binary type of field $name of ${irClass.render()}")
|
||||
}
|
||||
}
|
||||
ClassLayoutBuilder.FieldInfo(
|
||||
name, type,
|
||||
isConst = (field.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0,
|
||||
irFieldSymbol = IrFieldSymbolImpl(),
|
||||
alignment = field.alignment,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.getOuterClasses(takeOnlyInner: Boolean): List<IrClass> {
|
||||
var outerClass = this
|
||||
val outerClasses = mutableListOf(outerClass)
|
||||
while (outerClass.isInner || !takeOnlyInner) {
|
||||
outerClass = outerClass.parent as? IrClass ?: break
|
||||
outerClasses.add(outerClass)
|
||||
}
|
||||
outerClasses.reverse()
|
||||
return outerClasses
|
||||
}
|
||||
|
||||
val eagerInitializedFiles by lazy {
|
||||
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||
cache.serializedEagerInitializedFiles
|
||||
.map { it.file.deserializationState.file }
|
||||
.distinct()
|
||||
}
|
||||
|
||||
val sortedFileIds by lazy {
|
||||
fileDeserializationStates
|
||||
.sortedBy { it.file.fileEntry.name }
|
||||
.map { CacheSupport.cacheFileId(it.file.packageFqName.asString(), it.file.fileEntry.name) }
|
||||
}
|
||||
}
|
||||
|
||||
private inner class KonanInteropModuleDeserializer(
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
override val klib: KotlinLibrary,
|
||||
|
||||
+528
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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.konan.serialization
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.linkage.issues.checkNoUnboundSymbols
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.backend.common.serialization.*
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAndType
|
||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.InlineFunctionOriginInfo
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
import org.jetbrains.kotlin.ir.types.getPublicSignature
|
||||
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||
import org.jetbrains.kotlin.ir.util.IdSignature
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
internal class KonanPartialModuleDeserializer(
|
||||
konanIrLinker: KonanIrLinker,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
override val klib: KotlinLibrary,
|
||||
private val stubGenerator: DeclarationStubGenerator,
|
||||
private val cachedLibraries: CachedLibraries,
|
||||
private val inlineFunctionFiles: MutableMap<IrExternalPackageFragment, IrFile>,
|
||||
strategyResolver: (String) -> DeserializationStrategy,
|
||||
private val cacheDeserializationStrategy: CacheDeserializationStrategy,
|
||||
containsErrorCode: Boolean = false
|
||||
) : BasicIrModuleDeserializer(konanIrLinker, moduleDescriptor, klib,
|
||||
{ fileName ->
|
||||
if (cacheDeserializationStrategy.contains(fileName))
|
||||
strategyResolver(fileName)
|
||||
else DeserializationStrategy.ON_DEMAND
|
||||
}, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT, containsErrorCode
|
||||
) {
|
||||
private val descriptorSignatures = mutableMapOf<DeclarationDescriptor, IdSignature>()
|
||||
|
||||
val files by lazy { fileDeserializationStates.map { it.file } }
|
||||
|
||||
private val idSignatureToFile by lazy {
|
||||
buildMap {
|
||||
fileDeserializationStates.forEach { fileDeserializationState ->
|
||||
fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys.forEach { idSig ->
|
||||
put(idSig, fileDeserializationState.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val fileReferenceToFileDeserializationState by lazy {
|
||||
fileDeserializationStates.associateBy { SerializedFileReference(it.file.packageFqName.asString(), it.file.path) }
|
||||
}
|
||||
|
||||
private val SerializedFileReference.deserializationState
|
||||
get() = fileReferenceToFileDeserializationState[this] ?: error("Unknown file $this")
|
||||
|
||||
private tailrec fun IdSignature.fileSignature(): IdSignature.FileSignature? = when (this) {
|
||||
is IdSignature.FileSignature -> this
|
||||
is IdSignature.CompositeSignature -> this.container.fileSignature()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val IrClass.firstNonClassParent: IrDeclarationParent
|
||||
get() {
|
||||
var parent = parent
|
||||
while (parent is IrClass) parent = parent.parent
|
||||
return parent
|
||||
}
|
||||
|
||||
fun getFileNameOf(declaration: IrDeclaration): String {
|
||||
fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor]
|
||||
|
||||
val idSig = declaration.getSignature()
|
||||
?: (declaration.parent as? IrDeclaration)?.getSignature()
|
||||
?: ((declaration as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration)?.getSignature()
|
||||
?: error("Can't find signature of ${declaration.render()}")
|
||||
val topLevelIdSig = idSig.topLevelSignature()
|
||||
return topLevelIdSig.fileSignature()?.fileName
|
||||
?: idSignatureToFile[topLevelIdSig]?.path
|
||||
?: error("No file for $idSig")
|
||||
}
|
||||
|
||||
fun getKlibFileIndexOf(irFile: IrFile) = fileDeserializationStates.first { it.file == irFile }.fileIndex
|
||||
|
||||
fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference {
|
||||
val signature = irFunction.symbol.signature
|
||||
?: error("No signature for ${irFunction.render()}")
|
||||
val topLevelSignature = signature.topLevelSignature()
|
||||
val fileDeserializationState = moduleReversedFileIndex[topLevelSignature]
|
||||
?: error("No file deserializer for ${topLevelSignature.render()}")
|
||||
val declarationIndex = fileDeserializationState.fileDeserializer.reversedSignatureIndex[topLevelSignature]
|
||||
?: error("No declaration for ${topLevelSignature.render()}")
|
||||
val fileReader = fileDeserializationState.fileReader
|
||||
val symbolDeserializer = fileDeserializationState.fileDeserializer.symbolDeserializer
|
||||
val protoDeclaration = fileReader.declaration(declarationIndex)
|
||||
|
||||
val outerClasses = (irFunction.parent as? IrClass)?.getOuterClasses(takeOnlyInner = false) ?: emptyList()
|
||||
require((outerClasses.getOrNull(0)?.parent ?: irFunction.parent) is IrFile) {
|
||||
"Local inline functions are not supported: ${irFunction.render()}"
|
||||
}
|
||||
|
||||
val typeParameterSigs = mutableListOf<Int>()
|
||||
val outerReceiverSigs = mutableListOf<Int>()
|
||||
val protoFunction = if (outerClasses.isEmpty()) {
|
||||
val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner
|
||||
if (irProperty == null)
|
||||
protoDeclaration.irFunction
|
||||
else protoDeclaration.irProperty.findAccessor(irProperty, irFunction)
|
||||
} else {
|
||||
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
|
||||
var protoClass = protoDeclaration.irClass
|
||||
outerClasses.indices.forEach { classIndex ->
|
||||
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
|
||||
(0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) {
|
||||
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
|
||||
}
|
||||
}
|
||||
if (classIndex < outerClasses.size - 1) {
|
||||
if (classIndex >= firstNotInnerClassIndex)
|
||||
outerReceiverSigs.add(BinarySymbolData.decode(protoClass.thisReceiver.base.symbol).signatureId)
|
||||
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
|
||||
}
|
||||
}
|
||||
protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer)
|
||||
}
|
||||
|
||||
val functionSignature = BinarySymbolData.decode(protoFunction.base.base.symbol).signatureId
|
||||
(0 until protoFunction.base.typeParameterCount).mapTo(typeParameterSigs) {
|
||||
BinarySymbolData.decode(protoFunction.base.getTypeParameter(it).base.symbol).signatureId
|
||||
}
|
||||
val defaultValues = mutableListOf<Int>()
|
||||
val valueParameterSigs = (0 until protoFunction.base.valueParameterCount).map {
|
||||
val valueParameter = protoFunction.base.getValueParameter(it)
|
||||
defaultValues.add(if (valueParameter.hasDefaultValue()) valueParameter.defaultValue else KonanIrLinker.INVALID_INDEX)
|
||||
BinarySymbolData.decode(valueParameter.base.symbol).signatureId
|
||||
}
|
||||
val extensionReceiverSig = irFunction.extensionReceiverParameter?.let {
|
||||
BinarySymbolData.decode(protoFunction.base.extensionReceiver.base.symbol).signatureId
|
||||
} ?: KonanIrLinker.INVALID_INDEX
|
||||
val dispatchReceiverSig = irFunction.dispatchReceiverParameter?.let {
|
||||
BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId
|
||||
} ?: KonanIrLinker.INVALID_INDEX
|
||||
|
||||
return SerializedInlineFunctionReference(
|
||||
SerializedFileReference(fileDeserializationState.file),
|
||||
functionSignature, protoFunction.base.body, irFunction.startOffset, irFunction.endOffset,
|
||||
extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(),
|
||||
valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray()
|
||||
)
|
||||
}
|
||||
|
||||
fun buildClassFields(irClass: IrClass, fields: List<ClassLayoutBuilder.FieldInfo>): SerializedClassFields {
|
||||
val signature = irClass.symbol.signature
|
||||
?: error("No signature for ${irClass.render()}")
|
||||
val topLevelSignature = signature.topLevelSignature()
|
||||
val fileDeserializationState = moduleReversedFileIndex[topLevelSignature]
|
||||
?: error("No file deserializer for ${topLevelSignature.render()}")
|
||||
val fileDeserializer = fileDeserializationState.fileDeserializer
|
||||
val declarationIndex = fileDeserializer.reversedSignatureIndex[topLevelSignature]
|
||||
?: error("No declaration for ${topLevelSignature.render()}")
|
||||
val fileReader = fileDeserializationState.fileReader
|
||||
val symbolDeserializer = fileDeserializer.symbolDeserializer
|
||||
val protoDeclaration = fileReader.declaration(declarationIndex)
|
||||
|
||||
val outerClasses = irClass.getOuterClasses(takeOnlyInner = false)
|
||||
require(outerClasses.first().parent is IrFile) { "Local classes are not supported: ${irClass.render()}" }
|
||||
|
||||
val typeParameterSigs = mutableListOf<Int>()
|
||||
var protoClass = protoDeclaration.irClass
|
||||
val protoClasses = mutableListOf(protoClass)
|
||||
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
|
||||
for (classIndex in outerClasses.indices) {
|
||||
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
|
||||
(0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) {
|
||||
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
|
||||
}
|
||||
}
|
||||
if (classIndex < outerClasses.size - 1) {
|
||||
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
|
||||
protoClasses += protoClass
|
||||
}
|
||||
}
|
||||
|
||||
val protoFields = mutableListOf<ProtoField>()
|
||||
for (i in 0 until protoClass.declarationCount) {
|
||||
val declaration = protoClass.getDeclaration(i)
|
||||
if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_FIELD)
|
||||
protoFields.add(declaration.irField)
|
||||
else if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_PROPERTY) {
|
||||
val protoProperty = declaration.irProperty
|
||||
if (protoProperty.hasBackingField())
|
||||
protoFields.add(protoProperty.backingField)
|
||||
}
|
||||
}
|
||||
val protoFieldsMap = mutableMapOf<String, ProtoField>()
|
||||
protoFields.forEach {
|
||||
val nameAndType = BinaryNameAndType.decode(it.nameType)
|
||||
val name = fileReader.string(nameAndType.nameIndex)
|
||||
val prev = protoFieldsMap[name]
|
||||
if (prev != null)
|
||||
error("Class ${irClass.render()} has two fields with same name '$name'")
|
||||
protoFieldsMap[name] = it
|
||||
}
|
||||
|
||||
val outerThisIndex = fields.indexOfFirst { it.irField?.origin == IrDeclarationOrigin.FIELD_FOR_OUTER_THIS }
|
||||
val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures
|
||||
return SerializedClassFields(
|
||||
SerializedFileReference(fileDeserializationState.file),
|
||||
BinarySymbolData.decode(protoClass.base.symbol).signatureId,
|
||||
typeParameterSigs.toIntArray(),
|
||||
outerThisIndex,
|
||||
Array(fields.size) {
|
||||
val field = fields[it]
|
||||
val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}")
|
||||
if (it == outerThisIndex) {
|
||||
require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" }
|
||||
require(protoClasses.size > 1) { "An inner class must have at least one outer class" }
|
||||
val outerProtoClass = protoClasses[protoClasses.size - 2]
|
||||
val nameAndType = BinaryNameAndType.decode(outerProtoClass.thisReceiver.nameType)
|
||||
|
||||
SerializedClassFieldInfo(
|
||||
name = KonanIrLinker.INVALID_INDEX,
|
||||
binaryType = KonanIrLinker.INVALID_INDEX,
|
||||
nameAndType.typeIndex,
|
||||
flags = 0,
|
||||
field.alignment
|
||||
)
|
||||
} else {
|
||||
val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}")
|
||||
val nameAndType = BinaryNameAndType.decode(protoField.nameType)
|
||||
var flags = 0
|
||||
if (field.isConst)
|
||||
flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST
|
||||
val classifier = irField.type.classifierOrNull
|
||||
?: error("Fields of type ${irField.type.render()} are not supported")
|
||||
val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull()
|
||||
|
||||
SerializedClassFieldInfo(
|
||||
nameAndType.nameIndex,
|
||||
primitiveBinaryType?.ordinal ?: KonanIrLinker.INVALID_INDEX,
|
||||
if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false)
|
||||
KonanIrLinker.INVALID_INDEX
|
||||
else nameAndType.typeIndex,
|
||||
flags,
|
||||
field.alignment
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun buildEagerInitializedFile(irFile: IrFile) =
|
||||
SerializedEagerInitializedFile(SerializedFileReference(irFile))
|
||||
|
||||
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl(
|
||||
moduleDescriptor, KonanManglerDesc,
|
||||
DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY
|
||||
)
|
||||
|
||||
private val deserializedSymbols = mutableMapOf<IdSignature, IrSymbol>()
|
||||
|
||||
// Need to notify the deserializing machinery that some symbols have already been created by stub generator
|
||||
// (like type parameters and receiver parameters) and there's no need to create new symbols for them.
|
||||
private fun referenceIrSymbol(symbolDeserializer: IrSymbolDeserializer, sigIndex: Int, symbol: IrSymbol) {
|
||||
val idSig = symbolDeserializer.deserializeIdSignature(sigIndex)
|
||||
symbolDeserializer.referenceLocalIrSymbol(symbol, idSig)
|
||||
if (idSig.isPubliclyVisible) {
|
||||
deserializedSymbols[idSig]?.let {
|
||||
require(it == symbol) { "Two different symbols for the same signature ${idSig.render()}" }
|
||||
}
|
||||
// Sometimes the linker would want to create a new symbol, so save actual symbol here
|
||||
// and use it in [contains] and [tryDeserializeSymbol].
|
||||
deserializedSymbols[idSig] = symbol
|
||||
}
|
||||
}
|
||||
|
||||
override fun contains(idSig: IdSignature): Boolean =
|
||||
super.contains(idSig) || deserializedSymbols.containsKey(idSig) ||
|
||||
cacheDeserializationStrategy != CacheDeserializationStrategy.WholeModule
|
||||
&& idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null
|
||||
|
||||
override fun tryDeserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol? {
|
||||
super.tryDeserializeIrSymbol(idSig, symbolKind)?.let { return it }
|
||||
|
||||
deserializedSymbols[idSig]?.let { return it }
|
||||
|
||||
val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: return null
|
||||
|
||||
descriptorSignatures[descriptor] = idSig
|
||||
|
||||
return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol
|
||||
}
|
||||
|
||||
private val inlineFunctionReferences by lazy {
|
||||
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||
cache.serializedInlineFunctionBodies.associateBy {
|
||||
it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature)
|
||||
}
|
||||
}
|
||||
|
||||
private val deserializedInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||
|
||||
fun deserializeInlineFunction(function: IrFunction): DeserializedInlineFunction {
|
||||
deserializedInlineFunctions[function]?.let { return DeserializedInlineFunction(firstAccess = false, it) }
|
||||
val result = deserializeInlineFunctionInternal(function)
|
||||
deserializedInlineFunctions[function] = result
|
||||
return DeserializedInlineFunction(firstAccess = true, result)
|
||||
}
|
||||
|
||||
private fun deserializeInlineFunctionInternal(function: IrFunction): InlineFunctionOriginInfo {
|
||||
val packageFragment = function.getPackageFragment()
|
||||
if (function.parents.any { (it as? IrFunction)?.isInline == true }) {
|
||||
// Already deserialized by the top-most inline function.
|
||||
return InlineFunctionOriginInfo(
|
||||
function,
|
||||
packageFragment as? IrFile
|
||||
?: inlineFunctionFiles[packageFragment as IrExternalPackageFragment]
|
||||
?: error("${function.render()} should've been deserialized along with its parent"),
|
||||
function.startOffset, function.endOffset
|
||||
)
|
||||
}
|
||||
|
||||
val signature = function.symbol.signature
|
||||
?: descriptorSignatures[function.descriptor]
|
||||
?: error("No signature for ${function.render()}")
|
||||
val inlineFunctionReference = inlineFunctionReferences[signature]
|
||||
?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}")
|
||||
val fileDeserializationState = inlineFunctionReference.file.deserializationState
|
||||
val declarationDeserializer = fileDeserializationState.declarationDeserializer
|
||||
|
||||
if (packageFragment is IrExternalPackageFragment) {
|
||||
val symbolDeserializer = declarationDeserializer.symbolDeserializer
|
||||
|
||||
inlineFunctionFiles[packageFragment]?.let {
|
||||
require(it == fileDeserializationState.file) {
|
||||
"Different files ${it.fileEntry.name} and ${fileDeserializationState.file.fileEntry.name} have the same $packageFragment"
|
||||
}
|
||||
}
|
||||
inlineFunctionFiles[packageFragment] = fileDeserializationState.file
|
||||
|
||||
val outerClasses = (function.parent as? IrClass)?.getOuterClasses(takeOnlyInner = true) ?: emptyList()
|
||||
require((outerClasses.getOrNull(0)?.firstNonClassParent ?: function.parent) is IrPackageFragment) {
|
||||
"Local inline functions are not supported: ${function.render()}"
|
||||
}
|
||||
|
||||
var endToEndTypeParameterIndex = 0
|
||||
outerClasses.forEach { outerClass ->
|
||||
outerClass.typeParameters.forEach { parameter ->
|
||||
val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
}
|
||||
function.typeParameters.forEach { parameter ->
|
||||
val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
function.valueParameters.forEachIndexed { index, parameter ->
|
||||
val sigIndex = inlineFunctionReference.valueParameterSigs[index]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
function.extensionReceiverParameter?.let { parameter ->
|
||||
val sigIndex = inlineFunctionReference.extensionReceiverSig
|
||||
require(sigIndex != KonanIrLinker.INVALID_INDEX) { "Expected a valid sig reference to the extension receiver for ${function.render()}" }
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
function.dispatchReceiverParameter?.let { parameter ->
|
||||
val sigIndex = inlineFunctionReference.dispatchReceiverSig
|
||||
require(sigIndex != KonanIrLinker.INVALID_INDEX) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" }
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
for (index in 0 until outerClasses.size - 1) {
|
||||
val sigIndex = inlineFunctionReference.outerReceiverSigs[index]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, outerClasses[index].thisReceiver!!.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
with(declarationDeserializer) {
|
||||
function.withDeserializeBodies {
|
||||
body = (deserializeStatementBody(inlineFunctionReference.body) as IrBody)
|
||||
valueParameters.forEachIndexed { index, parameter ->
|
||||
val defaultValueIndex = inlineFunctionReference.defaultValues[index]
|
||||
if (defaultValueIndex != KonanIrLinker.INVALID_INDEX)
|
||||
parameter.defaultValue = deserializeExpressionBody(defaultValueIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packageFragment is IrFile)
|
||||
linker.deserializeAllReachableTopLevels()
|
||||
|
||||
linker.partialLinkageSupport.exploreClassifiers(linker.fakeOverrideBuilder)
|
||||
linker.partialLinkageSupport.exploreClassifiersInInlineLazyIrFunction(function)
|
||||
|
||||
linker.fakeOverrideBuilder.provideFakeOverrides()
|
||||
|
||||
linker.partialLinkageSupport.generateStubsAndPatchUsages(linker.symbolTable, function)
|
||||
|
||||
linker.checkNoUnboundSymbols(
|
||||
linker.symbolTable,
|
||||
"after deserializing lazy-IR function ${function.name.asString()} in inline functions lowering"
|
||||
)
|
||||
|
||||
return InlineFunctionOriginInfo(
|
||||
function,
|
||||
fileDeserializationState.file,
|
||||
inlineFunctionReference.startOffset,
|
||||
inlineFunctionReference.endOffset
|
||||
)
|
||||
}
|
||||
|
||||
private val classesFields by lazy {
|
||||
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||
cache.serializedClassFields.associateBy {
|
||||
it.file.deserializationState.declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature)
|
||||
}
|
||||
}
|
||||
|
||||
private val lock = Any()
|
||||
|
||||
fun deserializeClassFields(irClass: IrClass, outerThisFieldInfo: ClassLayoutBuilder.FieldInfo?): List<ClassLayoutBuilder.FieldInfo> = synchronized(lock) {
|
||||
val signature = irClass.symbol.signature
|
||||
?: error("No signature for ${irClass.render()}")
|
||||
val serializedClassFields = classesFields[signature]
|
||||
?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}")
|
||||
val fileDeserializationState = serializedClassFields.file.deserializationState
|
||||
val declarationDeserializer = fileDeserializationState.declarationDeserializer
|
||||
val symbolDeserializer = declarationDeserializer.symbolDeserializer
|
||||
|
||||
if (irClass.getPackageFragment() is IrExternalPackageFragment) {
|
||||
val outerClasses = irClass.getOuterClasses(takeOnlyInner = true)
|
||||
require(outerClasses.first().firstNonClassParent is IrExternalPackageFragment) {
|
||||
"Local classes are not supported: ${irClass.render()}"
|
||||
}
|
||||
|
||||
var endToEndTypeParameterIndex = 0
|
||||
outerClasses.forEach { outerClass ->
|
||||
outerClass.typeParameters.forEach { parameter ->
|
||||
val sigIndex = serializedClassFields.typeParameterSigs[endToEndTypeParameterIndex++]
|
||||
referenceIrSymbol(symbolDeserializer, sigIndex, parameter.symbol)
|
||||
}
|
||||
}
|
||||
require(endToEndTypeParameterIndex == serializedClassFields.typeParameterSigs.size) {
|
||||
"Not all type parameters have been referenced"
|
||||
}
|
||||
}
|
||||
|
||||
fun getByClassId(classId: ClassId): IrClassSymbol {
|
||||
val classIdSig = getPublicSignature(classId.packageFqName, classId.relativeClassName.asString())
|
||||
return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol
|
||||
}
|
||||
|
||||
return serializedClassFields.fields.mapIndexed { index, field ->
|
||||
val builtIns = linker.builtIns
|
||||
if (index == serializedClassFields.outerThisIndex) {
|
||||
require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" }
|
||||
require(outerThisFieldInfo != null) { "For an inner class ${irClass.render()} there should be <outer this> field" }
|
||||
outerThisFieldInfo.also {
|
||||
require(it.alignment == field.alignment) { "Mismatched align information for outer this"}
|
||||
}
|
||||
} else {
|
||||
val name = fileDeserializationState.fileReader.string(field.name)
|
||||
val type = when {
|
||||
field.type != KonanIrLinker.INVALID_INDEX -> declarationDeserializer.deserializeIrType(field.type)
|
||||
field.binaryType == KonanIrLinker.INVALID_INDEX -> builtIns.anyNType
|
||||
else -> when (PrimitiveBinaryType.values().getOrNull(field.binaryType)) {
|
||||
PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType
|
||||
PrimitiveBinaryType.BYTE -> builtIns.byteType
|
||||
PrimitiveBinaryType.SHORT -> builtIns.shortType
|
||||
PrimitiveBinaryType.INT -> builtIns.intType
|
||||
PrimitiveBinaryType.LONG -> builtIns.longType
|
||||
PrimitiveBinaryType.FLOAT -> builtIns.floatType
|
||||
PrimitiveBinaryType.DOUBLE -> builtIns.doubleType
|
||||
PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType
|
||||
PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType
|
||||
else -> error("Bad binary type of field $name of ${irClass.render()}")
|
||||
}
|
||||
}
|
||||
ClassLayoutBuilder.FieldInfo(
|
||||
name, type,
|
||||
isConst = (field.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0,
|
||||
irFieldSymbol = IrFieldSymbolImpl(),
|
||||
alignment = field.alignment,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.getOuterClasses(takeOnlyInner: Boolean): List<IrClass> {
|
||||
var outerClass = this
|
||||
val outerClasses = mutableListOf(outerClass)
|
||||
while (outerClass.isInner || !takeOnlyInner) {
|
||||
outerClass = outerClass.parent as? IrClass ?: break
|
||||
outerClasses.add(outerClass)
|
||||
}
|
||||
outerClasses.reverse()
|
||||
return outerClasses
|
||||
}
|
||||
|
||||
val eagerInitializedFiles by lazy {
|
||||
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||
cache.serializedEagerInitializedFiles
|
||||
.map { it.file.deserializationState.file }
|
||||
.distinct()
|
||||
}
|
||||
|
||||
val sortedFileIds by lazy {
|
||||
fileDeserializationStates
|
||||
.sortedBy { it.file.fileEntry.name }
|
||||
.map { CacheSupport.cacheFileId(it.file.packageFqName.asString(), it.file.fileEntry.name) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user