Commonized native and js IR serialization infrastructure.

This commit is contained in:
Alexander Gorshenev
2019-03-13 23:05:19 +03:00
committed by alexander-gorshenev
parent 46879b94cc
commit d9ff5a9778
20 changed files with 268 additions and 3866 deletions
@@ -53,6 +53,7 @@ import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.serialization.KotlinMangler
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
@@ -62,7 +63,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
*/
internal const val SYNTHETIC_OFFSET = -2
internal class SpecialDeclarationsFactory(val context: Context) {
internal class SpecialDeclarationsFactory(val context: Context) : KotlinMangler by KonanMangler {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>()
private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>()
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
@@ -13,6 +14,7 @@ import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
@@ -67,7 +69,7 @@ internal val psiToIrPhase = konanUnitPhase(
val forwardDeclarationsModuleDescriptor = moduleDescriptor.allDependencyModules.firstOrNull { it.isForwardDeclarationModule }
val deserializer = KonanIrModuleDeserializer(
val deserializer = KonanIrLinker(
moduleDescriptor,
this as LoggingContext,
generatorContext.irBuiltIns,
@@ -144,8 +146,8 @@ internal val patchDeclarationParents0Phase = konanUnitPhase(
internal val serializerPhase = konanUnitPhase(
op = {
val declarationTable = DeclarationTable(irModule!!.irBuiltins, DescriptorTable())
val serializedIr = IrModuleSerializer(this, declarationTable).serializedIrModule(irModule!!)
val declarationTable = KonanDeclarationTable(irModule!!.irBuiltins, DescriptorTable()).apply { loadKnownBuiltins() }
val serializedIr = KonanIrModuleSerializer(this, declarationTable).serializedIrModule(irModule!!)
val serializer = KonanSerializationUtil(this, config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable)
serializedLinkData =
serializer.serializeModule(moduleDescriptor, /*if (!config.isInteropStubs) serializedIr else null*/ serializedIr)
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.backend.konan.library
import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.konan.serialization.UniqId
import org.jetbrains.kotlin.backend.common.serialization.SerializedIr
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
import org.jetbrains.kotlin.konan.properties.Properties
@@ -31,12 +31,6 @@ class LinkData(
val ir: SerializedIr? = null
)
class SerializedIr (
val module: ByteArray,
val combinedDeclarationFilePath: String,
val debugIndex: Map<UniqId, String>
)
interface MetadataWriter {
fun addLinkData(linkData: LinkData)
}
@@ -30,7 +30,5 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra
// TODO: use Files.move.
File(it).copyTo(irFile)
}
val lines = linkData.ir?.debugIndex?.map { entry -> "${entry.key}: ${entry.value}" }
if (lines != null) irIndex.writeLines(lines)
}
}
@@ -6,11 +6,15 @@
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef
import org.jetbrains.kotlin.backend.common.serialization.KotlinMangler
import org.jetbrains.kotlin.backend.common.serialization.KotlinManglerImpl
import org.jetbrains.kotlin.backend.common.serialization.isVararg
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.externalSymbolOrThrow
import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler.isExported
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -29,261 +33,118 @@ import org.jetbrains.kotlin.name.Name
// TODO: revise the naming scheme to ensure it produces unique names.
// TODO: do not serialize descriptors of non-exported declarations.
/**
* Defines whether the declaration is exported, i.e. visible from other modules.
*
* Exported declarations must have predictable and stable ABI
* that doesn't depend on any internal transformations (e.g. IR lowering),
* and so should be computable from the descriptor itself without checking a backend state.
*/
internal tailrec fun IrDeclaration.isExported(): Boolean {
// TODO: revise
val descriptorAnnotations = this.descriptor.annotations
if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(exportForCppRuntimeAnnotation)) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(cnameAnnotation)) {
// Treat `@CName` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(exportForCompilerAnnotation)) {
return true
}
if (descriptorAnnotations.hasAnnotation(publishedApiAnnotation)){
return true
}
object KonanMangler : KotlinManglerImpl() {
if (this.isAnonymousObject)
return false
if (this is IrConstructor && constructedClass.kind.isSingleton) {
// Currently code generator can access the constructor of the singleton,
// so ignore visibility of the constructor itself.
return constructedClass.isExported()
}
if (this is IrFunction) {
val descriptor = this.descriptor
// TODO: this code is required because accessor doesn't have a reference to property.
if (descriptor is PropertyAccessorDescriptor) {
val property = descriptor.correspondingProperty
if (property.annotations.hasAnnotation(publishedApiAnnotation)) return true
}
}
val visibility = when (this) {
is IrClass -> this.visibility
is IrFunction -> this.visibility
is IrProperty -> this.visibility
is IrField -> this.visibility
else -> null
}
override val String.hashMangle get() = this.localHash.value
/**
* note: about INTERNAL - with support of friend modules we let frontend to deal with internal declarations.
* Defines whether the declaration is exported, i.e. visible from other modules.
*
* Exported declarations must have predictable and stable ABI
* that doesn't depend on any internal transformations (e.g. IR lowering),
* and so should be computable from the descriptor itself without checking a backend state.
*/
if (visibility != null && !visibility.isPublicAPI && visibility != Visibilities.INTERNAL) {
// If the declaration is explicitly marked as non-public,
// then it must not be accessible from other modules.
override fun IrDeclaration.isPlatformSpecificExported(): Boolean {
// TODO: revise
val descriptorAnnotations = this.descriptor.annotations
if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(exportForCppRuntimeAnnotation)) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(cnameAnnotation)) {
// Treat `@CName` declaration as exported.
return true
}
if (descriptorAnnotations.hasAnnotation(exportForCompilerAnnotation)) {
return true
}
return false
}
val parent = this.parent
if (parent is IrDeclaration) {
return parent.isExported()
}
private val symbolNameAnnotation = RuntimeNames.symbolName
return true
}
private val cnameAnnotation = FqName("kotlin.native.CName")
private val symbolNameAnnotation = RuntimeNames.symbolName
private val exportForCppRuntimeAnnotation = RuntimeNames.exportForCppRuntime
private val cnameAnnotation = FqName("kotlin.native.CName")
private val exportForCompilerAnnotation = RuntimeNames.exportForCompilerAnnotation
private val exportForCppRuntimeAnnotation = RuntimeNames.exportForCppRuntime
private val exportForCompilerAnnotation = RuntimeNames.exportForCompilerAnnotation
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
private fun acyclicTypeMangler(visited: MutableSet<IrTypeParameter>, type: IrType): String {
val descriptor = (type.classifierOrNull as? IrTypeParameterSymbol)?.owner
if (descriptor != null) {
val upperBounds = if (visited.contains(descriptor)) "" else {
visited.add(descriptor)
descriptor.superTypes.map {
val bound = acyclicTypeMangler(visited, it)
if (bound == "kotlin.Any?") "" else "_$bound"
}.joinToString("")
}
return "#GENERIC${if (type.isMarkedNullable()) "?" else ""}$upperBounds"
}
var hashString = type.getClass()!!.fqNameSafe.asString()
if (type !is IrSimpleType) error(type)
if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map {
when (it) {
is IrStarProjection -> "#STAR"
is IrTypeProjection -> {
val variance = it.variance.label
val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type)
}
else -> error(it)
}
}.joinToString(",")}>"
}
if (type.hasQuestionMark) hashString += "?"
return hashString
}
private fun typeToHashString(type: IrType)
= acyclicTypeMangler(mutableSetOf<IrTypeParameter>(), type)
internal val IrValueParameter.extensionReceiverNamePart: String
get() = "@${typeToHashString(this.type)}."
private val IrFunction.signature: String
get() {
val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
val argsPart = this.valueParameters.map {
override val IrFunction.argsPart get() = this.valueParameters.map {
// TODO: there are clashes originating from ObjectiveC interop.
// kotlinx.cinterop.ObjCClassOf<T>.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt
// and
// kotlinx.cinterop.ObjCClassOf<T>.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt
val argName = if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${it.name}:" else ""
"$argName${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}"
}.joinToString(";")
// Distinguish value types and references - it's needed for calling virtual methods through bridges.
// Also is function has type arguments - frontend allows exactly matching overrides.
val signatureSuffix =
when {
this.typeParameters.isNotEmpty() -> "Generic"
returnType.isInlined() -> "ValueType"
!returnType.isUnitOrNullableUnit() -> typeToHashString(returnType)
else -> ""
val argName =
if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${it.name}:" else ""
"$argName${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}"
}.joinToString(";")
override val IrFunction.platformSpecificFunctionName: String?
get() {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()
?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
append("objc:")
append(it.selector)
if (this@platformSpecificFunctionName is IrConstructor && this@platformSpecificFunctionName.isObjCConstructor) append("#Constructor")
// We happen to have the clashing combinations such as
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// So disambiguate by the name of the bridge for now.
// TODO: idealy we'd never generate such identical declarations.
if (this@platformSpecificFunctionName is IrSimpleFunction && this@platformSpecificFunctionName.hasObjCMethodAnnotation()) {
this@platformSpecificFunctionName.objCMethodArgValue("selector")?.let { append("#$it") }
this@platformSpecificFunctionName.objCMethodArgValue("bridge")?.let { append("#$it") }
}
}
}
return "$extensionReceiverPart($argsPart)$signatureSuffix"
}
return null
}
// TODO: rename to indicate that it has signature included
internal val IrFunction.functionName: String
get() {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
internal val IrFunction.symbolName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.descriptor.toString())
}
append("objc:")
append(it.selector)
if (this@functionName is IrConstructor && this@functionName.isObjCConstructor) append("#Constructor")
// We happen to have the clashing combinations such as
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
//@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172")
//external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// So disambiguate by the name of the bridge for now.
// TODO: idealy we'd never generate such identical declarations.
if (this@functionName is IrSimpleFunction && this@functionName.hasObjCMethodAnnotation()) {
this@functionName.objCMethodArgValue("selector") ?.let { append("#$it") }
this@functionName.objCMethodArgValue("bridge") ?.let { append("#$it") }
if (isExternal) {
this.descriptor.externalSymbolOrThrow()?.let {
return it
}
}
}
val name = this.name.mangleIfInternal(this.module, this.visibility)
return "$name$signature"
}
private fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility: Visibility): String =
if (visibility != Visibilities.INTERNAL) {
this.asString()
} else {
val moduleName = moduleDescriptor.name.asString()
.let { it.substring(1, it.lastIndex) } // Remove < and >.
"$this\$$moduleName"
}
internal val IrFunction.symbolName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.descriptor.toString())
}
if (isExternal) {
this.descriptor.externalSymbolOrThrow()?.let {
return it
this.descriptor.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
val name = getAnnotationValue(it) ?: this.name.asString()
return name // no wrapping currently required
}
val parent = this.parent
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart$functionName"
}
this.descriptor.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
val name = getAnnotationValue(it) ?: this.name.asString()
return name // no wrapping currently required
}
val parent = this.parent
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart$functionName"
}
internal val IrField.symbolName: String
get() {
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfield:$containingDeclarationPart$name"
}
// TODO: bring here dependencies of this method?
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
val returnType = when {
function is IrConstructor -> voidType
function.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(function.returnType)
}
val paramTypes = ArrayList(function.allParameters.map { getLLVMType(it.type) })
if (function.isSuspend)
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
}
internal fun RuntimeAware.getLlvmFunctionType(symbol: DataFlowIR.FunctionSymbol): LLVMTypeRef {
val returnType = if (symbol.returnsUnit) voidType else getLLVMType(symbol.returnParameter.type)
val paramTypes = ArrayList(symbol.parameters.map { getLLVMType(it.type) })
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
}
internal val IrClass.typeInfoSymbolName: String
get() {
assert (this.isExported())
return "ktype:" + this.fqNameSafe.toString()
}
internal val IrClass.writableTypeInfoSymbolName: String
get() {
assert (this.isExported())
@@ -311,6 +172,39 @@ internal val IrClass.objectInstanceShadowFieldSymbolName: String
return "kshadowobjref:$fqNameSafe"
}
val IrFunction.functionName get() = with(KonanMangler) { functionName }
val IrFunction.symbolName get() = with(KonanMangler) { symbolName }
val IrField.symbolName get() = with(KonanMangler) { symbolName }
val IrClass.typeInfoSymbolName get() = with(KonanMangler) { typeInfoSymbolName }
fun IrDeclaration.isExported() = with(KonanMangler) { isExported() }
// TODO: bring here dependencies of this method?
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
val returnType = when {
function is IrConstructor -> voidType
function.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(function.returnType)
}
val paramTypes = ArrayList(function.allParameters.map { getLLVMType(it.type) })
if (function.isSuspend)
paramTypes.add(kObjHeaderPtr) // Suspend functions have implicit parameter of type Continuation<>.
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
}
internal fun RuntimeAware.getLlvmFunctionType(symbol: DataFlowIR.FunctionSymbol): LLVMTypeRef {
val returnType = if (symbol.returnsUnit) voidType else getLLVMType(symbol.returnParameter.type)
val paramTypes = ArrayList(symbol.parameters.map { getLLVMType(it.type) })
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
}
internal val IrClass.typeInfoHasVtableAttached: Boolean
get() = !this.isAbstract() && !this.isExternalObjCClass()
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.common.serialization.KotlinMangler
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
@@ -1,56 +0,0 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
class DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
descriptors.getOrPut(descriptor) { uniqId.index }
}
fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor]
}
// TODO: We don't manage id clashes anyhow now.
class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: DescriptorTable) {
private val table = mutableMapOf<IrDeclaration, UniqId>()
val debugIndex = mutableMapOf<UniqId, String>()
val descriptors = descriptorTable
private var currentIndex = 0L
init {
builtIns.knownBuiltins.forEach {
table.put(it, UniqId(currentIndex ++, false))
}
}
fun uniqIdByDeclaration(value: IrDeclaration): UniqId = table.getOrPut(value) {
val index = if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
!value.isExported()
|| value is IrVariable
|| value is IrTypeParameter
|| value is IrValueParameter
|| value is IrAnonymousInitializerImpl
) {
UniqId(currentIndex++, true)
} else {
UniqId(value.uniqIdIndex, false)
}
// It can grow as large as 1/3 of ir/* size.
// debugIndex.put(index) {
// "${if (index.isLocal) "" else value.uniqSymbolName()} descriptor = ${value.descriptor}"
//}.also {it == null}
index
}
}
// This is what we pre-populate tables with
val IrBuiltIns.knownBuiltins
get() = irBuiltInsExternalPackageFragment.declarations
@@ -0,0 +1,18 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
// TODO: We don't manage id clashes anyhow now.
class KonanDeclarationTable(builtIns: IrBuiltIns, descriptorTable: DescriptorTable):
DeclarationTable(builtIns, descriptorTable, KonanMangler) {
override var currentIndex = 0L
}
// This is what we pre-populate tables with
val IrBuiltIns.knownBuiltins
get() = irBuiltInsExternalPackageFragment.declarations
@@ -1,5 +1,9 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.DescriptorReferenceDeserializer
import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.UniqId
import org.jetbrains.kotlin.backend.common.serialization.UniqIdKey
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.ClassId
@@ -13,63 +17,30 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
// tree of deserialized descriptors. Think of it as base + offset.
// packageFqName + classFqName + index allow to localize some deserialized descriptor.
// Then the rest of the fields allow to find the needed descriptor relative to the one with index.
class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>) {
class KonanDescriptorReferenceDeserializer(
currentModule: ModuleDescriptor,
resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>)
: DescriptorReferenceDeserializer(currentModule, resolvedForwardDeclarations),
DescriptorUniqIdAware by KonanDescriptorUniqIdAware{
private fun getContributedDescriptors(packageFqNameString: String, name: String): Collection<DeclarationDescriptor> {
val packageFqName = packageFqNameString.let {
if (it == "<root>") FqName.ROOT else FqName(it)
}// TODO: whould we store an empty string in the protobuf?
// TODO: these are dummies. Eliminate them.
override fun resolveSpecialDescriptor(fqn: FqName): DeclarationDescriptor = currentModule
override fun checkIfSpecialDescriptorId(id: Long): Boolean = false
override fun getDescriptorIdOrNull(descriptor: DeclarationDescriptor): Long? = null
val memberScope = currentModule.getPackage(packageFqName).memberScope
return getContributedDescriptors(memberScope, name)
}
private fun getContributedDescriptors(memberScope: MemberScope, name: String): Collection<DeclarationDescriptor> {
val contributedNameString = if (name.startsWith("<get-") || name.startsWith("<set-")) {
name.substring(5, name.length - 1) // FIXME: rework serialization format.
} else {
name
}
val contributedName = Name.identifier(contributedNameString)
return memberScope.getContributedFunctions(contributedName, NoLookupLocation.FROM_BACKEND) +
memberScope.getContributedVariables(contributedName, NoLookupLocation.FROM_BACKEND) +
listOfNotNull(memberScope.getContributedClassifier(contributedName, NoLookupLocation.FROM_BACKEND))
}
private class ClassMembers(val defaultConstructor: ClassConstructorDescriptor?,
val members: Map<Long, DeclarationDescriptor>,
val realMembers: Map<Long, DeclarationDescriptor>)
private fun getMembers(members: Collection<DeclarationDescriptor>): ClassMembers {
val allMembersMap = mutableMapOf<Long, DeclarationDescriptor>()
val realMembersMap = mutableMapOf<Long, DeclarationDescriptor>()
var classConstructorDescriptor: ClassConstructorDescriptor? = null
members.forEach { member ->
if (member is ClassConstructorDescriptor)
classConstructorDescriptor = member
val realMembers =
if (member is CallableMemberDescriptor && member.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
member.resolveFakeOverrideMaybeAbstract()
else
setOf(member)
member.getUniqId()?.index?.let { allMembersMap[it] = member }
realMembers.mapNotNull { it.getUniqId()?.index }.forEach { realMembersMap[it] = member }
}
return ClassMembers(classConstructorDescriptor, allMembersMap, realMembersMap)
}
fun deserializeDescriptorReference(
// Most of this function duplicates the parent, but it deals with forward declarations.
// TODO: Refactor me.
override fun deserializeDescriptorReference(
packageFqNameString: String,
classFqNameString: String,
name: String,
index: Long?,
isEnumEntry: Boolean = false,
isEnumSpecial: Boolean = false,
isDefaultConstructor: Boolean = false,
isFakeOverride: Boolean = false,
isGetter: Boolean = false,
isSetter: Boolean = false
isEnumEntry: Boolean,
isEnumSpecial: Boolean,
isDefaultConstructor: Boolean,
isFakeOverride: Boolean,
isGetter: Boolean,
isSetter: Boolean
): DeclarationDescriptor {
val packageFqName = packageFqNameString.let {
if (it == "<root>") FqName.ROOT else FqName(it)
@@ -93,7 +64,7 @@ class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val r
)
) {
if (descriptor is DeserializedClassDescriptor) {
val uniqId = UniqId(descriptor.getUniqId()!!.index, false)
val uniqId = UniqId(descriptor.getUniqId()!!, false)
val newKey = UniqIdKey(null, uniqId)
val oldKey = UniqIdKey(null, UniqId(protoIndex!!, false))
@@ -132,4 +103,4 @@ class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val r
}
} ?: error("Could not find serialized descriptor for index: ${index} ${packageFqName},${classFqName},${name}")
}
}
}
@@ -1,660 +0,0 @@
syntax = "proto2";
package org.jetbrains.kotlin.metadata;
option java_outer_classname = "KonanIr";
option optimize_for = LITE_RUNTIME;
message DescriptorReference {
required String package_fq_name = 1;
required String class_fq_name = 2;
required String name = 3;
optional UniqId uniq_id = 4;
optional bool is_getter = 5 [default = false];
optional bool is_setter = 6 [default = false];
optional bool is_backing_field = 7 [default = false];
optional bool is_fake_override = 8 [default = false];
optional bool is_default_constructor = 9 [default = false];
optional bool is_enum_entry = 10 [default = false];
optional bool is_enum_special = 11 [default = false];
}
message UniqId {
required uint64 index = 1;
required bool isLocal = 2;
}
message Coordinates {
required int32 start_offset = 1;
required int32 end_offset = 2;
}
message Visibility {
required String name = 1;
}
message IrStatementOrigin {
required String name = 1;
}
enum KnownOrigin {
CUSTOM = 1;
DEFINED = 2;
FAKE_OVERRIDE = 3;
FOR_LOOP_ITERATOR = 4;
FOR_LOOP_VARIABLE = 5;
FOR_LOOP_IMPLICIT_VARIABLE = 6;
PROPERTY_BACKING_FIELD = 7;
DEFAULT_PROPERTY_ACCESSOR = 8;
DELEGATE = 9;
DELEGATED_PROPERTY_ACCESSOR = 10;
DELEGATED_MEMBER = 11;
ENUM_CLASS_SPECIAL_MEMBER = 12;
FUNCTION_FOR_DEFAULT_PARAMETER = 13;
FILE_CLASS = 14;
GENERATED_DATA_CLASS_MEMBER = 15;
GENERATED_INLINE_CLASS_MEMBER = 16;
LOCAL_FUNCTION_FOR_LAMBDA = 17;
CATCH_PARAMETER = 19;
INSTANCE_RECEIVER = 20;
PRIMARY_CONSTRUCTOR_PARAMETER = 21;
IR_TEMPORARY_VARIABLE = 22;
IR_EXTERNAL_DECLARATION_STUB = 23;
IR_EXTERNAL_JAVA_DECLARATION_STUB = 24;
IR_BUILTINS_STUB = 25;
BRIDGE = 26;
FIELD_FOR_ENUM_ENTRY = 27;
FIELD_FOR_ENUM_VALUES = 28;
FIELD_FOR_OBJECT_INSTANCE = 29;
}
message IrDeclarationOrigin {
oneof either {
KnownOrigin origin = 1;
String custom = 2;
}
}
/* ------ Top Level---------------------------------------KonanIrModuleDeserializer.kt------- */
message IrDeclarationContainer {
repeated IrDeclaration declaration = 1;
}
message FileEntry {
required String name = 1;
repeated int32 line_start_offsets = 2;
}
message IrFile {
repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2;
required String fq_name = 3;
required Annotations annotations = 4;
repeated IrSymbol explicitly_exported_to_compiler = 5; // Symbols referenced by C runtime. TODO: Make an extension?
}
message IrModule {
required String name = 1;
repeated IrFile file = 2;
required IrSymbolTable symbol_table = 3;
required IrTypeTable type_table = 4;
required StringTable string_table = 5;
}
/* ------ String Table ------------------------------------------ */
message String {
required int32 index = 1;
}
message StringTable {
repeated string strings = 1;
}
/* ------ IrSymbols --------------------------------------------- */
enum IrSymbolKind {
FUNCTION_SYMBOL = 1;
CONSTRUCTOR_SYMBOL = 2;
ENUM_ENTRY_SYMBOL = 3;
FIELD_SYMBOL = 4;
VALUE_PARAMETER_SYMBOL = 5;
RETURNABLE_BLOCK_SYMBOL = 6;
CLASS_SYMBOL = 7;
TYPE_PARAMETER_SYMBOL = 8;
VARIABLE_SYMBOL = 9;
ANONYMOUS_INIT_SYMBOL = 10;
STANDALONE_FIELD_SYMBOL = 11; // For fields without properties. WrappedFieldDescriptor, rather than WrappedPropertyDescriptor.
RECEIVER_PARAMETER_SYMBOL = 12; // ReceiverParameterDescriptor rather than ValueParameterDescriptor.
}
message IrSymbolData {
required IrSymbolKind kind = 1;
required UniqId uniq_id = 2;
required UniqId top_level_uniq_id = 3;
optional String fqname = 4;
optional DescriptorReference descriptor_reference = 5;
}
message IrSymbol {
required int32 index = 1;
}
message IrSymbolTable {
repeated IrSymbolData symbols = 1;
}
/* ------ IrTypes --------------------------------------------- */
enum IrTypeVariance { // Should we import metadata variance, or better stay separate?
IN = 0;
OUT = 1;
INV = 2;
}
message Annotations {
repeated IrCall annotation = 1;
}
message TypeArguments {
repeated IrTypeIndex type_argument = 1;
}
message IrStarProjection {
optional bool void = 1;
}
message IrTypeProjection {
required IrTypeVariance variance = 1;
required IrTypeIndex type = 2;
}
message IrTypeArgument {
oneof kind {
IrStarProjection star = 1;
IrTypeProjection type = 2;
}
}
message IrSimpleType {
required Annotations annotations = 1;
required IrSymbol classifier = 2;
required bool has_question_mark = 3;
repeated IrTypeArgument argument = 4;
}
message IrDynamicType {
required Annotations annotations = 1;
}
message IrErrorType {
required Annotations annotations = 1;
}
message IrType {
oneof kind {
IrSimpleType simple = 1;
IrDynamicType dynamic = 2;
IrErrorType error = 3;
}
}
message IrTypeTable {
repeated IrType types = 1;
}
message IrTypeIndex {
required int32 index = 1;
}
/* ------ IrExpressions --------------------------------------------- */
message IrBreak {
required int32 loop_id = 1;
optional String label = 2;
}
message IrBlock {
required bool is_lambda_origin = 1;
repeated IrStatement statement = 2;
}
message MemberAccessCommon {
optional IrExpression dispatch_receiver = 1;
optional IrExpression extension_receiver = 2;
repeated NullableIrExpression value_argument = 3;
required TypeArguments type_arguments = 4;
}
message IrCall {
enum Primitive {
NOT_PRIMITIVE = 1;
NULLARY = 2;
UNARY = 3;
BINARY = 4;
}
required Primitive kind = 1;
required IrSymbol symbol = 2;
required MemberAccessCommon member_access = 3;
optional IrSymbol super = 4;
}
message IrFunctionReference {
required IrSymbol symbol = 1;
optional IrStatementOrigin origin = 2;
required MemberAccessCommon member_access = 3;
}
message IrPropertyReference {
optional IrSymbol field = 1;
optional IrSymbol getter = 2;
optional IrSymbol setter = 3;
optional IrStatementOrigin origin = 4;
required MemberAccessCommon member_access = 5;
optional DescriptorReference descriptor = 6; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
}
message IrComposite {
repeated IrStatement statement = 1;
}
message IrClassReference {
required IrSymbol class_symbol = 1;
required IrTypeIndex class_type = 2;
}
message IrConst {
oneof value {
bool null = 1;
bool boolean = 2;
int32 char = 3;
int32 byte = 4;
int32 short = 5;
int32 int = 6;
int64 long = 7;
float float = 8;
double double = 9;
String string = 10;
}
}
message IrContinue {
required int32 loop_id = 1;
optional String label = 2;
}
message IrDelegatingConstructorCall {
required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2;
}
message IrDoWhile {
required Loop loop = 1;
}
message IrEnumConstructorCall {
required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2;
}
message IrGetClass {
required IrExpression argument = 1;
}
message IrGetEnumValue {
required IrSymbol symbol = 2;
}
message FieldAccessCommon {
required IrSymbol symbol = 1;
optional IrSymbol super = 2;
optional IrExpression receiver = 3;
}
message IrGetField {
required FieldAccessCommon field_access = 1;
}
message IrGetValue {
required IrSymbol symbol = 1;
}
message IrGetObject {
required IrSymbol symbol = 1;
}
message IrInstanceInitializerCall {
required IrSymbol symbol = 1;
}
message Loop {
required int32 loop_id = 1;
required IrExpression condition = 2;
optional String label = 3;
optional IrExpression body = 4;
}
message IrReturn {
required IrSymbol return_target = 1;
required IrExpression value = 2;
}
message IrSetField {
required FieldAccessCommon field_access = 1;
required IrExpression value = 2;
}
message IrSetVariable {
required IrSymbol symbol = 1;
required IrExpression value = 2;
}
message IrSpreadElement {
required IrExpression expression = 1;
required Coordinates coordinates = 2;
}
message IrStringConcat {
repeated IrExpression argument = 1;
}
message IrThrow {
required IrExpression value = 1;
}
message IrTry {
required IrExpression result = 1;
repeated IrStatement catch = 2;
optional IrExpression finally = 3;
}
message IrTypeOp {
required IrTypeOperator operator = 1;
required IrTypeIndex operand = 2;
required IrExpression argument = 3;
}
message IrVararg {
required IrTypeIndex element_type = 1;
repeated IrVarargElement element = 2;
}
message IrVarargElement {
oneof vararg_element {
IrExpression expression = 1;
IrSpreadElement spread_element = 2;
}
}
message IrWhen {
repeated IrStatement branch = 1;
}
message IrWhile {
required Loop loop = 1;
}
// TODO: we need an extension mechanism to accomodate new
// IR operators in upcoming releases.
message IrOperation {
oneof operation {
IrBlock block = 1;
IrBreak break = 2;
IrCall call = 3;
IrClassReference class_reference = 4;
IrComposite composite = 5;
IrConst const = 6;
IrContinue continue = 7;
IrDelegatingConstructorCall delegating_constructor_call = 8;
IrDoWhile do_while = 9;
IrEnumConstructorCall enum_constructor_call = 10;
IrFunctionReference function_reference = 11;
IrGetClass get_class = 12;
IrGetEnumValue get_enum_value = 13;
IrGetField get_field = 14;
IrGetObject get_object = 15;
IrGetValue get_value = 16;
IrInstanceInitializerCall instance_initializer_call = 17;
IrPropertyReference property_reference = 18;
IrReturn return = 19;
IrSetField set_field = 20;
IrSetVariable set_variable = 21;
IrStringConcat string_concat = 22;
IrThrow throw = 23;
IrTry try = 24;
IrTypeOp type_op = 25;
IrVararg vararg = 26;
IrWhen when = 27;
IrWhile while = 28;
}
}
enum IrTypeOperator {
CAST = 1;
IMPLICIT_CAST = 2;
IMPLICIT_NOTNULL = 3;
IMPLICIT_COERCION_TO_UNIT = 4;
IMPLICIT_INTEGER_COERCION = 5;
SAFE_CAST = 6;
INSTANCEOF = 7;
NOT_INSTANCEOF = 8;
SAM_CONVERSION = 9;
}
message IrExpression {
required IrOperation operation = 1;
required IrTypeIndex type = 2;
required Coordinates coordinates = 3;
}
message NullableIrExpression {
optional IrExpression expression = 1;
}
/* ------ Declarations --------------------------------------------- */
message IrTypeAlias {
// Nothing for now.
}
message IrFunction {
required IrSymbol symbol = 1;
required IrFunctionBase base = 2;
required ModalityKind modality = 3;
required bool is_tailrec = 4;
required bool is_suspend = 5;
repeated IrSymbol overridden = 6;
//optional UniqId corresponding_property = 7;
}
message IrFunctionBase {
required String name = 1;
required Visibility visibility = 2;
required bool is_inline = 3;
required bool is_external = 4;
required IrTypeParameterContainer type_parameters = 5;
optional IrDeclaration dispatch_receiver = 6;
optional IrDeclaration extension_receiver = 7;
repeated IrDeclaration value_parameter = 8;
optional IrStatement body = 9;
required IrTypeIndex return_type = 10;
}
message IrConstructor {
required IrSymbol symbol = 1;
required IrFunctionBase base = 2;
required bool is_primary = 3;
}
message IrField {
required IrSymbol symbol = 1;
optional IrExpression initializer = 2;
required String name = 3;
required Visibility visibility = 4;
required bool is_final = 5;
required bool is_external = 6;
required bool is_static = 7;
required IrTypeIndex type = 8;
}
message IrProperty {
optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
required String name = 2;
required Visibility visibility = 3;
required ModalityKind modality = 4;
required bool is_var = 5;
required bool is_const = 6;
required bool is_lateinit = 7;
required bool is_delegated = 8;
required bool is_external = 9;
optional IrField backing_field = 10;
optional IrFunction getter = 11;
optional IrFunction setter = 12;
}
message IrVariable {
required String name = 1;
required IrSymbol symbol = 2;
required IrTypeIndex type = 3;
required bool is_var = 4;
required bool is_const = 5;
required bool is_lateinit = 6;
optional IrExpression initializer = 7;
}
enum ClassKind {
CLASS = 1;
INTERFACE = 2;
ENUM_CLASS = 3;
ENUM_ENTRY = 4;
ANNOTATION_CLASS = 5;
OBJECT = 6;
}
enum ModalityKind { // It is ModalityKind to not clash with Modality in descriptor metadata.
FINAL_MODALITY = 1;
SEALED_MODALITY = 2;
OPEN_MODALITY = 3;
ABSTRACT_MODALITY = 4;
}
message IrValueParameter {
required IrSymbol symbol = 1;
required String name = 2;
required int32 index = 3;
required IrTypeIndex type = 4;
optional IrTypeIndex vararg_element_type = 5;
required bool is_crossinline = 6;
required bool is_noinline = 7;
optional IrExpression default_value = 8;
}
message IrTypeParameter {
required IrSymbol symbol = 1;
required String name = 2;
required int32 index = 3;
required IrTypeVariance variance = 4;
repeated IrTypeIndex super_type = 5;
required bool is_reified = 6;
}
message IrTypeParameterContainer {
repeated IrDeclaration type_parameter = 1;
}
message IrClass {
required IrSymbol symbol = 1;
required String name = 2;
required ClassKind kind = 3;
required Visibility visibility = 4;
required ModalityKind modality = 5;
// TODO: consider using flags for the booleans.
required bool is_companion = 6;
required bool is_inner = 7;
required bool is_data = 8;
required bool is_external = 9;
required bool is_inline = 10;
optional IrDeclaration this_receiver = 11;
required IrTypeParameterContainer type_parameters = 12;
required IrDeclarationContainer declaration_container = 13;
repeated IrTypeIndex super_type = 14;
}
message IrEnumEntry {
required IrSymbol symbol = 1;
optional IrExpression initializer = 2;
optional IrDeclaration corresponding_class = 3;
required String name = 4;
}
message IrAnonymousInit {
required IrSymbol symbol = 1;
required IrStatement body = 2;
}
// TODO: we need an extension mechanism to accomodate new
// IR operators in upcoming releases.
message IrDeclarator {
oneof declarator {
IrAnonymousInit ir_anonymous_init = 1;
IrClass ir_class = 2;
IrConstructor ir_constructor = 3;
IrEnumEntry ir_enum_entry = 4;
IrField ir_field = 5;
IrFunction ir_function = 6;
IrProperty ir_property = 7;
IrTypeAlias ir_type_alias = 8;
IrTypeParameter ir_type_parameter = 9;
IrVariable ir_variable = 10;
IrValueParameter ir_value_parameter = 11;
}
}
message IrDeclaration {
required IrDeclarationOrigin origin = 1;
required Coordinates coordinates = 2;
required Annotations annotations = 3;
required IrDeclarator declarator = 4;
}
/* ------- IrStatements --------------------------------------------- */
message IrBranch {
required IrExpression condition = 1;
required IrExpression result = 2;
}
message IrBlockBody {
repeated IrStatement statement = 1;
}
message IrCatch {
required IrDeclaration catch_parameter = 1;
required IrExpression result = 2;
}
enum IrSyntheticBodyKind {
ENUM_VALUES = 1;
ENUM_VALUEOF = 2;
}
message IrSyntheticBody {
required IrSyntheticBodyKind kind = 1;
}
// Let's try to map IrElement as well as IrStatement to IrStatement.
message IrStatement {
required Coordinates coordinates = 1;
oneof statement {
IrDeclaration declaration = 2;
IrExpression expression = 3;
IrBlockBody block_body = 4;
IrBranch branch = 5;
IrCatch catch = 6;
IrSyntheticBody synthetic_body = 7;
}
}
@@ -1,378 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.descriptors.findTopLevelDescriptor
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.backend.konan.ir.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.impl.IrLoopBase
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.konan.KonanSerializerProtocol
class KonanIrModuleDeserializer(
currentModule: ModuleDescriptor,
logger: LoggingContext,
builtIns: IrBuiltIns,
symbolTable: SymbolTable,
val forwardModuleDescriptor: ModuleDescriptor?)
: IrModuleDeserializer(logger, builtIns, symbolTable) {
val deserializedSymbols = mutableMapOf<UniqIdKey, IrSymbol>()
val reachableTopLevels = mutableSetOf<UniqIdKey>()
val deserializedTopLevels = mutableSetOf<UniqIdKey>()
val forwardDeclarations = mutableSetOf<IrSymbol>()
var deserializedModuleDescriptor: ModuleDescriptor? = null
var deserializedModuleProtoSymbolTables = mutableMapOf<ModuleDescriptor, KonanIr.IrSymbolTable>()
var deserializedModuleProtoStringTables = mutableMapOf<ModuleDescriptor, KonanIr.StringTable>()
var deserializedModuleProtoTypeTables = mutableMapOf<ModuleDescriptor, KonanIr.IrTypeTable>()
var deserializedModuleLoops = mutableMapOf<Pair<ModuleDescriptor, Int>, IrLoopBase>()
val resolvedForwardDeclarations = mutableMapOf<UniqIdKey, UniqIdKey>()
val descriptorReferenceDeserializer = DescriptorReferenceDeserializer(currentModule, resolvedForwardDeclarations)
init {
var currentIndex = 0L
builtIns.knownBuiltins.forEach {
require(it is IrFunction)
deserializedSymbols.put(UniqIdKey(null, UniqId(currentIndex, isLocal = false)), it.symbol)
assert(symbolTable.referenceSimpleFunction(it.descriptor) == it.symbol)
currentIndex++
}
}
private fun referenceDeserializedSymbol(proto: KonanIr.IrSymbolData, descriptor: DeclarationDescriptor?): IrSymbol = when (proto.kind) {
KonanIr.IrSymbolKind.ANONYMOUS_INIT_SYMBOL ->
IrAnonymousInitializerSymbolImpl(
descriptor as ClassDescriptor?
?: WrappedClassDescriptor()
)
KonanIr.IrSymbolKind.CLASS_SYMBOL ->
symbolTable.referenceClass(
descriptor as ClassDescriptor?
?: WrappedClassDescriptor()
)
KonanIr.IrSymbolKind.CONSTRUCTOR_SYMBOL ->
symbolTable.referenceConstructor(
descriptor as ClassConstructorDescriptor?
?: WrappedClassConstructorDescriptor()
)
KonanIr.IrSymbolKind.TYPE_PARAMETER_SYMBOL ->
symbolTable.referenceTypeParameter(
descriptor as TypeParameterDescriptor?
?: WrappedTypeParameterDescriptor()
)
KonanIr.IrSymbolKind.ENUM_ENTRY_SYMBOL ->
symbolTable.referenceEnumEntry(
descriptor as ClassDescriptor?
?: WrappedEnumEntryDescriptor()
)
KonanIr.IrSymbolKind.STANDALONE_FIELD_SYMBOL ->
symbolTable.referenceField(WrappedFieldDescriptor())
KonanIr.IrSymbolKind.FIELD_SYMBOL ->
symbolTable.referenceField(
descriptor as PropertyDescriptor?
?: WrappedPropertyDescriptor()
)
KonanIr.IrSymbolKind.FUNCTION_SYMBOL ->
symbolTable.referenceSimpleFunction(
descriptor as FunctionDescriptor?
?: WrappedSimpleFunctionDescriptor()
)
KonanIr.IrSymbolKind.VARIABLE_SYMBOL ->
IrVariableSymbolImpl(
descriptor as VariableDescriptor?
?: WrappedVariableDescriptor()
)
KonanIr.IrSymbolKind.VALUE_PARAMETER_SYMBOL ->
IrValueParameterSymbolImpl(
descriptor as ParameterDescriptor?
?: WrappedValueParameterDescriptor()
)
KonanIr.IrSymbolKind.RECEIVER_PARAMETER_SYMBOL ->
IrValueParameterSymbolImpl(
descriptor as ParameterDescriptor? ?: WrappedReceiverParameterDescriptor()
)
else -> TODO("Unexpected classifier symbol kind: ${proto.kind}")
}
override fun deserializeIrSymbol(proto: KonanIr.IrSymbol): IrSymbol {
val symbolData =
deserializedModuleProtoSymbolTables[deserializedModuleDescriptor]!!.getSymbols(proto.index)
return deserializeIrSymbolData(symbolData)
}
override fun deserializeIrType(proto: KonanIr.IrTypeIndex): IrType {
val typeData =
deserializedModuleProtoTypeTables[deserializedModuleDescriptor]!!.getTypes(proto.index)
return deserializeIrTypeData(typeData)
}
override fun deserializeString(proto: KonanIr.String) =
deserializedModuleProtoStringTables[deserializedModuleDescriptor]!!.getStrings(proto.index)
override fun deserializeLoopHeader(loopIndex: Int, loopBuilder: () -> IrLoopBase) =
deserializedModuleLoops.getOrPut(deserializedModuleDescriptor!! to loopIndex, loopBuilder)
fun deserializeIrSymbolData(proto: KonanIr.IrSymbolData): IrSymbol {
val key = proto.uniqId.uniqIdKey(deserializedModuleDescriptor!!)
val topLevelKey = proto.topLevelUniqId.uniqIdKey(deserializedModuleDescriptor!!)
if (!deserializedTopLevels.contains(topLevelKey)) reachableTopLevels.add(topLevelKey)
val symbol = deserializedSymbols.getOrPut(key) {
val descriptor = if (proto.hasDescriptorReference()) {
deserializeDescriptorReference(proto.descriptorReference)
} else {
null
}
resolvedForwardDeclarations[key]?.let {
if (!deserializedTopLevels.contains(it)) reachableTopLevels.add(it) // Assuming forward declarations are always top levels.
}
referenceDeserializedSymbol(proto, descriptor)
}
if (symbol.descriptor is ClassDescriptor &&
symbol.descriptor !is WrappedDeclarationDescriptor<*> &&
symbol.descriptor.module.isForwardDeclarationModule
) {
forwardDeclarations.add(symbol)
}
return symbol
}
override fun deserializeDescriptorReference(proto: KonanIr.DescriptorReference): DeclarationDescriptor =
descriptorReferenceDeserializer.deserializeDescriptorReference(
deserializeString(proto.packageFqName),
deserializeString(proto.classFqName),
deserializeString(proto.name),
if (proto.hasUniqId()) proto.uniqId.index else null,
isEnumEntry = proto.isEnumEntry,
isEnumSpecial = proto.isEnumSpecial,
isDefaultConstructor = proto.isDefaultConstructor,
isFakeOverride = proto.isFakeOverride,
isGetter = proto.isGetter,
isSetter = proto.isSetter
)
private val ByteArray.codedInputStream: org.jetbrains.kotlin.protobuf.CodedInputStream
get() {
val codedInputStream = org.jetbrains.kotlin.protobuf.CodedInputStream.newInstance(this)
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
return codedInputStream
}
private val reversedFileIndex = mutableMapOf<UniqIdKey, IrFile>()
private val UniqIdKey.moduleOfOrigin get() =
this.moduleDescriptor ?: reversedFileIndex[this]?.packageFragmentDescriptor?.containingDeclaration
private fun deserializeTopLevelDeclaration(uniqIdKey: UniqIdKey): IrDeclaration {
val proto = loadTopLevelDeclarationProto(uniqIdKey)
return deserializeDeclaration(proto, reversedFileIndex[uniqIdKey]!!)
}
private fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId) = moduleDescriptor.konanLibrary!!.irDeclaration(uniqId.index, uniqId.isLocal)
private fun loadTopLevelDeclarationProto(uniqIdKey: UniqIdKey): KonanIr.IrDeclaration {
val stream = reader(uniqIdKey.moduleOfOrigin!!, uniqIdKey.uniqId).codedInputStream
return KonanIr.IrDeclaration.parseFrom(stream, KonanSerializerProtocol.extensionRegistry)
}
private fun findDeserializedDeclarationForDescriptor(descriptor: DeclarationDescriptor): DeclarationDescriptor? {
val topLevelDescriptor = descriptor.findTopLevelDescriptor()
if (topLevelDescriptor.module.isForwardDeclarationModule) return null
if (topLevelDescriptor !is DeserializedClassDescriptor && topLevelDescriptor !is DeserializedCallableMemberDescriptor) {
return null
}
val descriptorUniqId = topLevelDescriptor.getUniqId()
?: error("could not get descriptor uniq id for $topLevelDescriptor")
val uniqId = UniqId(descriptorUniqId.index, isLocal = false)
val topLevelKey = UniqIdKey(topLevelDescriptor.module, uniqId)
// This top level descriptor doesn't have a serialized IR declaration.
if (topLevelKey.moduleOfOrigin == null) return null
reachableTopLevels.add(topLevelKey)
do {
val key = reachableTopLevels.first()
if (deserializedSymbols[key]?.isBound == true ||
// The key.moduleOrigin is null for uniqIds that we haven't seen in any of the library headers.
// Just skip it for now and handle it elsewhere.
key.moduleOfOrigin == null) {
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
continue
}
deserializedModuleDescriptor = key.moduleOfOrigin
val reachable = deserializeTopLevelDeclaration(key)
val file = reversedFileIndex[key]!!
file.declarations.add(reachable)
reachable.patchDeclarationParents(file)
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
} while (reachableTopLevels.isNotEmpty())
return topLevelDescriptor
}
override fun findDeserializedDeclaration(symbol: IrSymbol): IrDeclaration? {
if (!symbol.isBound) {
val topLevelDesecriptor = findDeserializedDeclarationForDescriptor(symbol.descriptor)
if (topLevelDesecriptor == null) return null
}
assert(symbol.isBound) {
"findDeserializedDeclaration: symbol ${symbol} is unbound, descriptor = ${symbol.descriptor}, hash = ${symbol.descriptor.hashCode()}"
}
return symbol.owner as IrDeclaration
}
override fun findDeserializedDeclaration(propertyDescriptor: PropertyDescriptor): IrProperty? {
val topLevelDesecriptor = findDeserializedDeclarationForDescriptor(propertyDescriptor)
if (topLevelDesecriptor == null) return null
return symbolTable.propertyTable[propertyDescriptor]
?: error("findDeserializedDeclaration: property descriptor $propertyDescriptor} is not present in propertyTable after deserialization}")
}
override fun declareForwardDeclarations() {
if (forwardModuleDescriptor == null) return
val packageFragments = forwardDeclarations.map { it.descriptor.findPackage() }.distinct()
// We don't bother making a real IR module here, as we have no need in it any later.
// All we need is just to declare forward declarations in the symbol table
// In case you need a full fledged module, turn the forEach into a map and collect
// produced files into an IrModuleFragment.
packageFragments.forEach { packageFragment ->
val symbol = IrFileSymbolImpl(packageFragment)
val file = IrFileImpl(NaiveSourceBasedFileEntryImpl("forward declarations pseudo-file"), symbol)
val symbols = forwardDeclarations
.filter { !it.isBound }
.filter { it.descriptor.findPackage() == packageFragment }
val declarations = symbols.map {
val classDescriptor = it.descriptor as ClassDescriptor
val declaration = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
classDescriptor,
classDescriptor.modality
) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) }
.also {
it.parent = file
}
declaration
}
file.declarations.addAll(declarations)
}
}
fun deserializeIrFile(fileProto: KonanIr.IrFile, moduleDescriptor: ModuleDescriptor, deseralizationStrategy: DeserializationStrategy): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(
deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = deserializeString(fileProto.fqName).let { if (it == "<root>") FqName.ROOT else FqName(it) }
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
val file = IrFileImpl(fileEntry, symbol, fqName)
fileProto.declarationIdList.forEach {
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reversedFileIndex.put(uniqIdKey, file)
if (deseralizationStrategy == DeserializationStrategy.ALL) {
file.declarations.add(deserializeTopLevelDeclaration(uniqIdKey))
}
}
val annotations = deserializeAnnotations(fileProto.annotations)
file.annotations.addAll(annotations)
if (deseralizationStrategy == DeserializationStrategy.EXPLICITLY_EXPORTED)
fileProto.explicitlyExportedToCompilerList.forEach { deserializeIrSymbol(it) }
return file
}
fun deserializeIrModuleHeader(proto: KonanIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializationStrategy: DeserializationStrategy): IrModuleFragment {
deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
deserializedModuleProtoStringTables.put(moduleDescriptor, proto.stringTable)
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
val files = proto.fileList.map {
deserializeIrFile(it, moduleDescriptor, deserializationStrategy)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null)
return module
}
fun deserializeIrModuleHeader(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializationStrategy: DeserializationStrategy = DeserializationStrategy.ONLY_REFERENCED): IrModuleFragment {
val proto = KonanIr.IrModule.parseFrom(byteArray.codedInputStream, KonanSerializerProtocol.extensionRegistry)
return deserializeIrModuleHeader(proto, moduleDescriptor, deserializationStrategy)
}
}
enum class DeserializationStrategy {
ONLY_REFERENCED,
ALL,
EXPLICITLY_EXPORTED
}
@@ -0,0 +1,24 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.llvm.KonanMangler
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFunction
class KonanIrModuleSerializer(
logger: LoggingContext,
declarationTable: DeclarationTable,
bodiesOnlyForInlines: Boolean = false
) : IrModuleSerializer(logger, declarationTable, KonanMangler, bodiesOnlyForInlines) {
override fun backendSpecificExplicitRoot(declaration: IrFunction) =
declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportForCppRuntime) ||
declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportForCompilerAnnotation)
override fun backendSpecificExplicitRoot(declaration: IrClass) =
declaration.descriptor.annotations.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation)
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.KotlinIrLinker
import org.jetbrains.kotlin.backend.common.serialization.UniqId
import org.jetbrains.kotlin.backend.common.serialization.UniqIdKey
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.SymbolTable
class KonanIrLinker(
currentModule: ModuleDescriptor,
logger: LoggingContext,
builtIns: IrBuiltIns,
symbolTable: SymbolTable,
val forwardModuleDescriptor: ModuleDescriptor?)
: KotlinIrLinker(currentModule, logger, builtIns, symbolTable, forwardModuleDescriptor),
DescriptorUniqIdAware by KonanDescriptorUniqIdAware {
private val forwardDeclarations = mutableSetOf<IrSymbol>()
override val descriptorReferenceDeserializer = KonanDescriptorReferenceDeserializer(currentModule, resolvedForwardDeclarations)
override fun reader(moduleDescriptor: ModuleDescriptor, uniqId: UniqId) = moduleDescriptor.konanLibrary!!.irDeclaration(uniqId.index, uniqId.isLocal)
init {
var currentIndex = 0L
builtIns.knownBuiltins.forEach {
require(it is IrFunction)
deserializedSymbols.put(UniqIdKey(null, UniqId(currentIndex, isLocal = false)), it.symbol)
assert(symbolTable.referenceSimpleFunction(it.descriptor) == it.symbol)
currentIndex++
}
}
}
@@ -5,15 +5,16 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.SerializedIr
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.descriptors.isSerializableExpectClass
import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.backend.konan.library.SerializedIr
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
@@ -20,7 +21,8 @@ import org.jetbrains.kotlin.serialization.konan.SourceFileMap
import org.jetbrains.kotlin.types.KotlinType
internal class KonanSerializerExtension(val context: Context, override val metadataVersion: BinaryVersion,
val sourceFileMap: SourceFileMap, val declarationTable: DeclarationTable) :
val sourceFileMap: SourceFileMap, val declarationTable: DeclarationTable
) :
KotlinSerializerExtensionBase(KonanSerializerProtocol) {
override val stringTable = KonanStringTable()
@@ -28,7 +30,7 @@ internal class KonanSerializerExtension(val context: Context, override val metad
fun uniqId(descriptor: DeclarationDescriptor): KonanProtoBuf.DescriptorUniqId? {
val index = declarationTable.descriptorTable.get(descriptor)
return index?.let { newDescriptorUniqId(it) }
return index?.let { newKonanDescriptorUniqId(it) }
}
override fun serializeType(type: KotlinType, proto: ProtoBuf.Type.Builder) {
@@ -1,108 +0,0 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.ir.isAccessor
import org.jetbrains.kotlin.backend.konan.ir.isGetter
import org.jetbrains.kotlin.backend.konan.ir.isSetter
import org.jetbrains.kotlin.backend.konan.llvm.isExported
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
class DescriptorReferenceSerializer(val declarationTable: DeclarationTable, val serializeString: (String) -> KonanIr.String) {
// Not all exported descriptors are deserialized, some a synthesized anew during metadata deserialization.
// Those created descriptors can't carry the uniqIdIndex, since it is available only for deserialized descriptors.
// So we record the uniq id of some other "discoverable" descriptor for which we know for sure that it will be
// available as deserialized descriptor, plus the path to find the needed descriptor from that one.
fun serializeDescriptorReference(declaration: IrDeclaration): KonanIr.DescriptorReference? {
val descriptor = declaration.descriptor
if (!declaration.isExported() && !((declaration as? IrDeclarationWithVisibility)?.visibility == Visibilities.INVISIBLE_FAKE)) {
return null
}
if (declaration is IrAnonymousInitializer) return null
if (descriptor is ParameterDescriptor || (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) || descriptor is TypeParameterDescriptor) return null
val containingDeclaration = descriptor.containingDeclaration!!
val (packageFqName, classFqName) = when (containingDeclaration) {
is ClassDescriptor -> {
val classId = containingDeclaration.classId ?: return null
Pair(classId.packageFqName.toString(), classId.relativeClassName.toString())
}
is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "")
else -> return null
}
val isAccessor = declaration.isAccessor
val isBackingField = declaration is IrField && declaration.correspondingProperty != null
val isFakeOverride = declaration.origin == IrDeclarationOrigin.FAKE_OVERRIDE
val isDefaultConstructor =
descriptor is ClassConstructorDescriptor && containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.OBJECT
val isEnumEntry = descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY
val isEnumSpecial = declaration.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER
val realDeclaration = if (isFakeOverride) {
when (declaration) {
is IrSimpleFunction -> declaration.resolveFakeOverrideMaybeAbstract()
is IrField -> declaration.resolveFakeOverrideMaybeAbstract()
is IrProperty -> declaration.resolveFakeOverrideMaybeAbstract()
else -> error("Unexpected fake override declaration")
}
} else {
declaration
}
val discoverableDescriptorsDeclaration: IrDeclaration? = if (isAccessor) {
(realDeclaration as IrSimpleFunction).correspondingProperty!!
} else if (isBackingField) {
(realDeclaration as IrField).correspondingProperty!!
} else if (isDefaultConstructor || isEnumEntry) {
null
} else {
realDeclaration
}
val uniqId = discoverableDescriptorsDeclaration?.let { declarationTable.uniqIdByDeclaration(it) }
uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) }
val proto = KonanIr.DescriptorReference.newBuilder()
.setPackageFqName(serializeString(packageFqName))
.setClassFqName(serializeString(classFqName))
.setName(serializeString(descriptor.name.toString()))
if (uniqId != null) proto.setUniqId(protoUniqId(uniqId))
if (isFakeOverride) {
proto.setIsFakeOverride(true)
}
if (isBackingField) {
proto.setIsBackingField(true)
}
if (isAccessor) {
if (declaration.isGetter)
proto.setIsGetter(true)
else if (declaration.isSetter)
proto.setIsSetter(true)
else
error("A property accessor which is neither a getter, nor a setter: $descriptor")
} else if (isDefaultConstructor) {
proto.setIsDefaultConstructor(true)
} else if (isEnumEntry) {
proto.setIsEnumEntry(true)
} else if (isEnumSpecial) {
proto.setIsEnumSpecial(true)
}
return proto.build()
}
}
@@ -5,53 +5,22 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware
import org.jetbrains.kotlin.backend.common.serialization.tryGetExtension
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
// This is an abstract uniqIdIndex any serialized IR declarations gets.
// It is either isLocal and then just gets and ordinary number within its module.
// Or is visible across modules and then gets a hash of mangled name as its index.
data class UniqId (
val index: Long,
val isLocal: Boolean
)
// isLocal=true in UniqId is good while we dealing with a single current module.
// To disambiguate module local declarations of different modules we use UniqIdKey.
// It has moduleDescriptor specified for isLocal=true uniqIds.
data class UniqIdKey private constructor(val uniqId: UniqId, val moduleDescriptor: ModuleDescriptor?) {
constructor(moduleDescriptor: ModuleDescriptor?, uniqId: UniqId)
: this(uniqId, if (uniqId.isLocal) moduleDescriptor!! else null)
object KonanDescriptorUniqIdAware: DescriptorUniqIdAware {
override fun DeclarationDescriptor.getUniqId(): Long? = when (this) {
is DeserializedClassDescriptor -> this.classProto.tryGetExtension(KonanProtoBuf.classUniqId)
is DeserializedSimpleFunctionDescriptor -> this.proto.tryGetExtension(KonanProtoBuf.functionUniqId)
is DeserializedPropertyDescriptor -> this.proto.tryGetExtension(KonanProtoBuf.propertyUniqId)
is DeserializedClassConstructorDescriptor -> this.proto.tryGetExtension(KonanProtoBuf.constructorUniqId)
else -> null
}?.index
}
internal val IrDeclaration.uniqIdIndex: Long
get() = this.uniqSymbolName().localHash.value
fun protoUniqId(uniqId: UniqId): KonanIr.UniqId =
KonanIr.UniqId.newBuilder()
.setIndex(uniqId.index)
.setIsLocal(uniqId.isLocal)
.build()
fun KonanIr.UniqId.uniqId(): UniqId = UniqId(this.index, this.isLocal)
fun KonanIr.UniqId.uniqIdKey(moduleDescriptor: ModuleDescriptor) =
UniqIdKey(moduleDescriptor, this.uniqId())
fun <T, M:GeneratedMessageLite.ExtendableMessage<M>> M.tryGetExtension(extension: GeneratedMessageLite.GeneratedExtension<M, T>)
= if (this.hasExtension(extension)) this.getExtension<T>(extension) else null
fun DeclarationDescriptor.getUniqId(): KonanProtoBuf.DescriptorUniqId? = when (this) {
is DeserializedClassDescriptor -> this.classProto.tryGetExtension(KonanProtoBuf.classUniqId)
is DeserializedSimpleFunctionDescriptor -> this.proto.tryGetExtension(KonanProtoBuf.functionUniqId)
is DeserializedPropertyDescriptor -> this.proto.tryGetExtension(KonanProtoBuf.propertyUniqId)
is DeserializedClassConstructorDescriptor -> this.proto.tryGetExtension(KonanProtoBuf.constructorUniqId)
else -> null
}
fun newDescriptorUniqId(index: Long): KonanProtoBuf.DescriptorUniqId =
fun newKonanDescriptorUniqId(index: Long): KonanProtoBuf.DescriptorUniqId =
KonanProtoBuf.DescriptorUniqId.newBuilder().setIndex(index).build()
@@ -1,72 +0,0 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.ir.fqNameSafe
import org.jetbrains.kotlin.backend.konan.ir.name
import org.jetbrains.kotlin.backend.konan.llvm.extensionReceiverNamePart
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.symbolName
import org.jetbrains.kotlin.backend.konan.llvm.typeInfoSymbolName
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
// This is a little extension over what's used in real mangling
// since some declarations never appear in the bitcode symbols.
internal fun IrDeclaration.uniqSymbolName(): String = when (this) {
is IrFunction
-> this.uniqFunctionName
is IrProperty
-> this.symbolName
is IrClass
-> this.typeInfoSymbolName
is IrField
-> this.symbolName
is IrEnumEntry
-> this.symbolName
else -> error("Unexpected exported declaration: $this")
}
private val IrDeclarationParent.fqNameUnique: FqName
get() = when(this) {
is IrPackageFragment -> this.fqName
is IrDeclaration -> this.parent.fqNameUnique.child(this.uniqName)
else -> error(this)
}
private val IrDeclaration.uniqName: Name
get() = when (this) {
is IrSimpleFunction -> Name.special("<${this.uniqFunctionName}>")
else -> this.name
}
private val IrProperty.symbolName: String
get() {
val extensionReceiver: String = getter!!.extensionReceiverParameter ?. extensionReceiverNamePart ?: ""
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kprop:$containingDeclarationPart$extensionReceiver$name"
}
private val IrEnumEntry.symbolName: String
get() {
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kenumentry:$containingDeclarationPart$name"
}
// This is basicly the same as .symbolName, but disambiguates external functions with the same C name.
// In addition functions appearing in fq sequence appear as <full signature>.
private val IrFunction.uniqFunctionName: String
get() {
val parent = this.parent
val containingDeclarationPart = parent.fqNameUnique.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart#$functionName"
}