Whole module IR serialization/deserialization.

With public descriptors inserted and wrapped ones used instead of the locals.
This commit is contained in:
Alexander Gorshenev
2018-06-14 17:27:03 +03:00
committed by alexander-gorshenev
parent 21852ec2a3
commit cfe153c742
75 changed files with 4500 additions and 2998 deletions
@@ -17,4 +17,4 @@ fun BinaryType<*>.primitiveBinaryTypeOrNull(): PrimitiveBinaryType? = when (this
enum class PrimitiveBinaryType {
BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, POINTER
}
}
@@ -13,6 +13,10 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -224,4 +228,4 @@ internal fun IrBuiltIns.getKotlinClass(cache: BoxCache): IrClass = when (cache)
// TODO: consider adding box caches for unsigned types.
enum class BoxCache {
BOOLEAN, BYTE, SHORT, CHAR, INT, LONG
}
}
@@ -263,6 +263,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
// But we have to wait until the code generation phase,
// to dump this information into generated file.
var serializedLinkData: LinkData? = null
var serializedIr: ByteArray? = null
var dataFlowGraph: ByteArray? = null
@Deprecated("")
@@ -55,7 +55,7 @@ fun IrType.computePrimitiveBinaryTypeOrNull(): PrimitiveBinaryType? =
fun IrType.computeBinaryType(): BinaryType<IrClass> = IrTypeInlineClassesSupport.computeBinaryType(this)
fun IrClass.inlinedClassIsNullable(): Boolean = this.defaultType.makeNullable().getInlinedClass() == this // TODO: optimize
fun IrClass.inlinedClassIsNullable(): Boolean = this.defaultType.makeNullable(false).getInlinedClass() == this // TODO: optimize
fun IrClass.isUsedAsBoxClass(): Boolean = IrTypeInlineClassesSupport.isUsedAsBoxClass(this)
/**
@@ -5,16 +5,20 @@
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.konan.descriptors.isForwardDeclarationModule
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex
import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializationUtil
import org.jetbrains.kotlin.backend.konan.serialization.markBackingFields
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
@@ -62,9 +66,30 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
@Suppress("DEPRECATION")
context.psi2IrGeneratorContext = generatorContext
val symbols = KonanSymbols(context, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper)
val forwardDeclarationsModuleDescriptor = context.moduleDescriptor.allDependencyModules.firstOrNull { it.isForwardDeclarationModule }
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles())
val deserializer = KonanIrModuleDeserializer(
context.moduleDescriptor,
context as LoggingContext,
generatorContext.irBuiltIns,
generatorContext.symbolTable,
forwardDeclarationsModuleDescriptor
)
val irModules = context.moduleDescriptor.allDependencyModules.map {
val library = it.konanLibrary
if (library == null) {
return@map null
}
deserializer.deserializeIrModule(it, library.irHeader)
}.filterNotNull()
val symbols = KonanSymbols(context, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper)
val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer)
irModules.forEach {
it.patchDeclarationParents()
}
context.irModule = module
context.ir.symbols = symbols
@@ -80,10 +105,23 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
phaser.phase(KonanPhase.GEN_SYNTHETIC_FIELDS) {
markBackingFields(context)
}
// TODO: We copy default value expressions from expects to actuals before IR serialization,
// because the current infrastructure doesn't allow us to get them at deserialization stage.
// That equires some design and implementation work.
phaser.phase(KonanPhase.COPY_DEFAULT_VALUES_TO_ACTUAL) {
context.irModule!!.files.forEach(ExpectToActualDefaultValueCopier(context)::lower)
}
context.irModule!!.patchDeclarationParents() // why do we need it?
phaser.phase(KonanPhase.SERIALIZER) {
val serializer = KonanSerializationUtil(context, context.config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!)
val declarationTable = DeclarationTable(context.irModule!!.irBuiltins, DescriptorTable())
val serializedIr = IrModuleSerializer(context, declarationTable/*, onlyForInlines = false*/).serializedIrModule(context.irModule!!)
val serializer = KonanSerializationUtil(context, context.config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable)
context.serializedLinkData =
serializer.serializeModule(context.moduleDescriptor)
serializer.serializeModule(context.moduleDescriptor, serializedIr)
}
phaser.phase(KonanPhase.BACKEND) {
phaser.phase(KonanPhase.LOWER) {
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering
import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.name
import org.jetbrains.kotlin.ir.util.checkDeclarationParents
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols
@@ -64,13 +65,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
irModule.files.forEach(InteropLoweringPart1(context)::lower)
}
val symbolTable = context.ir.symbols.symbolTable
do {
@Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context)
} while (symbolTable.unboundClasses.isNotEmpty())
irModule.patchDeclarationParents()
// validateIrModule(context, irModule) // Temporarily disabled until moving to new IR finished.
@@ -17,6 +17,7 @@ enum class KonanPhase(val description: String,
/* */ PSI_TO_IR("Psi to IR conversion"),
/* */ IR_GENERATOR_PLUGINS("Plugged-in ir generators"),
/* */ GEN_SYNTHETIC_FIELDS("Generate synthetic fields"),
/* */ COPY_DEFAULT_VALUES_TO_ACTUAL("Copy default values from expect to actual declarations"),
/* */ SERIALIZER("Serialize descriptor tree and inline IR bodies", GEN_SYNTHETIC_FIELDS),
/* */ BACKEND("All backend"),
/* ... */ LOWER("IR Lowering"),
@@ -52,11 +53,11 @@ enum class KonanPhase(val description: String,
/* ... ... */ RETURNS_INSERTION("Returns insertion for Unit functions", AUTOBOX, LOWER_COROUTINES, LOWER_ENUMS),
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ BUILD_DFG("Data flow graph building"),
/* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing"),
/* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG),
/* ... ... */ BUILD_DFG("Data flow graph building", enabled = false),
/* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing", enabled = false),
/* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG, enabled = false),
/* ... ... */ ESCAPE_ANALYSIS("Escape analysis", BUILD_DFG, DESERIALIZE_DFG, enabled = false), // TODO: Requires devirtualization.
/* ... ... */ SERIALIZE_DFG("Data flow graph serializing", BUILD_DFG), // TODO: Requires escape analysis.
/* ... ... */ SERIALIZE_DFG("Data flow graph serializing", BUILD_DFG, enabled = false), // TODO: Requires escape analysis.
/* ... ... */ CODEGEN("Code Generation"),
/* ... ... */ C_STUBS("C stubs compilation"),
/* ... ... */ BITCODE_LINKER("Bitcode linking"),
@@ -8,14 +8,16 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.descriptors.findPackageView
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getExternalObjCMethodInfo
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition
@@ -27,8 +29,8 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.supertypes
private val interopPackageName = InteropFqNames.packageName
private val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
internal val interopPackageName = InteropFqNames.packageName
internal val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass"))
internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass"))
private val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod"))
@@ -36,17 +38,30 @@ private val objCConstructorFqName = FqName("kotlinx.cinterop.ObjCConstructor")
private val objCFactoryFqName = interopPackageName.child(Name.identifier("ObjCFactory"))
private val objCBridgeFqName = interopPackageName.child(Name.identifier("ObjCBridge"))
@Deprecated("Use IR version rather than descriptor version")
fun ClassDescriptor.isObjCClass(): Boolean =
this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } &&
this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } && // TODO: this is not cheap. Cache me!
this.containingDeclaration.fqNameSafe != interopPackageName
fun KotlinType.isObjCObjectType(): Boolean =
(this.supertypes() + this).any { TypeUtils.getClassDescriptor(it)?.fqNameSafe == objCObjectFqName }
private fun IrClass.getAllSuperClassifiers(): List<IrClass> =
listOf(this) + this.superTypes.flatMap { (it.classifierOrFail.owner as IrClass).getAllSuperClassifiers() }
internal fun IrClass.isObjCClass() = this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } &&
this.parent.fqNameSafe != interopPackageName
@Deprecated("Use IR version rather than descriptor version")
fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
this.parentsWithSelf.filterIsInstance<ClassDescriptor>().any {
it.annotations.findAnnotation(externalObjCClassFqName) != null
}
fun IrClass.isExternalObjCClass(): Boolean = this.isObjCClass() &&
(this as IrDeclaration).parentDeclarationsWithSelf.filterIsInstance<IrClass>().any {
it.annotations.findAnnotation(externalObjCClassFqName) != null
}
fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().any {
it.fqNameSafe == objCClassFqName
@@ -55,15 +70,27 @@ fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().a
fun FunctionDescriptor.isObjCClassMethod() =
this.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() }
@Deprecated("Use IR version rather than descriptor version")
fun FunctionDescriptor.isExternalObjCClassMethod() =
this.containingDeclaration.let { it is ClassDescriptor && it.isExternalObjCClass() }
internal fun IrFunction.isExternalObjCClassMethod() =
this.parent.let {it is IrClass && it.isExternalObjCClass()}
// Special case: methods from Kotlin Objective-C classes can be called virtually from bridges.
@Deprecated("Use IR version rather than descriptor version")
fun FunctionDescriptor.canObjCClassMethodBeCalledVirtually(overriddenDescriptor: FunctionDescriptor) =
overriddenDescriptor.isOverridable && this.kind.isReal && !this.isExternalObjCClassMethod()
internal fun IrFunction.canObjCClassMethodBeCalledVirtually(overridden: IrFunction) =
overridden.isOverridable && this.origin != IrDeclarationOrigin.FAKE_OVERRIDE && !this.isExternalObjCClassMethod()
@Deprecated("Use IR version rather than descriptor version")
fun ClassDescriptor.isKotlinObjCClass(): Boolean = this.isObjCClass() && !this.isExternalObjCClass()
fun IrClass.isKotlinObjCClass(): Boolean = this.isObjCClass() && !this.isExternalObjCClass()
data class ObjCMethodInfo(val bridge: FunctionDescriptor,
val selector: String,
val encoding: String,
@@ -97,6 +124,20 @@ private fun objCMethodInfoByBridge(packageView: PackageViewDescriptor, bridgeNam
)
}
fun IrSimpleFunction.objCMethodArgValue(argName: String): String? {
val methodAnnotation = this.annotations.findAnnotation(objCMethodFqName) ?: return null
methodAnnotation.symbol.owner.valueParameters.forEachIndexed { index, parameter ->
if (parameter.name.asString() == argName) {
val bridgeArgument = methodAnnotation.getValueArgument(index) as IrConst<kotlin.String>
return bridgeArgument.value
}
}
return null
}
fun IrSimpleFunction.hasObjCMethodAnnotation() =
this.annotations.findAnnotation(objCMethodFqName) != null
/**
* @param onlyExternal indicates whether to accept overriding methods from Kotlin classes
*/
@@ -183,6 +224,19 @@ class ObjCOverridabilityCondition : ExternalOverridabilityCondition {
}
fun IrConstructor.objCConstructorIsDesignated(): Boolean {
val annotation = this.annotations.findAnnotation(objCConstructorFqName)!!
for (index in 0 until annotation.valueArgumentsCount) {
val parameter = annotation.symbol.owner.valueParameters[index]
if (parameter.name == Name.identifier("designated")) {
val actual = annotation.getValueArgument(index) as IrConst<kotlin.Boolean>
return actual.value
}
}
error("Could not find 'designated' argument")
}
@Deprecated("Use IR version rather than descriptor version")
fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean {
val annotation = this.annotations.findAnnotation(objCConstructorFqName)!!
val value = annotation.allValueArguments[Name.identifier("designated")]!!
@@ -190,6 +244,7 @@ fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean {
return (value as BooleanValue).value
}
fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? {
return this.annotations.findAnnotation(objCConstructorFqName)?.let {
val initSelector = it.getStringValue("initSelector")
@@ -199,7 +254,7 @@ fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? {
}
}
fun IrConstructor.isObjCConstructor(): Boolean = this.descriptor.annotations.hasAnnotation(objCConstructorFqName)
val IrConstructor.isObjCConstructor get() = this.descriptor.annotations.hasAnnotation(objCConstructorFqName)
fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
return this.descriptor.annotations.findAnnotation(objCConstructorFqName)?.let {
@@ -210,6 +265,10 @@ fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
}
}
val IrFunction.hasObjCFactoryAnnotation get() = this.descriptor.annotations.hasAnnotation(objCFactoryFqName)
val IrFunction.hasObjCMethodAnnotation get() = this.descriptor.annotations.hasAnnotation(objCMethodFqName)
fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? {
val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null
val bridgeName = factoryAnnotation.getStringValue("bridge")
@@ -12,11 +12,12 @@ import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions
internal class OverriddenFunctionDescriptor(
val descriptor: SimpleFunctionDescriptor,
overriddenDescriptor: SimpleFunctionDescriptor
val descriptor: IrSimpleFunction,
overriddenDescriptor: IrSimpleFunction
) {
val overriddenDescriptor = overriddenDescriptor.original
@@ -40,7 +41,7 @@ internal class OverriddenFunctionDescriptor(
&& descriptor.target.overrides(overriddenDescriptor)
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()
fun getImplementation(context: Context): SimpleFunctionDescriptor? {
fun getImplementation(context: Context): IrSimpleFunction? {
val target = descriptor.target
val implementation = if (!needBridge)
target
@@ -154,7 +155,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.uniqueId }
}
fun vtableIndex(function: SimpleFunctionDescriptor): Int {
fun vtableIndex(function: IrSimpleFunction): Int {
val bridgeDirections = function.target.bridgeDirectionsTo(function.original)
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString())
@@ -170,7 +171,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
// TODO: probably method table should contain all accessible methods to improve binary compatibility
}
private val IrClass.sortedOverridableOrOverridingMethods: List<SimpleFunctionDescriptor>
private val IrClass.sortedOverridableOrOverridingMethods: List<IrSimpleFunction>
get() =
this.simpleFunctions()
.filter { (it.isOverridable || it.overriddenSymbols.isNotEmpty())
@@ -5,15 +5,18 @@
package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ConstructorDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.DeclarationDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.konan.isInlined
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.types.SimpleType
@@ -37,7 +40,7 @@ internal val ClassDescriptor.implementedInterfaces: List<ClassDescriptor>
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction {
internal fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimpleFunction {
if (this.isReal) {
return this
}
@@ -72,7 +75,7 @@ internal fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction {
realSupers.toList().forEach { excludeOverridden(it) }
}
return realSupers.first { it.modality != Modality.ABSTRACT }
return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT }
}
// TODO: don't forget to remove descriptor access here.
@@ -131,11 +134,11 @@ private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index:
internal fun FunctionDescriptor.needBridgeTo(target: FunctionDescriptor)
= (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) }
internal val SimpleFunctionDescriptor.target: SimpleFunctionDescriptor
internal val IrSimpleFunction.target: IrSimpleFunction
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
internal val FunctionDescriptor.target: FunctionDescriptor get() = when (this) {
is SimpleFunctionDescriptor -> this.target
is IrSimpleFunction -> this.target
is ConstructorDescriptor -> this
else -> error(this)
}
@@ -185,11 +188,11 @@ internal class BridgeDirections(val array: Array<BridgeDirection>) {
}
}
val SimpleFunctionDescriptor.allOverriddenDescriptors: Set<SimpleFunctionDescriptor>
val IrSimpleFunction.allOverriddenDescriptors: Set<IrSimpleFunction>
get() {
val result = mutableSetOf<SimpleFunctionDescriptor>()
val result = mutableSetOf<IrSimpleFunction>()
fun traverse(function: SimpleFunctionDescriptor) {
fun traverse(function: IrSimpleFunction) {
if (function in result) return
result += function
function.overriddenSymbols.forEach { traverse(it.owner) }
@@ -200,8 +203,8 @@ val SimpleFunctionDescriptor.allOverriddenDescriptors: Set<SimpleFunctionDescrip
return result
}
internal fun SimpleFunctionDescriptor.bridgeDirectionsTo(
overriddenDescriptor: SimpleFunctionDescriptor
internal fun IrSimpleFunction.bridgeDirectionsTo(
overriddenDescriptor: IrSimpleFunction
): BridgeDirections {
val ourDirections = BridgeDirections(this.valueParameters.size)
for (index in ourDirections.array.indices)
@@ -225,4 +228,24 @@ tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescrip
}
fun FunctionDescriptor.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean =
this in map.values
this in map.values
val IrDeclaration.isPropertyAccessor get() =
this is IrSimpleFunction && this.correspondingProperty != null
val IrDeclaration.isPropertyField get() =
this is IrField && this.correspondingProperty != null
val IrDeclaration.isTopLevelDeclaration get() =
parent !is IrDeclaration && !this.isPropertyAccessor && !this.isPropertyField
fun IrDeclaration.findTopLevelDeclaration(): IrDeclaration = when {
this.isTopLevelDeclaration ->
this
this.isPropertyAccessor ->
(this as IrSimpleFunction).correspondingProperty!!.findTopLevelDeclaration()
this.isPropertyField ->
(this as IrField).correspondingProperty!!.findTopLevelDeclaration()
else ->
(this.parent as IrDeclaration).findTopLevelDeclaration()
}
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.konan.RuntimeNames
import org.jetbrains.kotlin.backend.konan.binaryTypeIsReference
import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.backend.konan.serialization.isExported
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType
@@ -20,12 +19,18 @@ import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.konanModuleOrigin
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isKFunction
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -44,7 +49,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(allowAbstract: Boolean = false): T {
if (this.kind.isReal) {
return this
} else {
@@ -52,7 +57,7 @@ internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST")
return filtered.first { it.modality != Modality.ABSTRACT } as T
return filtered.first { allowAbstract || it.modality != Modality.ABSTRACT } as T
}
}
@@ -86,6 +91,15 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean
this.isOperator && this.name == OperatorNameConventions.INVOKE
}
internal val IrFunction.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isKFunction())
return dispatchReceiver.type.isFunction() &&
/* this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE
}
internal fun ClassDescriptor.isUnit() = this.defaultType.isUnit()
internal fun ClassDescriptor.isNothing() = this.defaultType.isNothing()
@@ -159,9 +173,6 @@ internal val FunctionDescriptor.needsInlining: Boolean
return (this.isInline && !this.isExternal)
}
internal val FunctionDescriptor.needsSerializedIr: Boolean
get() = (this.needsInlining && this.isExported())
fun AnnotationDescriptor.getStringValueOrNull(name: String): String? {
val constantValue = this.allValueArguments.entries.atMostOne {
it.key.asString() == name
@@ -199,6 +210,9 @@ val ClassDescriptor.enumEntries: List<ClassDescriptor>
internal val DeclarationDescriptor.isExpectMember: Boolean
get() = this is MemberDescriptor && this.isExpect
internal val DeclarationDescriptor.isSerializableExpectClass: Boolean
get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this)
internal fun KotlinType?.createExtensionReceiver(owner: CallableDescriptor): ReceiverParameterDescriptor? =
DescriptorFactory.createExtensionReceiverParameterForCallable(
owner,
@@ -286,3 +300,5 @@ fun createAnnotation(
values.map { (name, value) -> Name.identifier(name) to StringValue(value) }.toMap(),
SourceElement.NO_SOURCE
)
val ModuleDescriptor.konanLibrary get() = (this.konanModuleOrigin as? DeserializedKonanModuleOrigin)?.library
@@ -8,8 +8,7 @@ package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
val DeserializedPropertyDescriptor.konanBackingField: PropertyDescriptor?
get() =
@@ -48,4 +47,10 @@ internal val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCall
internal val CallableMemberDescriptor.isDeserializableCallable
get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor)
fun DeclarationDescriptor.findTopLevelDescriptor(): DeclarationDescriptor {
return if (this.containingDeclaration is org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor) this.propertyIfAccessor
else this.containingDeclaration!!.findTopLevelDescriptor()
}
val ModuleDescriptor.isForwardDeclarationModule get() =
name == Name.special("<forward declarations>")
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
import org.jetbrains.kotlin.backend.common.RenderIrElementWithDescriptorsVisitor.Companion.DECLARATION_RENDERER
import org.jetbrains.kotlin.backend.common.descriptors.WrappedDeclarationDescriptor
import org.jetbrains.kotlin.backend.common.ir.Ir
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.konan.*
@@ -19,10 +21,13 @@ import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
@@ -30,13 +35,20 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.StringWriter
import kotlin.properties.Delegates
// This is what Context collects about IR.
@@ -462,7 +474,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
val getClassTypeInfo = internalFunction("getClassTypeInfo")
val getObjectTypeInfo = internalFunction("getObjectTypeInfo")
val kClassImpl = internalClass("KClassImpl")
@@ -537,3 +548,634 @@ private fun getArrayListClassDescriptor(context: Context): ClassDescriptor {
return classifier as ClassDescriptor
}
fun IrElement.render() = accept(RenderIrElementVisitor(), null)
fun IrType.render() =
originalKotlinType?.let {
DECLARATION_RENDERER.renderType(it)
} ?: DECLARATION_RENDERER.renderType(this.toKotlinType())
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
override fun visitElement(element: IrElement, data: Nothing?): String =
"? ${element::class.java.simpleName}"
override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String =
"? ${declaration::class.java.simpleName} ${declaration.descriptor.ref()}"
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): String =
"MODULE_FRAGMENT name:${declaration.name}"
override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment, data: Nothing?): String =
"EXTERNAL_PACKAGE_FRAGMENT fqName:${declaration.fqName}"
override fun visitFile(declaration: IrFile, data: Nothing?): String =
"FILE fqName:${declaration.fqName} fileName:${declaration.name}"
override fun visitFunction(declaration: IrFunction, data: Nothing?): String =
"FUN ${declaration.renderOriginIfNonTrivial()}${declaration.renderDeclared()}"
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: Nothing?): String =
declaration.run {
"FUN ${renderOriginIfNonTrivial()}" +
//"name:$name visibility:$visibility modality:$modality " +
"name:$name $descriptor $symbol visibility:$visibility modality:$modality " +
renderTypeParameters() + " " +
renderValueParameterTypes() + " " +
"returnType:${returnType.render()} " +
"flags:${renderSimpleFunctionFlags()}"
}
private fun renderFlagsList(vararg flags: String?) =
flags.filterNotNull().joinToString(separator = ",")
private fun IrSimpleFunction.renderSimpleFunctionFlags(): String =
renderFlagsList(
"tailrec".takeIf { isTailrec },
"inline".takeIf { isInline },
"external".takeIf { isExternal },
"suspend".takeIf { isSuspend }
)
private fun IrFunction.renderTypeParameters(): String =
typeParameters.joinToString(separator = ", ", prefix = "<", postfix = ">") { it.name.toString() }
private fun IrFunction.renderValueParameterTypes(): String =
ArrayList<String>().apply {
addIfNotNull(dispatchReceiverParameter?.run { "\$this:${type.render()}" })
addIfNotNull(extensionReceiverParameter?.run { "\$receiver:${type.render()}" })
valueParameters.mapTo(this) { "${it.name}:${it.type.render()}" }
}.joinToString(separator = ", ", prefix = "(", postfix = ")")
override fun visitConstructor(declaration: IrConstructor, data: Nothing?): String =
declaration.run {
"CONSTRUCTOR ${renderOriginIfNonTrivial()}" +
"visibility:$visibility " +
renderTypeParameters() + " " +
renderValueParameterTypes() + " " +
"returnType:${returnType.render()} " +
"flags:${renderConstructorFlags()}"
}
private fun IrConstructor.renderConstructorFlags() =
renderFlagsList(
"inline".takeIf { isInline },
"external".takeIf { isExternal },
"primary".takeIf { isPrimary }
)
override fun visitProperty(declaration: IrProperty, data: Nothing?): String =
declaration.run {
"PROPERTY ${renderOriginIfNonTrivial()}" +
"name:$name visibility:$visibility modality:$modality " +
"flags:${renderPropertyFlags()}"
}
private fun IrProperty.renderPropertyFlags() =
renderFlagsList(
"external".takeIf { isExternal },
"const".takeIf { isConst },
"lateinit".takeIf { isLateinit },
"delegated".takeIf { isDelegated },
if (isVar) "var" else "val"
)
override fun visitField(declaration: IrField, data: Nothing?): String =
"FIELD ${declaration.renderOriginIfNonTrivial()}" +
"name:${declaration.name} type:${declaration.type.render()} visibility:${declaration.visibility} " +
"flags:${declaration.renderFieldFlags()}"
private fun IrField.renderFieldFlags() =
renderFlagsList(
"final".takeIf { isFinal },
"external".takeIf { isExternal },
"static".takeIf { isStatic }
)
override fun visitClass(declaration: IrClass, data: Nothing?): String =
declaration.run {
"CLASS ${renderOriginIfNonTrivial()}" +
"$kind name:$name modality:$modality visibility:$visibility " +
"flags:${renderClassFlags()} " +
"superTypes:[${superTypes.joinToString(separator = "; ") { it.render() }}]"
}
private fun IrClass.renderClassFlags() =
renderFlagsList(
"companion".takeIf { isCompanion },
"inner".takeIf { isInner },
"data".takeIf { isData },
"external".takeIf { isExternal },
"inline".takeIf { isInline }
)
override fun visitTypeAlias(declaration: IrTypeAlias, data: Nothing?): String =
"TYPEALIAS ${declaration.renderOriginIfNonTrivial()}${declaration.descriptor.ref()} " +
"type=${declaration.descriptor.underlyingType.render()}"
override fun visitVariable(declaration: IrVariable, data: Nothing?): String =
"VAR ${declaration.renderOriginIfNonTrivial()}" +
"name:${declaration.name} type:${declaration.type.render()} flags:${declaration.renderVariableFlags()}"
private fun IrVariable.renderVariableFlags(): String =
renderFlagsList(
"const".takeIf { isConst },
"lateinit".takeIf { isLateinit },
if (isVar) "var" else "val"
)
override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String =
"ENUM_ENTRY ${declaration.renderOriginIfNonTrivial()}name:${declaration.name}"
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): String =
"ANONYMOUS_INITIALIZER ${declaration.descriptor.ref()}"
override fun visitTypeParameter(declaration: IrTypeParameter, data: Nothing?): String =
declaration.run {
"TYPE_PARAMETER ${renderOriginIfNonTrivial()}" +
"name:$name index:$index variance:$variance " +
"superTypes:[${superTypes.joinToString(separator = "; ") { it.render() }}]"
}
override fun visitValueParameter(declaration: IrValueParameter, data: Nothing?): String =
declaration.run {
"VALUE_PARAMETER ${renderOriginIfNonTrivial()}" +
"name:$name " +
(if (index >= 0) "index:$index " else "") +
"type:${type.render()} " +
(varargElementType?.let { "varargElementType:${it.render()} " } ?: "") +
"flags:${renderValueParameterFlags()}"
}
private fun IrValueParameter.renderValueParameterFlags(): String =
renderFlagsList(
"vararg".takeIf { varargElementType != null },
"crossinline".takeIf { isCrossinline },
"noinline".takeIf { isNoinline }
)
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String =
declaration.run {
"LOCAL_DELEGATED_PROPERTY ${declaration.renderOriginIfNonTrivial()}" +
"name:$name type:${type.render()} flags:${renderLocalDelegatedPropertyFlags()}"
}
private fun IrLocalDelegatedProperty.renderLocalDelegatedPropertyFlags() =
if (isVar) "var" else "val"
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
"EXPRESSION_BODY"
override fun visitBlockBody(body: IrBlockBody, data: Nothing?): String =
"BLOCK_BODY"
override fun visitSyntheticBody(body: IrSyntheticBody, data: Nothing?): String =
"SYNTHETIC_BODY kind=${body.kind}"
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
"? ${expression::class.java.simpleName} type=${expression.type.render()}"
override fun <T> visitConst(expression: IrConst<T>, data: Nothing?): String =
"CONST ${expression.kind} type=${expression.type.render()} value=${expression.value}"
override fun visitVararg(expression: IrVararg, data: Nothing?): String =
"VARARG type=${expression.type.render()} varargElementType=${expression.varargElementType.render()}"
override fun visitSpreadElement(spread: IrSpreadElement, data: Nothing?): String =
"SPREAD_ELEMENT"
override fun visitBlock(expression: IrBlock, data: Nothing?): String =
if (expression is IrReturnableBlock)
"RETURNABLE_BLOCK type=${expression.type.render()} origin=${expression.origin} function=name:${expression.symbol.descriptor.name} ${expression.symbol.descriptor} ${expression.symbol}"
else "BLOCK type=${expression.type.render()} origin=${expression.origin}"
override fun visitComposite(expression: IrComposite, data: Nothing?): String =
"COMPOSITE type=${expression.type.render()} origin=${expression.origin}"
override fun visitReturn(expression: IrReturn, data: Nothing?): String =
"RETURN type=${expression.type.render()} from='name=${expression.returnTarget.name} ${expression.returnTarget/*.ref()*/} ${expression.returnTargetSymbol}'"
override fun visitCall(expression: IrCall, data: Nothing?): String =
"CALL '${expression.descriptor/*.ref()*/} ${expression.descriptor} ${expression.symbol}' ${expression.renderSuperQualifier()}" +
"type=${expression.type.render()} origin=${expression.origin}"
private fun IrCall.renderSuperQualifier(): String =
superQualifier?.let { "superQualifier=${it.name} " } ?: ""
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): String =
"DELEGATING_CONSTRUCTOR_CALL '${expression.descriptor.ref()}'"
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): String =
"ENUM_CONSTRUCTOR_CALL '${expression.descriptor.ref()}'"
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: Nothing?): String =
"INSTANCE_INITIALIZER_CALL classDescriptor='${expression.classDescriptor.ref()}'"
override fun visitGetValue(expression: IrGetValue, data: Nothing?): String =
"GET_VAR '${expression.descriptor.ref()}' /*${expression.symbol.owner} ${expression.symbol.owner.hashCode()} ${expression.descriptor} ${expression.descriptor.hashCode()} */ type=${expression.type.render()} origin=${expression.origin}"
override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): String =
"SET_VAR '${expression.descriptor.ref()}' type=${expression.type.render()} origin=${expression.origin}"
override fun visitGetField(expression: IrGetField, data: Nothing?): String =
"GET_FIELD '${expression.descriptor.ref()}' type=${expression.type.render()} origin=${expression.origin}"
override fun visitSetField(expression: IrSetField, data: Nothing?): String =
"SET_FIELD '${expression.descriptor.ref()}' type=${expression.type.render()} origin=${expression.origin}"
override fun visitGetObjectValue(expression: IrGetObjectValue, data: Nothing?): String =
"GET_OBJECT '${expression.descriptor.ref()}' type=${expression.type.render()}"
override fun visitGetEnumValue(expression: IrGetEnumValue, data: Nothing?): String =
"GET_ENUM '${expression.descriptor.ref()}' type=${expression.type.render()}"
override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): String =
"STRING_CONCATENATION type=${expression.type.render()}"
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Nothing?): String =
"TYPE_OP type=${expression.type.render()} origin=${expression.operator} typeOperand=${expression.typeOperand.render()}"
override fun visitWhen(expression: IrWhen, data: Nothing?): String =
"WHEN type=${expression.type.render()} origin=${expression.origin}"
override fun visitBranch(branch: IrBranch, data: Nothing?): String =
"BRANCH"
override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): String =
"WHILE label=${loop.label} origin=${loop.origin}"
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): String =
"DO_WHILE label=${loop.label} origin=${loop.origin}"
override fun visitBreak(jump: IrBreak, data: Nothing?): String =
"BREAK label=${jump.label} loop.label=${jump.loop.label}"
override fun visitContinue(jump: IrContinue, data: Nothing?): String =
"CONTINUE label=${jump.label} loop.label=${jump.loop.label}"
override fun visitThrow(expression: IrThrow, data: Nothing?): String =
"THROW type=${expression.type.render()}"
override fun visitFunctionReference(expression: IrFunctionReference, data: Nothing?): String =
"FUNCTION_REFERENCE 'name=${expression.descriptor.name/*.ref()*/} ${expression.descriptor} ${expression.symbol}' type=${expression.type.render()} origin=${expression.origin}"
override fun visitPropertyReference(expression: IrPropertyReference, data: Nothing?): String =
buildString {
append("PROPERTY_REFERENCE ")
append("'${expression.descriptor.ref()}' ")
appendNullableAttribute("field=", expression.field) { "'${it.descriptor.ref()}'" }
appendNullableAttribute("getter=", expression.getter) { "'${it.descriptor.ref()}'" }
appendNullableAttribute("setter=", expression.setter) { "'${it.descriptor.ref()}'" }
append("type=${expression.type.render()} ")
append("origin=${expression.origin}")
}
private inline fun <T : Any> StringBuilder.appendNullableAttribute(prefix: String, value: T?, toString: (T) -> String) {
append(prefix)
if (value != null) {
append(toString(value))
} else {
append("null")
}
append(" ")
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference, data: Nothing?): String =
buildString {
append("LOCAL_DELEGATED_PROPERTY_REFERENCE ")
append("'${expression.descriptor.ref()}' ")
append("delegate='${expression.delegate.descriptor.ref()}' ")
append("getter='${expression.getter.descriptor.ref()}' ")
appendNullableAttribute("setter=", expression.setter) { "'${it.descriptor.ref()}'" }
append("type=${expression.type.render()} ")
append("origin=${expression.origin}")
}
override fun visitClassReference(expression: IrClassReference, data: Nothing?): String =
"CLASS_REFERENCE '${expression.descriptor.ref()}' type=${expression.type.render()}"
override fun visitGetClass(expression: IrGetClass, data: Nothing?): String =
"GET_CLASS type=${expression.type.render()}"
override fun visitTry(aTry: IrTry, data: Nothing?): String =
"TRY type=${aTry.type.render()}"
override fun visitCatch(aCatch: IrCatch, data: Nothing?): String =
"CATCH parameter=${aCatch.parameter.ref()}"
override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String =
"ERROR_DECL ${declaration.descriptor::class.java.simpleName} ${declaration.descriptor.ref()}"
override fun visitErrorExpression(expression: IrErrorExpression, data: Nothing?): String =
"ERROR_EXPR '${expression.description}' type=${expression.type.render()}"
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String =
"ERROR_CALL '${expression.description}' type=${expression.type.render()}"
companion object {
val DECLARATION_RENDERER = DescriptorRenderer.withOptions {
withDefinedIn = false
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE
includePropertyConstant = true
classifierNamePolicy = ClassifierNamePolicy.FULLY_QUALIFIED
verbose = false
modifiers = DescriptorRendererModifier.ALL
}
val REFERENCE_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES
internal fun IrDeclaration.name(): String =
descriptor.name.toString()
internal fun DescriptorRenderer.renderDescriptor(descriptor: DeclarationDescriptor): String =
if (descriptor is ReceiverParameterDescriptor)
"this@${if (descriptor is WrappedDeclarationDescriptor<*>) "Wrapped" else descriptor.containingDeclaration.name}: ${if (descriptor is WrappedDeclarationDescriptor<*>) "Wrapped" else descriptor.type}"
else
render(descriptor)
internal fun IrDeclaration.renderDeclared(): String =
DECLARATION_RENDERER.renderDescriptor(this.descriptor)
internal fun DeclarationDescriptor.ref(): String =
REFERENCE_RENDERER.renderDescriptor(this)
internal fun KotlinType.render(): String =
DECLARATION_RENDERER.renderType(this)
internal fun IrDeclaration.renderOriginIfNonTrivial(): String =
if (origin != IrDeclarationOrigin.DEFINED) origin.toString() + " " else ""
}
}
class DumpIrTreeVizitor(out: Appendable) : IrElementVisitor<Unit, String> {
private val printer = Printer(out, " ")
private val elementRenderer = RenderIrElementVisitor()
companion object {
val ANNOTATIONS_RENDERER = DescriptorRenderer.withOptions {
verbose = true
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
}
}
override fun visitElement(element: IrElement, data: String) {
element.dumpLabeledElementWith(data) {
if (element is IrAnnotationContainer) {
dumpAnnotations(element)
}
element.acceptChildren(this@DumpIrTreeVizitor, "")
}
}
override fun visitModuleFragment(declaration: IrModuleFragment, data: String) {
declaration.dumpLabeledElementWith(data) {
declaration.files.dumpElements()
}
}
override fun visitFile(declaration: IrFile, data: String) {
declaration.dumpLabeledElementWith(data) {
declaration.fileAnnotations.dumpItemsWith("fileAnnotations") {
ANNOTATIONS_RENDERER.renderAnnotation(it)
}
dumpAnnotations(declaration)
declaration.declarations.dumpElements()
}
}
override fun visitClass(declaration: IrClass, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
declaration.thisReceiver?.accept(this, "\$this")
declaration.typeParameters.dumpElements()
declaration.declarations.dumpElements()
}
}
override fun visitTypeParameter(declaration: IrTypeParameter, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
}
}
override fun visitSimpleFunction(declaration: IrSimpleFunction, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
declaration.correspondingProperty?.dumpInternal("correspondingProperty")
declaration.overriddenSymbols.dumpItems<IrSymbol>("overridden") {
it.dumpDeclarationElementOrDescriptor()
}
declaration.typeParameters.dumpElements()
declaration.dispatchReceiverParameter?.accept(this, "\$this")
declaration.extensionReceiverParameter?.accept(this, "\$receiver")
declaration.valueParameters.dumpElements()
declaration.body?.accept(this, "")
}
}
private fun dumpAnnotations(element: IrAnnotationContainer) {
element.annotations.dumpItems("annotations") {
element.annotations.dumpElements()
}
}
private fun IrSymbol.dumpDeclarationElementOrDescriptor(label: String? = null) {
when {
isBound ->
owner.dumpInternal(label)
label != null ->
printer.println("$label: ", "UNBOUND: ", DescriptorRenderer.COMPACT.render(descriptor))
else ->
printer.println("UNBOUND: ", DescriptorRenderer.COMPACT.render(descriptor))
}
}
override fun visitConstructor(declaration: IrConstructor, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
declaration.typeParameters.dumpElements()
declaration.dispatchReceiverParameter?.accept(this, "\$outer")
declaration.valueParameters.dumpElements()
declaration.body?.accept(this, "")
}
}
override fun visitProperty(declaration: IrProperty, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
declaration.backingField?.accept(this, "")
declaration.getter?.accept(this, "")
declaration.setter?.accept(this, "")
}
}
override fun visitField(declaration: IrField, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
declaration.overriddenSymbols.dumpItems("overridden") {
it.dumpDeclarationElementOrDescriptor()
}
declaration.initializer?.accept(this, "")
}
}
private fun List<IrElement>.dumpElements() {
forEach { it.accept(this@DumpIrTreeVizitor, "") }
}
override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: String) {
expression.dumpLabeledElementWith(data) {
expression.explicitReceiver?.accept(this, "receiver")
expression.arguments.dumpElements()
}
}
override fun visitEnumEntry(declaration: IrEnumEntry, data: String) {
declaration.dumpLabeledElementWith(data) {
dumpAnnotations(declaration)
declaration.initializerExpression?.accept(this, "init")
declaration.correspondingClass?.accept(this, "class")
}
}
override fun visitMemberAccess(expression: IrMemberAccessExpression, data: String) {
expression.dumpLabeledElementWith(data) {
dumpTypeArguments(expression)
expression.dispatchReceiver?.accept(this, "\$this")
expression.extensionReceiver?.accept(this, "\$receiver")
for (valueParameter in expression.descriptor.valueParameters) {
expression.getValueArgument(valueParameter.index)?.accept(this, valueParameter.name.asString())
}
}
}
private fun dumpTypeArguments(expression: IrMemberAccessExpression) {
for (index in 0 until expression.typeArgumentsCount) {
printer.println(
"${expression.descriptor.renderTypeParameter(index)}: ${expression.renderTypeArgument(index)}"
)
}
}
private fun CallableDescriptor.renderTypeParameter(index: Int): String {
val typeParameter = original.typeParameters.getOrNull(index)
return if (typeParameter != null)
DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(typeParameter)
else
"<`$index>"
}
private fun IrMemberAccessExpression.renderTypeArgument(index: Int): String =
getTypeArgument(index)?.render() ?: "<none>"
override fun visitGetField(expression: IrGetField, data: String) {
expression.dumpLabeledElementWith(data) {
expression.receiver?.accept(this, "receiver")
}
}
override fun visitSetField(expression: IrSetField, data: String) {
expression.dumpLabeledElementWith(data) {
expression.receiver?.accept(this, "receiver")
expression.value.accept(this, "value")
}
}
override fun visitWhen(expression: IrWhen, data: String) {
expression.dumpLabeledElementWith(data) {
expression.branches.dumpElements()
}
}
override fun visitBranch(branch: IrBranch, data: String) {
branch.dumpLabeledElementWith(data) {
branch.condition.accept(this, "if")
branch.result.accept(this, "then")
}
}
override fun visitWhileLoop(loop: IrWhileLoop, data: String) {
loop.dumpLabeledElementWith(data) {
loop.condition.accept(this, "condition")
loop.body?.accept(this, "body")
}
}
override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: String) {
loop.dumpLabeledElementWith(data) {
loop.body?.accept(this, "body")
loop.condition.accept(this, "condition")
}
}
override fun visitTry(aTry: IrTry, data: String) {
aTry.dumpLabeledElementWith(data) {
aTry.tryResult.accept(this, "try")
aTry.catches.dumpElements()
aTry.finallyExpression?.accept(this, "finally")
}
}
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: String) {
expression.dumpLabeledElementWith(data) {
expression.typeOperandClassifier.dumpDeclarationElementOrDescriptor("typeOperand")
expression.acceptChildren(this, "")
}
}
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
printer.println(accept(elementRenderer, null).withLabel(label))
indented(body)
}
private inline fun <T> Collection<T>.dumpItems(caption: String, renderElement: (T) -> Unit) {
if (isEmpty()) return
indented(caption) {
forEach {
renderElement(it)
}
}
}
private inline fun <T> Collection<T>.dumpItemsWith(caption: String, renderElement: (T) -> String) {
if (isEmpty()) return
indented(caption) {
forEach {
printer.println(renderElement(it))
}
}
}
private fun IrElement.dumpInternal(label: String? = null) {
if (label != null) {
printer.println("$label: ", accept(elementRenderer, null))
} else {
printer.println(accept(elementRenderer, null))
}
}
private inline fun indented(label: String, body: () -> Unit) {
printer.println("$label:")
indented(body)
}
private inline fun indented(body: () -> Unit) {
printer.pushIndent()
body()
printer.popIndent()
}
private fun String.withLabel(label: String) =
if (label.isEmpty()) this else "$label: $this"
}
fun ir2stringWholezzz(ir: IrElement?): String {
val strWriter = StringWriter()
ir?.accept(DumpIrTreeVizitor(strWriter), "")
return strWriter.toString()
}
@@ -86,10 +86,13 @@ class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.F
//-------------------------------------------------------------------------//
override val maxOffset: Int
get() = TODO("not implemented")
//get() = TODO("not implemented")
get() = UNDEFINED_OFFSET
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int): SourceRangeInfo {
TODO("not implemented")
//TODO("not implemented")
return SourceRangeInfo(name, beginOffset, -1, -1, endOffset, -1, -1)
}
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -25,15 +26,10 @@ internal val IrDeclaration.module get() = this.descriptor.module
internal val IrField.isDelegate get() = @Suppress("DEPRECATION") this.descriptor.isDelegated
internal fun IrFunction.getObjCMethodInfo() = this.descriptor.getObjCMethodInfo()
internal fun IrClass.isExternalObjCClass() = this.descriptor.isExternalObjCClass()
internal fun IrClass.isKotlinObjCClass() = this.descriptor.isKotlinObjCClass()
internal fun IrFunction.getExternalObjCMethodInfo() = this.descriptor.getExternalObjCMethodInfo()
internal fun IrFunction.isObjCClassMethod() = this.descriptor.isObjCClassMethod()
internal fun IrFunction.canObjCClassMethodBeCalledVirtually(overridden: IrFunction) =
this.descriptor.canObjCClassMethodBeCalledVirtually(overridden.descriptor)
internal fun IrClass.isObjCClass() = this.descriptor.isObjCClass()
internal fun IrClass.isObjCMetaClass() = this.descriptor.isObjCMetaClass()
internal fun IrFunction.isExternalObjCClassMethod() = this.descriptor.isExternalObjCClassMethod()
internal val IrDeclaration.llvmSymbolOrigin get() = this.descriptor.llvmSymbolOrigin
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
internal typealias DeclarationDescriptor = IrDeclaration
internal typealias FunctionDescriptor = IrFunction
internal typealias SimpleFunctionDescriptor = IrSimpleFunction
internal typealias ClassDescriptor = IrClass
internal typealias ConstructorDescriptor = IrConstructor
internal typealias ClassConstructorDescriptor = IrConstructor
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
@@ -19,6 +20,8 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isSuspendFunction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
@@ -162,3 +165,17 @@ fun IrAnnotationContainer.hasAnnotation(fqName: FqName) =
fun List<IrCall>.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull {
it.annotationClass.fqNameSafe == fqName
}
fun IrValueParameter.isInlineParameter(): Boolean =
!this.isNoinline && (this.type.isFunction() || this.type.isSuspendFunction()) && !this.type.isMarkedNullable()
val IrDeclaration.parentDeclarationsWithSelf: Sequence<IrDeclaration>
get() = generateSequence(this, { it.parent as? IrDeclaration })
fun IrClass.companionObject() = this.declarations.singleOrNull {it is IrClass && it.isCompanion }
val IrDeclaration.isGetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.getter
val IrDeclaration.isSetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.setter
val IrDeclaration.isAccessor get() = this.isGetter || this.isSetter
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan.library
import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.konan.serialization.UniqId
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
import org.jetbrains.kotlin.konan.properties.Properties
@@ -26,7 +27,14 @@ interface KonanLibraryWriter {
class LinkData(
val module: ByteArray,
val fragments: List<List<ByteArray>>,
val fragmentNames: List<String>
val fragmentNames: List<String>,
val ir: SerializedIr? = null
)
class SerializedIr (
val module: ByteArray,
val declarations: Map<UniqId, ByteArray>,
val debugIndex: Map<UniqId, String>
)
interface MetadataWriter {
@@ -52,6 +52,7 @@ class LibraryWriterImpl(
nativeDir.mkdirs()
includedDir.mkdirs()
resourcesDir.mkdirs()
irDir.mkdirs()
// TODO: <name>:<hash> will go somewhere around here.
manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName)
manifestProperties.writeKonanLibraryVersioning(versions)
@@ -12,6 +12,7 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra
fun addLinkData(linkData: LinkData) {
moduleHeaderFile.writeBytes(linkData.module)
wholeIrFile.writeBytes(linkData.ir!!.module)
linkData.fragments.forEachIndexed { index, it ->
val packageFqName = linkData.fragmentNames[index]
val shortName = packageFqName.substringAfterLast(".")
@@ -24,5 +25,15 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra
packageFragmentFile(packageFqName, "${withLeadingZeros(i)}_$shortName").writeBytes(fragment)
}
}
linkData.ir?.declarations?.forEach {
val index = it.key.index.toULong().toString(16)
val file = if (it.key.isLocal)
hiddenDeclarationFile(index)
else
visibleDeclarationFile(index)
file.writeBytes(it.value)
}
val lines = linkData.ir?.debugIndex.map { entry -> "${entry.key}: ${entry.value}" }
irIndex.writeLines(lines)
}
}
@@ -6,12 +6,11 @@
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef
import org.jetbrains.kotlin.backend.konan.RuntimeNames
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.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isInlined
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -38,7 +37,7 @@ import org.jetbrains.kotlin.name.Name
* 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 DeclarationDescriptor.isExported(): Boolean {
internal tailrec fun IrDeclaration.isExported(): Boolean {
// TODO: revise
val descriptorAnnotations = this.descriptor.annotations
if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) {
@@ -63,7 +62,7 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
if (this.isAnonymousObject)
return false
if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) {
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()
@@ -151,11 +150,21 @@ private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, typ
private fun typeToHashString(type: IrType)
= acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type)
private val FunctionDescriptor.signature: String
internal val IrValueParameter.extensionReceiverNamePart: String
get() = "@${typeToHashString(this.type)}."
private val IrFunction.signature: String
get() {
val extensionReceiverPart = this.extensionReceiverParameter?.let { "@${typeToHashString(it.type)}." } ?: ""
val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
val argsPart = this.valueParameters.map {
"${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}"
// 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.
@@ -170,10 +179,10 @@ private val FunctionDescriptor.signature: String
}
// TODO: rename to indicate that it has signature included
internal val FunctionDescriptor.functionName: String
internal val IrFunction.functionName: String
get() {
with(this.original) { // basic support for generics
this.getObjCMethodInfo()?.let {
(if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name)
@@ -182,6 +191,20 @@ internal val FunctionDescriptor.functionName: String
append("objc:")
append(it.selector)
if (this@with is IrConstructor && this@with.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@with is IrSimpleFunction && this@with.hasObjCMethodAnnotation()) {
this@with.objCMethodArgValue("selector") ?.let { append("#$it") }
this@with.objCMethodArgValue("bridge") ?.let { append("#$it") }
}
}
}
@@ -201,7 +224,7 @@ private fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility
"$this\$$moduleName"
}
internal val FunctionDescriptor.symbolName: String
internal val IrFunction.symbolName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.descriptor.toString())
@@ -231,15 +254,15 @@ internal val IrField.symbolName: String
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kprop:$containingDeclarationPart$name"
return "kfield:$containingDeclarationPart$name"
}
// TODO: bring here dependencies of this method?
internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef {
val original = function.original
val returnType = when {
original is ConstructorDescriptor -> voidType
original is IrConstructor -> voidType
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(original.returnType)
}
@@ -259,19 +282,21 @@ internal fun RuntimeAware.getLlvmFunctionType(symbol: DataFlowIR.FunctionSymbol)
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
}
internal val ClassDescriptor.typeInfoSymbolName: String
internal val IrClass.typeInfoSymbolName: String
get() {
assert (this.isExported())
return "ktype:" + this.fqNameSafe.toString()
}
internal val ClassDescriptor.writableTypeInfoSymbolName: String
internal val IrClass.writableTypeInfoSymbolName: String
get() {
assert (this.isExported())
return "ktypew:" + this.fqNameSafe.toString()
}
internal val ClassDescriptor.objectInstanceFieldSymbolName: String
internal val theUnitInstanceName = "kobj:kotlin.Unit"
internal val IrClass.objectInstanceFieldSymbolName: String
get() {
assert (this.isExported())
assert (this.kind.isSingleton)
@@ -280,7 +305,7 @@ internal val ClassDescriptor.objectInstanceFieldSymbolName: String
return "kobjref:$fqNameSafe"
}
internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String
internal val IrClass.objectInstanceShadowFieldSymbolName: String
get() {
assert (this.isExported())
assert (this.kind.isSingleton)
@@ -290,7 +315,7 @@ internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String
return "kshadowobjref:$fqNameSafe"
}
internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean
internal val IrClass.typeInfoHasVtableAttached: Boolean
get() = !this.isAbstract() && !this.isExternalObjCClass()
internal fun ModuleDescriptor.privateFunctionSymbolName(index: Int, functionName: String?) = "private_functions_${name.asString()}_${functionName}_$index"
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -655,7 +654,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
* if toString/eq/hc is invoked on an interface instance, we resolve
* owner as Any and dispatch it via vtable.
*/
val anyMethod = (descriptor as SimpleFunctionDescriptor).findOverriddenMethodOfAny()
val anyMethod = (descriptor as IrSimpleFunction).findOverriddenMethodOfAny()
val owner = (anyMethod ?: descriptor).containingDeclaration as ClassDescriptor
val llvmMethod = if (!owner.isInterface) {
@@ -146,7 +146,7 @@ internal interface ContextUtils : RuntimeAware {
fun isExternal(descriptor: DeclarationDescriptor): Boolean {
val pkg = descriptor.findPackage()
return when (pkg) {
is IrFile -> false
is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor
is IrExternalPackageFragment -> true
else -> error(pkg)
}
@@ -601,7 +601,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return
}
if (declaration.isObjCConstructor()) {
if (declaration.isObjCConstructor) {
// Do not generate any ctors for external Objective-C classes.
return
}
@@ -1996,7 +1996,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateFunctionReference(expression: IrFunctionReference): LLVMValueRef {
// TODO: consider creating separate IR element for pointer to function.
assert (expression.type.getClass()?.descriptor == context.interopBuiltIns.cPointer)
assert (expression.type.getClass()?.descriptor == context.interopBuiltIns.cPointer) {
"assert: ${expression.type.getClass()?.descriptor} == ${context.interopBuiltIns.cPointer}"
}
assert (expression.getArguments().isEmpty())
@@ -2142,7 +2144,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"}
if (superClass == null && descriptor is SimpleFunctionDescriptor && descriptor.isOverridable)
if (superClass == null && descriptor is IrSimpleFunction && descriptor.isOverridable)
return callVirtual(descriptor, args, resultLifetime)
else
return callDirect(descriptor, args, resultLifetime)
@@ -42,10 +42,10 @@ internal class LlvmDeclarations(
private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>,
private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) {
fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?:
error(descriptor.toString())
error("${descriptor.toString()} ${descriptor.name} in ${(descriptor.parent as IrDeclaration).name}")
fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?:
error(descriptor.toString())
error("$descriptor ${descriptor.name}")
fun forField(descriptor: IrField) = fields[descriptor] ?:
error(descriptor.toString())
@@ -393,7 +393,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val descriptor = declaration
val llvmFunctionType = getLlvmFunctionType(descriptor)
if ((descriptor is ConstructorDescriptor && descriptor.isObjCConstructor())) {
if ((descriptor is ConstructorDescriptor && descriptor.isObjCConstructor)) {
return
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.computePrimitiveBinaryTypeOrNull
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.types.*
@@ -337,4 +337,4 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
}
}
}
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
@@ -21,18 +21,25 @@ import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
@@ -71,6 +78,10 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
}
override fun visitField(declaration: IrField) {
// TODO: inlining a function returning an object
// we get PropertyDescriptors from whithin that object here.
// That is a bug, most probably.
// We workaround the issue with question marks here.
(declaration.descriptor as? WrappedFieldDescriptor)?.bind(declaration)
declaration.acceptChildrenVoid(this)
}
@@ -96,7 +107,6 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
declaration.acceptChildrenVoid(this)
}
})
result.patchDeclarationParents(parent)
return result
}
@@ -1013,4 +1023,4 @@ internal class DescriptorSubstitutorForExternalScope(
return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol)
}
}
}
@@ -30,18 +30,28 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
* Note: org.jetbrains.kotlin.backend.common.lower.ExpectDeclarationsRemoving is copy of this lower.
*/
internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass {
override fun lower(irFile: IrFile) {
// All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`.
irFile.declarations.removeAll {
if (it.descriptor.isExpectMember) {
copyDefaultArgumentsFromExpectToActual(it)
true
} else {
false
}
}
}
}
internal class ExpectToActualDefaultValueCopier(val context: Context) : FileLoweringPass {
override fun lower(irFile: IrFile) {
// All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`.
irFile.declarations.forEach {
if (it.descriptor.isExpectMember) {
copyDefaultArgumentsFromExpectToActual(it)
}
}
}
private fun copyDefaultArgumentsFromExpectToActual(declaration: IrDeclaration) {
declaration.acceptVoid(object : IrElementVisitorVoid {
@@ -9,16 +9,16 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isInlineParameter
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement
@@ -34,10 +34,10 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl
@@ -119,7 +119,6 @@ internal class Ref<T>(var value: T)
internal class FunctionInlining(val context: Context): IrElementTransformerWithContext<Ref<Boolean>>() {
private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
@@ -138,8 +137,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
val result = super.visitFunctionNew(declaration, localData)
data.value = data.value or localData.value
if (descriptor.needsInlining)
if (descriptor.needsInlining) {
inlineFunctions[descriptor] = localData.value
}
return result
}
@@ -163,19 +163,20 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
}
data.value = data.value or callee.second
// TODO: do we still need this Ref<Boolean> mechanism?
val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false)
callee.first.transformChildren(this, childIsBad) // Process recursive inline.
inlineFunctions[functionDescriptor] = childIsBad.value
data.value = data.value or childIsBad.value
val currentCalleeIsBad = argsAreBad.value or childIsBad.value or callee.second
val currentCalleeIsBad = false
val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!,
allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull(), context, this)
return inliner.inline()
}
//-------------------------------------------------------------------------//
// TODO: do we really need this function anymore?
private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair<IrFunction, Boolean>? =
when {
descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) ->
@@ -189,7 +190,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
else ->
context.ir.originalModuleIndex.functions[descriptor]?.let { it to false }
?: deserializer.deserializeInlineBody(descriptor)?.let { it as IrFunction to true }
?: context.ir.symbols.symbolTable.referenceFunction(descriptor).owner to true
}
}
@@ -258,8 +259,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
val newThis = currentScope.scope.createTemporaryVariable(
val oldThis = (callee as IrConstructor).constructedClass.thisReceiver!!.descriptor
val newThis = currentScope.scope.createTemporaryVariableWithWrappedDescriptor(
irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
@@ -399,7 +400,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val isInlinableLambdaArgument : Boolean
get() {
if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
if (!parameter.isInlineParameter()) return false
if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway.
@@ -521,7 +522,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
return@forEach
}
val newVariable = currentScope.scope.createTemporaryVariable(
val newVariable = currentScope.scope.createTemporaryVariableWithWrappedDescriptor( // Create new variable and init it with the parameter expression.
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(),
isMutable = false)
@@ -537,4 +538,4 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
}
return evaluationStatements
}
}
}
@@ -204,4 +204,4 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
})
}
}
}
}
@@ -86,7 +86,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private val outerClasses = mutableListOf<IrClass>()
override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.descriptor.isKotlinObjCClass()) {
if (declaration.isKotlinObjCClass()) {
lowerKotlinObjCClass(declaration)
}
@@ -507,13 +507,13 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val constructedClass = outerClasses.peek()!!
val constructedClassDescriptor = constructedClass.descriptor
if (!constructedClassDescriptor.isObjCClass()) {
if (!constructedClass.isObjCClass()) {
return expression
}
constructedClassDescriptor.containingDeclaration.let { classContainer ->
if (classContainer is ClassDescriptor && classContainer.isObjCClass() &&
constructedClassDescriptor == classContainer.companionObjectDescriptor) {
constructedClass.parent.let { parent ->
if (parent is IrClass && parent.isObjCClass() &&
constructedClass.isCompanion) {
// Note: it is actually not used; getting values of such objects is handled by code generator
// in [FunctionGenerationContext.getObjectValue].
@@ -522,8 +522,8 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
}
}
if (!constructedClassDescriptor.isExternalObjCClass() &&
expression.descriptor.constructedClass.isExternalObjCClass()) {
if (!constructedClass.isExternalObjCClass() &&
(expression.symbol.owner.constructedClass).isExternalObjCClass()) {
// Calling super constructor from Kotlin Objective-C class.
@@ -531,7 +531,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initMethod = expression.descriptor.getObjCInitMethod()!!
if (!expression.descriptor.objCConstructorIsDesignated()) {
if (!expression.symbol.owner.objCConstructorIsDesignated()) {
context.reportCompilationError(
"Unable to call non-designated initializer as super constructor",
currentFile,
@@ -582,7 +582,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val superClass = superQualifier?.let { getObjCClass(it) } ?:
irCall(symbols.getNativeNullPtr, symbols.nativePtrType)
val bridge = symbolTable.referenceSimpleFunction(info.bridge)
val bridge = symbols.lazySymbolTable.referenceSimpleFunction(info.bridge)
return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
putValueArgument(0, superClass)
putValueArgument(1, receiver)
@@ -1103,4 +1103,4 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
scopeStack.peek()!!.add(declaration)
}
}
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.lower.SymbolWithIrBuilder
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
@@ -37,6 +38,8 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class TestProcessor (val context: KonanBackendContext) {
@@ -608,4 +611,4 @@ internal class TestProcessor (val context: KonanBackendContext) {
createTestSuites(it, annotationCollector)
}
}
}
}
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.util.OperatorNameConventions
private fun IrClass.getOverridingOf(function: FunctionDescriptor) = (function as? SimpleFunctionDescriptor)?.let {
private fun IrClass.getOverridingOf(function: FunctionDescriptor) = (function as? IrSimpleFunction)?.let {
it.allOverriddenDescriptors.atMostOne { it.parent == this }
}
@@ -1274,4 +1274,4 @@ internal object DFGSerializer {
return ExternalModulesDFG(allTypes, publicTypesMap, publicFunctionsMap, functions)
}
}
}
@@ -601,7 +601,7 @@ internal object DataFlowIR {
}
else -> {
val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT
val isAbstract = it is IrSimpleFunction && it.modality == Modality.ABSTRACT
val classDescriptor = it.containingDeclaration as? ClassDescriptor
val bridgeTarget = it.bridgeTarget
val isSpecialBridge = bridgeTarget.let {
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -30,7 +27,9 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid
list?.add(declaration.backingField!!.descriptor)
}
if (declaration.backingField == null || declaration.isDelegated) return
assert(declaration.backingField!!.descriptor == declaration.descriptor)
assert(declaration.backingField!!.descriptor == declaration.descriptor) {
"backing field descriptor mismatch: ${declaration.backingField!!.descriptor} != ${declaration.descriptor}"
}
context.ir.propertiesWithBackingFields.add(declaration.descriptor)
}
@@ -0,0 +1,63 @@
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
fun <K, V> MutableMap<K, V>.putOnce(k:K, v: V): Unit {
assert(!this.containsKey(k) || this[k] == v) {
"adding $v for $k, but it is already ${this[k]} for $k"
}
this.put(k, v)
}
class DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
descriptors.putOnce(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 {
val index = table.getOrPut(value) {
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)
}
}
debugIndex.put(index, "${if (index.isLocal) "" else value.uniqSymbolName()} descriptor = ${value.descriptor}")
return index
}
}
// This is what we pre-populate tables with
val IrBuiltIns.knownBuiltins
get() = irBuiltInsExternalPackageFragment.declarations
@@ -1,293 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.descriptors.externalSymbolOrThrow
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.backend.konan.getInlinedClass
import org.jetbrains.kotlin.backend.konan.getObjCMethodInfo
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.contracts.parsing.ContractsDslNames
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
// TODO: merge with FunctionDescriptor.symbolName in BinaryInterface.kt.
internal val DeclarationDescriptor.symbolName: String get() = when (this) {
is FunctionDescriptor
-> this.uniqueName
is PropertyDescriptor
-> this.uniqueName
is ClassDescriptor
-> this.uniqueName
else -> error("Unexpected exported descriptor: $this")
}
internal val DeclarationDescriptor.uniqId
get() = this.symbolName.localHash.value
internal val DeclarationDescriptor.isSerializableExpectClass: Boolean
get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this)
// TODO: We don't manage id clashes anyhow now.
class DescriptorTable(val builtIns: IrBuiltIns) {
val table = mutableMapOf<DeclarationDescriptor, Long>()
var currentIndex = 0L
init {
builtIns.irBuiltInDescriptors.forEach {
table.put(it, it.uniqId)
}
}
fun indexByValue(value: DeclarationDescriptor): Long {
val index = table.getOrPut(value) {
if (!value.isExported()
|| value is TypeParameterDescriptor) {
currentIndex++
} else {
value.uniqId
}
}
return index
}
}
class IrDeserializationDescriptorIndex(irBuiltIns: IrBuiltIns) {
val map = mutableMapOf<Long, DeclarationDescriptor>()
init {
irBuiltIns.irBuiltInDescriptors.forEach {
map.put(it.uniqId, it)
}
}
}
val IrBuiltIns.irBuiltInDescriptors
get() = (lessFunByOperandType.values +
lessOrEqualFunByOperandType.values +
greaterOrEqualFunByOperandType.values +
greaterFunByOperandType.values +
ieee754equalsFunByOperandType.values +
eqeqeqFun + eqeqFun + throwNpeFun + booleanNotFun + noWhenBranchMatchedExceptionFun + enumValueOfFun)
.map(IrSimpleFunction::descriptor)
// The declarations below are copied from `BinaryInterface.kt` when it was based on descriptors.
// 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 DeclarationDescriptor.isExported(): Boolean {
assert(!this.isExpectMember || this.isSerializableExpectClass) { this }
if (this.annotations.findAnnotation(ContractsDslNames.CONTRACTS_DSL_ANNOTATION_FQN) != null) {
// TODO: Seems like this should be deleted in PsiToIR.
// Treat any `@ContractsDsl` declaration as exported.
return true
}
if (this.annotations.findAnnotation(symbolNameAnnotation) != null) {
// Treat any `@SymbolName` declaration as exported.
return true
}
if (this.annotations.findAnnotation(exportForCppRuntimeAnnotation) != null) {
// Treat any `@ExportForCppRuntime` declaration as exported.
return true
}
if (this.annotations.findAnnotation(cnameAnnotation) != null) {
// Treat `@CName` declaration as exported.
return true
}
if (this.annotations.hasAnnotation(exportForCompilerAnnotation)) {
return true
}
if (this.annotations.hasAnnotation(publishedApiAnnotation)){
return true
}
if (DescriptorUtils.isAnonymousObject(this))
return false
if (this is ConstructorDescriptor && 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 PropertyAccessorDescriptor) {
return this.correspondingProperty.isExported()
}
if (this is DeclarationDescriptorWithVisibility && !this.visibility.isPublicAPI) {
// If the declaration is explicitly marked as non-public,
// then it must not be accessible from other modules.
return false
}
if (this is DeclarationDescriptorNonRoot) {
// If the declaration is not root, then check its container too.
return containingDeclaration.isExported()
}
return true
}
private val symbolNameAnnotation = FqName("kotlin.native.SymbolName")
private val exportForCppRuntimeAnnotation = FqName("kotlin.native.internal.ExportForCppRuntime")
private val cnameAnnotation = FqName("kotlin.native.internal.CName")
private val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler")
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, type: KotlinType): String {
val descriptor = TypeUtils.getTypeParameterDescriptorOrNull(type)
if (descriptor != null) {
val upperBounds = if (visited.contains(descriptor)) "" else {
visited.add(descriptor)
descriptor.upperBounds.map {
val bound = acyclicTypeMangler(visited, it)
if (bound == "kotlin.Any?") "" else "_$bound"
}.joinToString("")
}
return "#GENERIC" + upperBounds
}
var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString()
if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map {
if (it.isStarProjection()) {
"#STAR"
} else {
val variance = it.projectionKind.label
val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type)
}
}.joinToString(",")}>"
}
if (type.isMarkedNullable) hashString += "?"
return hashString
}
private fun typeToHashString(type: KotlinType)
= acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type)
private val FunctionDescriptor.signature: String
get() {
val extensionReceiverPart = this.extensionReceiverParameter?.let { "@${typeToHashString(it.type)}." } ?: ""
val argsPart = this.valueParameters.map {
typeToHashString(it.type)
}.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?.getInlinedClass() != null -> "ValueType"
returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) } -> typeToHashString(returnType!!)
else -> ""
}
return "$extensionReceiverPart($argsPart)$signatureSuffix"
}
// TODO: rename to indicate that it has signature included
private val FunctionDescriptor.uniqueLocalName: String
get() {
with(this.original) { // basic support for generics
this.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(TypeUtils.getClassDescriptor(extensionReceiverParameter!!.type)!!.name)
append(".")
}
append("objc:")
append(it.selector)
}
}
return "$name$signature"
}
}
private val FunctionDescriptor.uniqueName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.toString())
}
if (this.isExternal) {
externalSymbolOrThrow()?.let {
return it
}
}
// TODO: check that only external function has @SymbolName.
this.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
val name = getStringValue(it) ?: this.name.asString()
return name // no wrapping currently required
}
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart$uniqueLocalName"
}
private val PropertyDescriptor.uniqueName: String
get() {
val containingDeclarationPart = containingDeclaration.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
val extensionReceiverPart = this.extensionReceiverParameter?.let { "${it.type}." } ?: ""
return "kprop:$containingDeclarationPart$extensionReceiverPart$name"
}
private fun getStringValue(annotation: AnnotationDescriptor): String? {
annotation.allValueArguments.values.ifNotEmpty {
val stringValue = this.single() as StringValue
return stringValue.value
}
return null
}
private val ClassDescriptor.uniqueName: String
get() {
assert (this.isExported())
return "ktype:" + this.fqNameSafe.toString()
}
@@ -0,0 +1,80 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>) {
fun deserializeDescriptorReference(proto: KonanIr.DescriptorReference): DeclarationDescriptor {
val packageFqName =
if (proto.packageFqName == "<root>") FqName.ROOT else FqName(proto.packageFqName) // TODO: whould we store an empty string in the protobuf?
val classFqName = FqName(proto.classFqName)
val protoIndex = if (proto.hasUniqId()) proto.uniqId.index else null
val (clazz, members) = if (proto.classFqName == "") {
Pair(null, currentModule.getPackage(packageFqName).memberScope.getContributedDescriptors())
} else {
val clazz = currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, classFqName, false))!!
Pair(clazz, clazz.unsubstitutedMemberScope.getContributedDescriptors() + clazz.getConstructors())
}
if (proto.packageFqName.startsWith("cnames.") || proto.packageFqName.startsWith("objcnames.")) {
val descriptor =
currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, FqName(proto.name), false))!!
if (!descriptor.fqNameUnsafe.asString().startsWith("cnames") && !descriptor.fqNameUnsafe.asString().startsWith(
"objcnames"
)
) {
if (descriptor is DeserializedClassDescriptor) {
val uniqId = UniqId(descriptor.getUniqId()!!.index, false)
val newKey = UniqIdKey(null, uniqId)
val oldKey = UniqIdKey(null, UniqId(protoIndex!!, false))
resolvedForwardDeclarations.put(oldKey, newKey)
} else {
/* ??? */
}
}
return descriptor
}
if (proto.isEnumEntry) {
val name = proto.name
val memberScope = (clazz as DeserializedClassDescriptor).getUnsubstitutedMemberScope()
return memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND)!!
}
if (proto.isEnumSpecial) {
val name = proto.name
return clazz!!.getStaticScope()
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single()
}
members.forEach { member ->
if (proto.isDefaultConstructor && member is ClassConstructorDescriptor) return member
val realMembers =
if (proto.isFakeOverride && member is CallableMemberDescriptor && member.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
member.resolveFakeOverrideMaybeAbstract()
else
setOf(member)
val memberIndices = realMembers.map { it.getUniqId()?.index }.filterNotNull()
if (memberIndices.contains(protoIndex)) {
return when {
member is PropertyDescriptor && proto.isSetter -> member.setter!!
member is PropertyDescriptor && proto.isGetter -> member.getter!!
else -> member
}
}
}
error("Could not find serialized descriptor for index: ${proto.uniqId.index} ${proto.packageFqName},${proto.classFqName},${proto.name}")
}
}
@@ -1,62 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.backend.konan.descriptors.EmptyDescriptorVisitorVoid
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.backend.konan.PhaseManager
import org.jetbrains.kotlin.backend.konan.KonanPhase
internal class DeserializerDriver(val context: Context) {
private val cache = mutableMapOf<FunctionDescriptor, IrDeclaration?>()
internal fun deserializeInlineBody(descriptor: FunctionDescriptor): IrDeclaration? = cache.getOrPut(descriptor) {
if (!descriptor.needsSerializedIr) return null
if (!descriptor.isDeserializableCallable) return null
var deserializedIr: IrDeclaration? = null
PhaseManager(context).phase(KonanPhase.DESERIALIZER) {
context.log{"### IR deserialization attempt:\t$descriptor"}
try {
deserializedIr = IrDeserializer(context, descriptor).decodeDeclaration()
context.log{"${deserializedIr!!.descriptor}"}
context.log{ ir2stringWhole(deserializedIr!!) }
context.log{"IR deserialization SUCCESS:\t$descriptor"}
} catch(e: Throwable) {
context.log{"IR deserialization FAILURE:\t$descriptor"}
if (context.phase!!.verbose) e.printStackTrace()
}
}
deserializedIr
}
internal fun dumpAllInlineBodies() {
if (! context.phase!!.verbose) return
context.log{"Now deserializing all inlines for debugging purpose."}
context.moduleDescriptor.accept(
InlineBodiesPrinterVisitor(InlineBodyPrinter()), Unit)
}
inner class InlineBodiesPrinterVisitor(worker: EmptyDescriptorVisitorVoid): DeepVisitor<Unit>(worker)
inner class InlineBodyPrinter: EmptyDescriptorVisitorVoid() {
override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): Boolean {
if (descriptor.isDeserializableCallable) {
this@DeserializerDriver.deserializeInlineBody(descriptor)
}
return true
}
}
}
@@ -1,413 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanIrDeserializationException
import org.jetbrains.kotlin.backend.konan.descriptors.contributedMethods
import org.jetbrains.kotlin.backend.konan.descriptors.createExtensionReceiver
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.metadata.KonanIr.DeclarationDescriptor.DescriptorCase
import org.jetbrains.kotlin.metadata.KonanIr.KotlinDescriptor.Kind.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.serialization.konan.KonanPackageFragment
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isError
internal fun DeserializedMemberDescriptor.nameTable(): ProtoBuf.QualifiedNameTable {
val pkg = this.findPackage()
assert(pkg is KonanPackageFragment)
return (pkg as KonanPackageFragment).proto.getNameTable()
}
internal fun DeserializedMemberDescriptor.nameResolver(): NameResolver {
val pkg = this.findPackage() as KonanPackageFragment
return NameResolverImpl(pkg.proto.getStringTable(), pkg.proto.getNameTable())
}
// This is the class that knowns how to deserialize
// Kotlin descriptors and types for IR.
internal class IrDescriptorDeserializer(val context: Context,
val rootDescriptor: DeserializedCallableMemberDescriptor,
val localDeserializer: LocalDeclarationDeserializer) {
val loopIndex = mutableMapOf<Int, IrLoop>()
val nameResolver = rootDescriptor.nameResolver() as NameResolverImpl
val nameTable = rootDescriptor.nameTable()
val descriptorIndex = IrDeserializationDescriptorIndex(context.irBuiltIns).map
fun deserializeKotlinType(proto: KonanIr.KotlinType): KotlinType {
val index = proto.getIndex()
val text = proto.getDebugText()
val typeProto = localDeserializer.parentTypeTable[index]
val type = localDeserializer.deserializeInlineType(typeProto)
if (type.isError)
throw KonanIrDeserializationException("Could not deserialize KotlinType: $text $type")
val realType = if (proto.isCaptured) {
unpackCapturedType(type)
} else
type
context.log{"### deserialized Kotlin Type index=$index, text=$text:\t$realType"}
return realType
}
fun deserializeLocalDeclaration(irProto: KonanIr.KotlinDescriptor): DeclarationDescriptor {
val localDeclarationProto = irProto.irLocalDeclaration.descriptor
val index = irProto.index
//val localDeserializer = LocalDeclarationDeserializer(parent)
val descriptor: DeclarationDescriptor = when(localDeclarationProto.descriptorCase) {
DescriptorCase.FUNCTION ->
localDeserializer.deserializeFunction(irProto)
DescriptorCase.PROPERTY ->
localDeserializer.deserializeProperty(irProto)
DescriptorCase.CLAZZ ->
localDeserializer.deserializeClass(irProto)
DescriptorCase.CONSTRUCTOR ->
localDeserializer.deserializeConstructor(irProto)
else -> TODO("Unexpected descriptor kind")
}
descriptorIndex.put(index, descriptor)
return descriptor
}
// Either (a substitution of) a public descriptor
// or an already seen local declaration.
fun deserializeKnownDescriptor(proto: KonanIr.KotlinDescriptor): DeclarationDescriptor {
val index = proto.index
val kind = proto.kind
val descriptor = when (kind) {
VALUE_PARAMETER, TYPE_PARAMETER, RECEIVER, PROPERTY, VARIABLE ->
descriptorIndex[index]!!
CLASS, CONSTRUCTOR, FUNCTION, ACCESSOR ->
descriptorIndex[index] ?:
findInTheDescriptorTree(proto) ?: error("${proto.name} is not found") // Note: can be null when using `@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")`
else -> TODO("Unexpected descriptor kind: $kind")
}
return descriptor
}
fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor): DeclarationDescriptor {
context.log{"### deserializeDescriptor ${proto.kind} ${proto.index}"}
val descriptor = if (proto.hasIrLocalDeclaration()) {
deserializeLocalDeclaration(proto)
} else
deserializeKnownDescriptor(proto)
descriptorIndex.put(proto.index, descriptor)
context.log{"### descriptor ${proto.kind} ${proto.index} -> $descriptor"}
// Now there are several descriptors that automatically
// recreated in addition to this one. Register them
// all too.
if (descriptor is FunctionDescriptor) {
registerParameterDescriptors(proto, descriptor)
}
return descriptor
}
// --------------------------------------------------------
//
// The section below is a poor man's resolve.
// Having a 'kind' and a 'name' of a descriptor,
// we need to find it's original unsubstituted version
// in the descriptor tree. And then apply the substitutions
// to get the same substituted descriptor we've obtained
// in the original ir.
//
// We don't deserialize value, type and receiver parameters, rather
// just obtain them from their function descriptor and match them to the indices
// stored in the IR serialization.
fun registerParameterDescriptors (
proto: KonanIr.KotlinDescriptor,
functionDescriptor: FunctionDescriptor) {
functionDescriptor.valueParameters.forEachIndexed { i, parameter ->
// Assume they are in the same order.
val index = proto.getValueParameter(i).index
descriptorIndex.put(index, parameter)
}
functionDescriptor.typeParameters.forEachIndexed {i, parameter ->
// Assume they are in the same order too.
val index = proto.getTypeParameter(i).index
descriptorIndex.put(index, parameter)
}
val dispatchReceiver = functionDescriptor.dispatchReceiverParameter
if (dispatchReceiver != null) {
assert(proto.hasDispatchReceiverUniqId())
val dispatchReceiverIndex = proto.dispatchReceiverIndex
descriptorIndex.put(dispatchReceiverIndex, dispatchReceiver)
}
val extensionReceiver = functionDescriptor.extensionReceiverParameter
if (extensionReceiver != null) {
assert(proto.hasExtensionReceiverUniqId())
val extensionReceiverIndex = proto.extensionReceiverIndex
descriptorIndex.put(extensionReceiverIndex, extensionReceiver)
}
}
fun substituteFunction(proto: KonanIr.KotlinDescriptor,
originalDescriptor: FunctionDescriptor): FunctionDescriptor {
val newDescriptor =
originalDescriptor.newCopyBuilder().apply() {
setOriginal(originalDescriptor)
setReturnType(deserializeKotlinType(proto.type))
if (proto.hasExtensionReceiverType()) {
val extensionReceiverType = deserializeKotlinType(proto.extensionReceiverType)
setExtensionReceiverParameter(extensionReceiverType.createExtensionReceiver(originalDescriptor))
}
}.build()!!
descriptorIndex.put(proto.index, newDescriptor)
return newDescriptor
}
fun substituteConstructor(proto: KonanIr.KotlinDescriptor,
originalDescriptor: ClassConstructorDescriptor): ClassConstructorDescriptor {
val newDescriptor = originalDescriptor.newCopyBuilder().apply() {
setOriginal(originalDescriptor)
setReturnType(deserializeKotlinType(proto.type))
assert(!proto.hasExtensionReceiverType())
}.build()!!
descriptorIndex.put(proto.index, newDescriptor)
// TODO: why?
return newDescriptor as ClassConstructorDescriptor
}
// Property accessors are different because the accessors don't have
// ProtoBuf serializations. Only their properties do.
// And also an accessor can not be copied, only properties can.
fun substituteAccessor(proto: KonanIr.KotlinDescriptor,
originalDescriptor: PropertyAccessorDescriptor): PropertyAccessorDescriptor {
val originalPropertyDescriptor = originalDescriptor.correspondingProperty as DeserializedPropertyDescriptor
// TODO: property copy building is a mess.
// Plus it is changing in the big Kotlin under my fingers.
// What should I do here???
// how do I set type and extensionreceiver for a property???
val newPropertyDescriptor = originalPropertyDescriptor
val newDescriptor = when (originalDescriptor) {
is PropertyGetterDescriptor ->
newPropertyDescriptor.getter
is PropertySetterDescriptor ->
newPropertyDescriptor.setter
else -> TODO("Unexpected accessor kind")
}
descriptorIndex.put(proto.index, newDescriptor!!)
newDescriptor.valueParameters.forEachIndexed { i, parameter ->
// Assume they are in the same order.
val index = proto.getValueParameter(i).index
descriptorIndex.put(index, parameter)
}
newPropertyDescriptor.typeParameters.forEachIndexed { i, parameter ->
// Assume they are in the same order too.
val index = proto.getTypeParameter(i).index
descriptorIndex.put(index, parameter)
}
val dispatchReceiver = newPropertyDescriptor.dispatchReceiverParameter
if (dispatchReceiver != null) {
assert(proto.hasDispatchReceiverUniqId())
val dispatchReceiverIndex = proto.dispatchReceiverIndex
descriptorIndex.put(dispatchReceiverIndex, dispatchReceiver)
}
val extensionReceiver = newPropertyDescriptor.extensionReceiverParameter
if (extensionReceiver != null) {
assert(proto.hasExtensionReceiverUniqId())
val extensionReceiverIndex = proto.extensionReceiverIndex
descriptorIndex.put(extensionReceiverIndex, extensionReceiver)
}
return newDescriptor
}
fun parentMemberScopeByFqNameIndex(index: Int): MemberScope {
val parent = parentByFqNameIndex(index)
return when (parent) {
is ClassDescriptor -> parent.getUnsubstitutedMemberScope()
is PackageFragmentDescriptor -> parent.getMemberScope()
is PackageViewDescriptor -> parent.memberScope
else -> TODO("could not get a member scope")
}
}
fun parentByFqNameIndex(index: Int): DeclarationDescriptor {
val module = context.moduleDescriptor
val parent = nameResolver.getDescriptorByFqNameIndex(module, nameTable, index)
return parent
}
fun matchNameInParentScope(proto: KonanIr.KotlinDescriptor): Collection<DeclarationDescriptor> {
val classOrPackage = proto.classOrPackage
val name = proto.name
when (proto.kind) {
CLASS -> {
val parentScope =
parentMemberScopeByFqNameIndex(classOrPackage)
val clazz = parentScope.getContributedClassifier(
Name.identifier(name), NoLookupLocation.FROM_BACKEND)
return listOf(clazz!!)
}
CONSTRUCTOR -> {
val parent = parentByFqNameIndex(classOrPackage)
assert(parent is ClassDescriptor)
return (parent as ClassDescriptor).constructors
}
ACCESSOR, FUNCTION -> {
val parentScope =
parentMemberScopeByFqNameIndex(classOrPackage)
return parentScope.contributedMethods.filter{
it.name == Name.guessByFirstCharacter(name)
}
}
else -> TODO("Can't find matching names for ${proto.kind}")
}
}
fun selectFunction(
functions: Collection<DeclarationDescriptor>,
descriptorProto: KonanIr.KotlinDescriptor):
DeserializedSimpleFunctionDescriptor {
val originalIndex = descriptorProto.originalIndex
val match = functions.singleOrNull() {
it.uniqId == originalIndex
} as? DeserializedSimpleFunctionDescriptor
if (match != null) return match
// Special case: for invoke we need to re-synthesize
// the invoke() descriptor.
val invoke = functions.singleOrNull {
(it as FunctionDescriptor).isFunctionInvoke
}
if (invoke != null)
return createSynthesizedInvokes(listOf(invoke as FunctionDescriptor)).single() as DeserializedSimpleFunctionDescriptor
else {
error("Could not find matching descriptor")
}
}
fun selectConstructor(
constructors: Collection<DeclarationDescriptor>,
descriptorProto: KonanIr.KotlinDescriptor):
DeserializedClassConstructorDescriptor {
val originalIndex = descriptorProto.originalIndex
return constructors.single {
it.uniqId == originalIndex
} as DeserializedClassConstructorDescriptor
}
fun selectAccessor(
functions: Collection<DeclarationDescriptor>,
proto: KonanIr.KotlinDescriptor):
PropertyAccessorDescriptor {
// TODO: property accessors are not serialized by
// descriptor serialization mechanisms, we can't match
// the "original" field of the deserialized descriptors.
// So KonanIr.KonanDescriptor.original contains
// original index of the property rather than accessor's.
val originalIndex = proto.originalIndex
return functions.single {
val property = (it as PropertyAccessorDescriptor).correspondingProperty as DeserializedPropertyDescriptor
property.uniqId == originalIndex
} as PropertyAccessorDescriptor
}
fun selectAmongMatchingNames(
matching: Collection<DeclarationDescriptor>,
proto: KonanIr.KotlinDescriptor):
DeclarationDescriptor {
return when(proto.kind) {
FUNCTION -> selectFunction(matching, proto)
ACCESSOR -> selectAccessor(matching, proto)
CONSTRUCTOR -> selectConstructor(matching, proto)
CLASS -> matching.single()
else -> TODO("don't know how to select ${proto.kind}")
}
}
fun performSubstitutions(proto: KonanIr.KotlinDescriptor,
originalDescriptor: DeclarationDescriptor):
DeclarationDescriptor {
//TODO: We need to properly skip creating substituted
// copies for public descriptors if we know the substituted
// descriptor is going to be the same.
// But that's not a trivial thing to find out.
if (originalDescriptor == rootDescriptor)
return rootDescriptor
return when (originalDescriptor) {
is SimpleFunctionDescriptor ->
substituteFunction(proto, originalDescriptor)
is PropertyAccessorDescriptor ->
substituteAccessor(proto, originalDescriptor)
is ClassConstructorDescriptor ->
substituteConstructor(proto, originalDescriptor)
is ClassDescriptor ->
// TODO: do we really need to ever substitute
// class descriptors here?
//substituteClass(proto, originalDescriptor)
originalDescriptor
else -> TODO("unexpected type of public function")
}
}
fun findInTheDescriptorTree(proto: KonanIr.KotlinDescriptor): DeclarationDescriptor? {
val matchingNames = matchNameInParentScope(proto).filter{it.isExported()}
if (matchingNames.size == 0) return null
val originalDescriptor = selectAmongMatchingNames(matchingNames, proto)
return performSubstitutions(proto, originalDescriptor)
}
}
@@ -1,149 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.calls.inference.isCaptured
import org.jetbrains.kotlin.types.KotlinType
val DeclarationDescriptor.classOrPackage: DeclarationDescriptor?
get() {
return if (this.containingDeclaration!! is ClassOrPackageFragmentDescriptor)
containingDeclaration
else null
}
internal class IrDescriptorSerializer(
val context: Context,
val descriptorTable: DescriptorTable,
val stringTable: KonanStringTable,
val localDeclarationSerializer: LocalDeclarationSerializer,
var rootFunction: FunctionDescriptor) {
fun serializeKotlinType(type: KotlinType): KonanIr.KotlinType {
val isCaptured = type.isCaptured()
val typeToSerialize = if (isCaptured) {
packCapturedType(type as CapturedType)
} else {
type
}
val index = localDeclarationSerializer.typeSerializer(typeToSerialize)
val proto = KonanIr.KotlinType.newBuilder()
.setIndex(index)
.setDebugText(type.toString())
.setIsCaptured(isCaptured)
.build()
return proto
}
fun kotlinDescriptorKind(descriptor: DeclarationDescriptor) =
when (descriptor) {
is ConstructorDescriptor
-> KonanIr.KotlinDescriptor.Kind.CONSTRUCTOR
is PropertyAccessorDescriptor
-> KonanIr.KotlinDescriptor.Kind.ACCESSOR
is FunctionDescriptor
-> KonanIr.KotlinDescriptor.Kind.FUNCTION
is ClassDescriptor
-> KonanIr.KotlinDescriptor.Kind.CLASS
is ValueParameterDescriptor
-> KonanIr.KotlinDescriptor.Kind.VALUE_PARAMETER
is LocalVariableDescriptor,
is IrTemporaryVariableDescriptor
-> KonanIr.KotlinDescriptor.Kind.VARIABLE
is TypeParameterDescriptor
-> KonanIr.KotlinDescriptor.Kind.TYPE_PARAMETER
is ReceiverParameterDescriptor
-> KonanIr.KotlinDescriptor.Kind.RECEIVER
is PropertyDescriptor
-> KonanIr.KotlinDescriptor.Kind.PROPERTY
else -> TODO("Unexpected local descriptor: $descriptor")
}
fun functionDescriptorSpecifics(descriptor: FunctionDescriptor, proto: KonanIr.KotlinDescriptor.Builder) {
val typeParameters = descriptor.propertyIfAccessor.typeParameters
typeParameters.forEach {
proto.addTypeParameter(serializeDescriptor(it))
// We explicitly serialize type parameters as types here so that
// they are interned in the natural order of declaration.
// Otherwise they appear in the order of appearence in the body
// of the function, and get wrong indices.
localDeclarationSerializer.typeSerializer(it.defaultType)
}
descriptor.valueParameters.forEach {
proto.addValueParameter(serializeDescriptor(it))
}
// Allocate two indicies for the receivers. They are not deserialized
// from protobuf, just recreated together with their function.
val dispatchReceiver = descriptor.dispatchReceiverParameter
if (dispatchReceiver != null)
proto.setDispatchReceiverIndex(
descriptorTable.indexByValue(dispatchReceiver))
val extensionReceiver = descriptor.extensionReceiverParameter
if (extensionReceiver != null) {
proto.setExtensionReceiverIndex(
descriptorTable.indexByValue(extensionReceiver))
proto.setExtensionReceiverType(
serializeKotlinType(extensionReceiver.type))
}
proto.setType(serializeKotlinType(
descriptor.returnType!!))
}
fun variableDescriptorSpecifics(descriptor: VariableDescriptor, proto: KonanIr.KotlinDescriptor.Builder) {
proto.setType(serializeKotlinType(descriptor.type))
}
fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor {
val classOrPackage = descriptor.classOrPackage
val parentFqNameIndex = if (classOrPackage is ClassOrPackageFragmentDescriptor) {
stringTable.getClassOrPackageFqNameIndex(classOrPackage)
} else null
val index = descriptorTable.indexByValue(descriptor)
// For getters and setters we use the *property* original index.
val originalIndex = descriptorTable.indexByValue(descriptor.propertyIfAccessor.original)
context.log{"index = $index"}
context.log{"originalIndex = $originalIndex"}
context.log{""}
val proto = KonanIr.KotlinDescriptor.newBuilder()
.setName(descriptor.name.asString())
.setKind(kotlinDescriptorKind(descriptor))
.setIndex(index)
.setOriginalIndex(originalIndex)
if (parentFqNameIndex != null)
proto.setClassOrPackage(parentFqNameIndex)
when (descriptor) {
is FunctionDescriptor ->
functionDescriptorSpecifics(descriptor, proto)
is VariableDescriptor ->
variableDescriptorSpecifics(descriptor, proto)
}
return proto.build()
}
}
@@ -0,0 +1,52 @@
/*
* 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.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.resolve.OverridingUtil
// TODO: move me somewhere
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun IrSimpleFunction.resolveFakeOverrideMaybeAbstract() = this.resolveFakeOverride(allowAbstract = true)
internal fun IrProperty.resolveFakeOverrideMaybeAbstract() = this.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!
internal fun IrField.resolveFakeOverrideMaybeAbstract() = this.correspondingProperty!!.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!.backingField
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverrideMaybeAbstract(): Set<T> {
if (this.kind.isReal) {
return setOf(this)
} else {
val overridden = OverridingUtil.getOverriddenDeclarations(this)
val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST")
return filtered as Set<T>
}
}
@@ -1,69 +1,26 @@
syntax = "proto2";
package org.jetbrains.kotlin.metadata;
// FIXME(ddol): fix this import after moving `metadata` to main Kotlin repo - it should refer to the actual metadata.proto file from Kotlin project
import "org/jetbrains/kotlin/backend/konan/serialization/metadata.proto1";
option java_outer_classname = "KonanIr";
option optimize_for = LITE_RUNTIME;
// This is subject to change.
// One can think of it as a 'descriptor reference'.
// The real descriptor data is encoded in KonanLinkdData.
message KotlinDescriptor {
enum Kind {
FUNCTION = 1;
VARIABLE = 2;
CLASS = 3;
VALUE_PARAMETER = 4;
CONSTRUCTOR = 5;
TYPE_PARAMETER = 6;
RECEIVER = 7;
ACCESSOR = 8;
PROPERTY = 9;
}
// TODO: Use the string table index.
optional string name = 1;
required Kind kind = 2;
required UniqId uniq_id = 3;
required UniqId original_uniq_id = 4;
// index in fq name table
optional int32 class_or_package = 5;
// Descriptor kind specific fields.
// TODO: consider introducing specific messages
// for functions, variables etc.
optional KotlinType type = 6;
repeated KotlinDescriptor value_parameter = 7;
repeated KotlinDescriptor type_parameter = 8;
optional UniqId dispatch_receiver_uniq_id = 9;
optional UniqId extension_receiver_uniq_id = 10;
optional KotlinType extension_receiver_type = 11;
optional LocalDeclaration ir_local_declaration = 12;
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 int64 index = 1;
}
// Inner descriptors used for inlining.
message DeclarationDescriptor {
// These are ProtoBuf.Function, ProtoBuf.Class etc
oneof descriptor {
Function function = 1;
Class clazz = 2;
Property property = 3;
Constructor constructor = 4;
}
}
message LocalDeclaration {
required DeclarationDescriptor descriptor = 1;
}
message KotlinType {
required int32 index = 1;
required bool isCaptured = 2; // TODO: make it a flag set?
optional string debug_text = 3; // TODO: remove me
required uint64 index = 1;
required bool isLocal = 2;
}
message Coordinates {
@@ -71,9 +28,127 @@ message Coordinates {
required int32 end_offset = 2;
}
message TypeArguments {
repeated KotlinType type_argument = 1;
/* ------ Top Level---------------------------------------------- */
message IrDeclarationContainer {
repeated IrDeclaration declaration = 1;
}
message FileEntry { // TODO: extend me.
required string name = 1;
}
message IrFile {
repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2;
// TODO: we need a better string management. See metadata serialization as an example.
required string fq_name = 3;
}
message IrModule {
required string name = 1;
repeated IrFile file = 2;
required IrSymbolTable symbol_table = 3;
required IrTypeTable type_table = 4;
}
/* ------ 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 {
@@ -83,14 +158,14 @@ message IrBreak {
message IrBlock {
required bool is_lambda_origin = 1;
repeated IrStatement statement = 2;
repeated IrStatement statement = 2;
}
message MemberAccessCommon {
optional IrExpression dispatch_receiver = 5;
optional IrExpression extension_receiver = 6;
repeated NullableIrExpression value_argument = 8;
required TypeArguments type_arguments = 9;
optional IrExpression dispatch_receiver = 1;
optional IrExpression extension_receiver = 2;
repeated NullableIrExpression value_argument = 3;
required TypeArguments type_arguments = 4;
}
message IrCall {
@@ -101,37 +176,47 @@ message IrCall {
BINARY = 4;
}
required Primitive kind = 1;
required KotlinDescriptor descriptor = 2;
required IrSymbol symbol = 2;
required MemberAccessCommon member_access = 3;
optional KotlinDescriptor super = 4;
optional IrSymbol super = 4;
}
message IrCallableReference {
required KotlinDescriptor descriptor = 1;
required TypeArguments type_arguments = 2;
message IrFunctionReference {
required IrSymbol symbol = 1;
optional string origin = 2;
required MemberAccessCommon member_access = 3;
}
message IrPropertyReference {
optional IrSymbol field = 1;
optional IrSymbol getter = 2;
optional IrSymbol setter = 3;
optional string origin = 4;
required MemberAccessCommon member_access = 5;
}
message IrComposite {
repeated IrStatement statement = 1;
}
message IrClassReference {
required KotlinDescriptor class_descriptor = 1;
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;
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;
}
}
@@ -141,7 +226,7 @@ message IrContinue {
}
message IrDelegatingConstructorCall {
required KotlinDescriptor descriptor = 1;
required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2;
}
@@ -150,7 +235,7 @@ message IrDoWhile {
}
message IrEnumConstructorCall {
required KotlinDescriptor descriptor = 1;
required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2;
}
@@ -159,14 +244,13 @@ message IrGetClass {
}
message IrGetEnumValue {
required KotlinType type = 1;
required KotlinDescriptor descriptor = 2;
required IrSymbol symbol = 2;
}
message FieldAccessCommon {
required KotlinDescriptor descriptor = 1;
optional KotlinDescriptor super = 2;
required IrExpression receiver = 3;
required IrSymbol symbol = 1;
optional IrSymbol super = 2;
optional IrExpression receiver = 3;
}
message IrGetField {
@@ -174,15 +258,15 @@ message IrGetField {
}
message IrGetValue {
required KotlinDescriptor descriptor = 1;
required IrSymbol symbol = 1;
}
message IrGetObject {
required KotlinDescriptor descriptor = 1;
required IrSymbol symbol = 1;
}
message IrInstanceInitializerCall {
required KotlinDescriptor descriptor = 1;
required IrSymbol symbol = 1;
}
message Loop {
@@ -193,7 +277,7 @@ message Loop {
}
message IrReturn {
required KotlinDescriptor return_target = 1;
required IrSymbol return_target = 1;
required IrExpression value = 2;
}
@@ -203,7 +287,7 @@ message IrSetField {
}
message IrSetVariable {
required KotlinDescriptor descriptor = 1;
required IrSymbol symbol = 1;
required IrExpression value = 2;
}
@@ -213,7 +297,7 @@ message IrSpreadElement {
}
message IrStringConcat {
repeated IrExpression argument = 1;
repeated IrExpression argument = 1;
}
message IrThrow {
@@ -228,12 +312,12 @@ message IrTry {
message IrTypeOp {
required IrTypeOperator operator = 1;
required KotlinType operand = 2;
required IrTypeIndex operand = 2;
required IrExpression argument = 3;
}
message IrVararg {
required KotlinType element_type = 1;
required IrTypeIndex element_type = 1;
repeated IrVarargElement element = 2;
}
@@ -259,30 +343,31 @@ message IrOperation {
IrBlock block = 1;
IrBreak break = 2;
IrCall call = 3;
IrCallableReference callable_reference = 4;
IrClassReference class_reference = 27;
IrConst const = 5;
IrComposite composite = 26;
IrContinue continue = 6;
IrDelegatingConstructorCall delegating_constructor_call = 7;
IrDoWhile do_while = 25;
IrEnumConstructorCall enum_constructor_call = 8;
IrGetClass get_class = 24;
IrGetEnumValue get_enum_value = 9;
IrGetField get_field = 10;
IrGetValue get_value = 11;
IrGetObject get_object = 12;
IrInstanceInitializerCall instance_initializer_call = 13;
IrReturn return = 14;
IrSetField set_field = 15;
IrSetVariable set_variable = 16;
IrStringConcat string_concat = 17;
IrThrow throw = 18;
IrTry try = 19;
IrTypeOp type_op = 20;
IrVararg vararg = 21;
IrWhen when = 22;
IrWhile while = 23;
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;
}
}
@@ -291,14 +376,17 @@ enum IrTypeOperator {
IMPLICIT_CAST = 2;
IMPLICIT_NOTNULL = 3;
IMPLICIT_COERCION_TO_UNIT = 4;
SAFE_CAST = 5;
INSTANCEOF = 6;
NOT_INSTANCEOF = 7;
IMPLICIT_INTEGER_COERCION = 5;
SAFE_CAST = 6;
INSTANCEOF = 7;
NOT_INSTANCEOF = 8;
SAM_CONVERSION = 9;
}
message IrExpression {
required IrOperation operation = 1;
required KotlinType type = 2;
required IrTypeIndex type = 2;
required Coordinates coordinates = 3;
}
@@ -306,59 +394,177 @@ message NullableIrExpression {
optional IrExpression expression = 1;
}
/* ------ Declarations --------------------------------------------- */
message IrTypeAlias {
// Nothing for now.
}
message IrFunction {
message DefaultArgument {
required int32 position = 1;
required IrExpression value = 2;
}
optional IrStatement body = 1;
repeated DefaultArgument default_argument = 2;
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 string 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 string visibility = 4;
required bool is_final = 5;
required bool is_external = 6;
required bool is_static = 7;
required IrTypeIndex type = 8;
}
message IrProperty {
message IrField {
required IrExpression initializer = 1;
}
required bool is_delegated = 1;
optional IrField backing_field = 2;
optional IrFunction getter = 3;
optional IrFunction setter = 4;
optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
required string name = 2;
required string 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 IrVar {
optional IrExpression initializer = 1;
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 {
repeated IrDeclaration member = 1;
required IrSymbol symbol = 1;
required string name = 2;
required ClassKind kind = 3;
required string 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 IrExpression initializer = 1;
optional IrDeclaration corresponding_class = 2;
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 symbol {
IrVar variable = 1;
IrFunction function = 2;
IrClass ir_class = 3;
oneof declarator {
IrAnonymousInit ir_anonymous_init = 1;
IrClass ir_class = 2;
IrConstructor ir_constructor = 3;
IrEnumEntry ir_enum_entry = 4;
IrProperty ir_property = 5;
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 IrDeclarationOrigin {
required string name = 1;
}
message IrDeclaration {
required KotlinDescriptor descriptor = 1;
required IrDeclarationOrigin origin = 1;
required Coordinates coordinates = 2;
required IrDeclarator declarator = 3;
repeated IrDeclaration nested = 4;
required string file_name = 5;
required Annotations annotations = 3;
required IrDeclarator declarator = 4;
//repeated IrDeclaration nested = 5;
required string file_name = 5; // TODO: files should be communicated some other way, I suppose.
}
/* ------- IrStatements --------------------------------------------- */
@@ -377,6 +583,15 @@ message IrCatch {
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;
@@ -386,6 +601,6 @@ message IrStatement {
IrBlockBody block_body = 4;
IrBranch branch = 5;
IrCatch catch = 6;
IrSyntheticBody synthetic_body = 7;
}
}
@@ -0,0 +1,340 @@
/*
* 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.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 deserializedModuleProtoTypeTables = mutableMapOf<ModuleDescriptor, KonanIr.IrTypeTable>()
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 ->
IrFieldSymbolImpl(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)
}
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)
= descriptorReferenceDeserializer.deserializeDescriptorReference(proto)
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)
reachableTopLevels.add(topLevelKey)
// TODO: This is a mess. Cleanup!
do {
val key = reachableTopLevels.first()
if (deserializedSymbols[key]?.isBound == true) {
reachableTopLevels.remove(key)
continue
}
val previousModuleDescriptor = deserializedModuleDescriptor
deserializedModuleDescriptor = key.moduleOfOrigin
if (deserializedModuleDescriptor == null) {
deserializedModuleDescriptor = previousModuleDescriptor
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
continue
}
val reachable = deserializeTopLevelDeclaration(key)
deserializedModuleDescriptor = previousModuleDescriptor
reversedFileIndex[key]!!.declarations.add(reachable)
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 declaration = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
it.descriptor as ClassDescriptor,
{ symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) }
)
declaration
}
file.declarations.addAll(declarations)
file
}
}
fun deserializeIrFile(fileProto: KonanIr.IrFile, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(fileProto.fileEntry.name)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = if (fileProto.fqName == "<root>") FqName.ROOT else FqName(fileProto.fqName)
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 (deserializeAllDeclarations) {
file.declarations.add(deserializeTopLevelDeclaration(uniqIdKey))
}
}
return file
}
fun deserializeIrModule(proto: KonanIr.IrModule, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrModuleFragment {
deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
val files = proto.fileList.map {
deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null)
return module
}
fun deserializeIrModule(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializeAllDeclarations: Boolean = false): IrModuleFragment {
val proto = KonanIr.IrModule.parseFrom(byteArray.codedInputStream, KonanSerializerProtocol.extensionRegistry)
return deserializeIrModule(proto, moduleDescriptor, deserializeAllDeclarations)
}
}
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.backend.konan.serialization
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.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.config.LanguageVersionSettings
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -32,7 +35,7 @@ import org.jetbrains.kotlin.serialization.konan.SourceFileMap
* with MemberDeserializer class.
*/
internal class KonanSerializationUtil(val context: Context, private val metadataVersion: BinaryVersion) {
internal class KonanSerializationUtil(val context: Context, val metadataVersion: BinaryVersion, val declarationTable: DeclarationTable) {
lateinit var serializerContext: SerializerContext
@@ -43,9 +46,8 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
val topSerializer: DescriptorSerializer,
var classSerializer: DescriptorSerializer = topSerializer
)
private fun createNewContext(): SerializerContext {
val extension = KonanSerializerExtension(context, metadataVersion, sourceFileMap)
val extension = KonanSerializerExtension(context, metadataVersion, sourceFileMap, declarationTable)
return SerializerContext(
extension,
DescriptorSerializer.createTopLevel(extension)
@@ -63,9 +65,9 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
with(serializerContext) {
val previousSerializer = classSerializer
// TODO: this is to filter out object{}. Change me.
if (classDescriptor.isExported())
classSerializer = DescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer)
// TODO: this is to filter out object{}. Change me.
// if (classDescriptor.isExported())
// classSerializer = KonanDescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer)
val classProto = classSerializer.classProto(classDescriptor).build()
?: error("Class not serialized: $classDescriptor")
@@ -207,7 +209,7 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
.build()
}
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData {
internal fun serializeModule(moduleDescriptor: ModuleDescriptor, serializedIr: SerializedIr): LinkData {
val libraryProto = KonanProtoBuf.LinkDataLibrary.newBuilder()
libraryProto.moduleName = moduleDescriptor.name.asString()
val fragments = mutableListOf<List<ByteArray>>()
@@ -233,7 +235,7 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
}
val libraryAsByteArray = libraryProto.build().toByteArray()
return LinkData(libraryAsByteArray, fragments, fragmentNames)
return LinkData(libraryAsByteArray, fragments, fragmentNames, serializedIr)
}
}
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.onlyIf
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.needsSerializedIr
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
@@ -22,15 +20,19 @@ 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) :
KotlinSerializerExtensionBase(KonanSerializerProtocol), IrAwareExtension {
val sourceFileMap: SourceFileMap, val declarationTable: DeclarationTable) :
KotlinSerializerExtensionBase(KonanSerializerProtocol) {
val inlineDescriptorTable = DescriptorTable(context.irBuiltIns)
override val stringTable = KonanStringTable()
override fun shouldUseTypeTable(): Boolean = true
fun uniqId(descriptor: DeclarationDescriptor): KonanProtoBuf.DescriptorUniqId? {
val index = declarationTable.descriptorTable.get(descriptor)
return index?.let { newDescriptorUniqId(it) }
}
override fun serializeType(type: KotlinType, proto: ProtoBuf.Type.Builder) {
// TODO: For debugging purpose we store the textual
// TODO: For debugging purpose we store the textual
// representation of serialized types.
// To be removed.
proto.setExtension(KonanProtoBuf.typeText, type.toString())
@@ -38,95 +40,58 @@ internal class KonanSerializerExtension(val context: Context, override val metad
super.serializeType(type, proto)
}
override fun serializeTypeParameter(typeParameter: TypeParameterDescriptor, proto: ProtoBuf.TypeParameter.Builder) {
uniqId(typeParameter) ?.let { proto.setExtension(KonanProtoBuf.typeParamUniqId, it) }
super.serializeTypeParameter(typeParameter, proto)
}
override fun serializeValueParameter(descriptor: ValueParameterDescriptor, proto: ProtoBuf.ValueParameter.Builder) {
uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.valueParamUniqId, it) }
super.serializeValueParameter(descriptor, proto)
}
override fun serializeEnumEntry(descriptor: ClassDescriptor, proto: ProtoBuf.EnumEntry.Builder) {
uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.enumEntryUniqId, it) }
// Serialization doesn't preserve enum entry order, so we need to serialize ordinal.
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(descriptor)
proto.setExtension(KonanProtoBuf.enumEntryOrdinal, ordinal)
super.serializeEnumEntry(descriptor, proto)
}
override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder,
childSerializer: DescriptorSerializer) {
super.serializeConstructor(descriptor, proto, childSerializer)
if (descriptor.needsSerializedIr) {
addConstructorIR(proto, serializeInlineBody(descriptor, childSerializer))
}
}
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable,
childSerializer: DescriptorSerializer) {
uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.classUniqId, it) }
super.serializeClass(descriptor, proto, versionRequirementTable, childSerializer)
context.ir.classesDelegatedBackingFields[descriptor]?.forEach {
proto.addProperty(childSerializer.propertyProto(it))
}
// Invocation of the propertyProto above can add more types
// to the type table that should also be serialized.
childSerializer.typeTable.serialize()?.let { proto.mergeTypeTable(it) }
}
override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder,
childSerializer: DescriptorSerializer) {
uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.constructorUniqId, it) }
super.serializeConstructor(descriptor, proto, childSerializer)
}
override fun serializeFunction(descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder,
childSerializer: DescriptorSerializer) {
proto.setExtension(KonanProtoBuf.functionFile, sourceFileMap.assign(descriptor.source.containingFile))
uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.functionUniqId, it) }
super.serializeFunction(descriptor, proto, childSerializer)
if (descriptor.needsSerializedIr) {
addFunctionIR(proto, serializeInlineBody(descriptor, childSerializer))
}
}
override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder,
versionRequirementTable: MutableVersionRequirementTable,
childSerializer: DescriptorSerializer) {
val variable = originalVariables[descriptor]
if (variable != null) {
proto.setExtension(KonanProtoBuf.usedAsVariable, true)
}
proto.setExtension(KonanProtoBuf.propertyFile, sourceFileMap.assign(descriptor.source.containingFile))
uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.propertyUniqId, it) }
proto.setExtension(KonanProtoBuf.hasBackingField,
context.ir.propertiesWithBackingFields.contains(descriptor))
super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer)
/* Konan specific chunk */
descriptor.getter?.onlyIf({ needsSerializedIr }) {
addGetterIR(proto, serializeInlineBody(it, childSerializer))
}
descriptor.setter?.onlyIf({ needsSerializedIr }) {
addSetterIR(proto, serializeInlineBody(it, childSerializer))
}
}
override fun addFunctionIR(proto: ProtoBuf.Function.Builder, serializedIR: String)
= proto.setInlineIr(inlineBody(serializedIR))
override fun addConstructorIR(proto: ProtoBuf.Constructor.Builder, serializedIR: String)
= proto.setConstructorIr(inlineBody(serializedIR))
override fun addGetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String)
= proto.setGetterIr(inlineBody(serializedIR))
override fun addSetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String)
= proto.setSetterIr(inlineBody(serializedIR))
override fun serializeInlineBody(descriptor: FunctionDescriptor, serializer: DescriptorSerializer): String {
return IrSerializer(
context, inlineDescriptorTable, stringTable, serializer, descriptor).serializeInlineBody()
}
override fun releaseCoroutines(): Boolean =
context.config.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
}
internal interface IrAwareExtension {
fun serializeInlineBody(descriptor: FunctionDescriptor, serializer: DescriptorSerializer): String
fun addFunctionIR(proto: ProtoBuf.Function.Builder, serializedIR: String): ProtoBuf.Function.Builder
fun addConstructorIR(proto: ProtoBuf.Constructor.Builder, serializedIR: String): ProtoBuf.Constructor.Builder
fun addSetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String): ProtoBuf.Property.Builder
fun addGetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String): ProtoBuf.Property.Builder
}
@@ -1,140 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.descriptors.allContainingDeclarations
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.konan.KonanMetadataVersion
import org.jetbrains.kotlin.serialization.konan.KonanPackageFragment
// This class knows how to construct contexts for
// MemberDeserializer to deserialize descriptors declared in IR.
// Eventually, these descriptors shall be reconstructed from IR declarations,
// or may be just go away completely.
class LocalDeclarationDeserializer(val rootDescriptor: DeclarationDescriptor) {
val tower: List<DeclarationDescriptor> =
(listOf(rootDescriptor) + rootDescriptor.allContainingDeclarations()).reversed()
init {
assert(tower.first() is ModuleDescriptor)
}
val parents = tower.drop(1)
val pkg = parents.first() as KonanPackageFragment
val components = pkg.components
val nameTable = pkg.proto.nameTable
val nameResolver = NameResolverImpl(pkg.proto.stringTable, nameTable)
val contextStack = mutableListOf<Pair<DeserializationContext, MemberDeserializer>>()
init {
parents.forEach{
pushContext(it)
}
}
val parentContext: DeserializationContext
get() = contextStack.peek()!!.first
val parentTypeTable: TypeTable
get() = parentContext.typeTable
val typeDeserializer: TypeDeserializer
get() = parentContext.typeDeserializer
val memberDeserializer: MemberDeserializer
get() = contextStack.peek()!!.second
fun newContext(descriptor: DeclarationDescriptor): DeserializationContext {
if (descriptor is KonanPackageFragment) {
val packageTypeTable = TypeTable(pkg.proto.getPackage().typeTable)
/* TODO: Check metadata version usege here. */
return components.createContext(
pkg, nameResolver, packageTypeTable, VersionRequirementTable.EMPTY, KonanMetadataVersion.INSTANCE, null)
}
// Only packages and classes have their type tables.
val typeTable = if (descriptor is DeserializedClassDescriptor) {
TypeTable(descriptor.classProto.typeTable)
} else {
parentTypeTable
}
val oldContext = contextStack.peek()!!.first
return oldContext.childContext(descriptor,
descriptor.typeParameterProtos, nameResolver, typeTable)
}
fun pushContext(descriptor: DeclarationDescriptor) {
val newContext = newContext(descriptor)
contextStack.push(Pair(newContext, MemberDeserializer(newContext)))
}
fun popContext(descriptor: DeclarationDescriptor) {
assert(contextStack.peek()!!.first.containingDeclaration == descriptor)
contextStack.pop()
}
fun deserializeInlineType(type: ProtoBuf.Type) = typeDeserializer.type(type)
fun deserializeClass(irProto: KonanIr.KotlinDescriptor): ClassDescriptor {
/* TODO: metadata version should be fixed. */
return DeserializedClassDescriptor(parentContext, irProto.irLocalDeclaration.descriptor.clazz, nameResolver, KonanMetadataVersion.INSTANCE, SourceElement.NO_SOURCE)
}
fun deserializeFunction(irProto: KonanIr.KotlinDescriptor): FunctionDescriptor =
memberDeserializer.loadFunction(irProto.irLocalDeclaration.descriptor.function)
fun deserializeConstructor(irProto: KonanIr.KotlinDescriptor): ConstructorDescriptor {
val proto = irProto.irLocalDeclaration.descriptor.constructor
val isPrimary = !Flags.IS_SECONDARY.get(proto.flags)
return memberDeserializer.loadConstructor(proto, isPrimary)
}
fun deserializeProperty(irProto: KonanIr.KotlinDescriptor): VariableDescriptor {
val proto = irProto.irLocalDeclaration.descriptor.property
val property = memberDeserializer.loadProperty(proto)
return if (proto.getExtension(KonanProtoBuf.usedAsVariable)) {
propertyToVariable(property)
} else {
property
}
}
private fun propertyToVariable(property: PropertyDescriptor): LocalVariableDescriptor {
// TODO: Should we transform the getter and the setter too?
@Suppress("DEPRECATION")
return LocalVariableDescriptor(
property.containingDeclaration,
property.annotations,
property.name,
property.type,
property.isVar,
property.isDelegated,
SourceElement.NO_SOURCE)
}
}
@@ -1,119 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
import org.jetbrains.kotlin.descriptors.Modality.FINAL
import org.jetbrains.kotlin.descriptors.SourceElement.NO_SOURCE
import org.jetbrains.kotlin.descriptors.Visibilities.INTERNAL
import org.jetbrains.kotlin.descriptors.annotations.Annotations.Companion.EMPTY
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.types.KotlinType
/*
* This class knows how to create DescriptorSerializer
* invocations to serialize function local declaration descriptors.
* Those descriptors are not part of the public descriptor tree.
*
* We maintain the stack of the serializers because this class
* provides type serialization facility for all the types in IR.
* And class serialization is context specific.
*/
internal class LocalDeclarationSerializer(val context: Context, val rootFunctionSerializer: DescriptorSerializer) {
private val contextStack = mutableListOf(rootFunctionSerializer)
fun pushContext(descriptor: DeclarationDescriptor) {
val previousContext = contextStack.peek()!!
val newSerializer = previousContext.createChildSerializer(descriptor)
contextStack.push(newSerializer)
}
fun popContext() {
contextStack.pop()
}
val localSerializer
get() = contextStack.peek()!!
fun typeSerializer(type: KotlinType) = localSerializer.typeId(type)
fun serializeLocalDeclaration(descriptor: DeclarationDescriptor): KonanIr.DeclarationDescriptor {
val proto = KonanIr.DeclarationDescriptor.newBuilder()
context.log{"### serializeLocalDeclaration: $descriptor"}
when (descriptor) {
is ClassConstructorDescriptor ->
proto.setConstructor(localSerializer.constructorProto(descriptor))
is FunctionDescriptor ->
proto.setFunction(localSerializer.functionProto(descriptor))
is PropertyDescriptor ->
proto.setProperty(localSerializer.propertyProto(descriptor))
is ClassDescriptor ->
proto.setClazz(localSerializer.classProto(descriptor))
is VariableDescriptor -> {
val property = variableAsProperty(descriptor)
originalVariables.put(property, descriptor)
proto.setProperty(localSerializer.propertyProto(property))
}
else -> error("Unexpected descriptor kind: $descriptor")
}
return proto.build()
}
// TODO: We utilize DescriptorSerializer's property
// serialization to serialize variables for now.
// Need to introduce an extension protobuf message
// and serialize variables directly.
private fun variableAsProperty(variable: VariableDescriptor): PropertyDescriptor {
@Suppress("DEPRECATION")
val isDelegated = when (variable) {
is LocalVariableDescriptor -> variable.isDelegated
is IrTemporaryVariableDescriptor -> false
else -> error("Unexpected variable descriptor.")
}
val property = PropertyDescriptorImpl.create(
variable.containingDeclaration,
EMPTY,
FINAL,
INTERNAL,
variable.isVar(),
variable.name,
DECLARATION,
NO_SOURCE,
false, false, false, false, false,
isDelegated)
property.setType(variable.type, listOf(), null, null)
// TODO: transform the getter and the setter too.
property.initialize(null, null)
return property
}
}
val originalVariables = mutableMapOf<PropertyDescriptor, VariableDescriptor>()
@@ -1,109 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf.*
import org.jetbrains.kotlin.metadata.ProtoBuf
fun newUniqId(index: Long): KonanIr.UniqId =
KonanIr.UniqId.newBuilder().setIndex(index).build()
// -----------------------------------------------------------
val KonanIr.KotlinDescriptor.index: Long
get() = this.uniqId.index
fun KonanIr.KotlinDescriptor.Builder.setIndex(index: Long)
= this.setUniqId(newUniqId(index))
val KonanIr.KotlinDescriptor.originalIndex: Long
get() = this.originalUniqId.index
fun KonanIr.KotlinDescriptor.Builder.setOriginalIndex(index: Long)
= this.setOriginalUniqId(newUniqId(index))
val KonanIr.KotlinDescriptor.dispatchReceiverIndex: Long
get() = this.dispatchReceiverUniqId.index
fun KonanIr.KotlinDescriptor.Builder.setDispatchReceiverIndex(index: Long)
= this.setDispatchReceiverUniqId(newUniqId(index))
val KonanIr.KotlinDescriptor.extensionReceiverIndex: Long
get() = this.extensionReceiverUniqId.index
fun KonanIr.KotlinDescriptor.Builder.setExtensionReceiverIndex(index: Long)
= this.setExtensionReceiverUniqId(newUniqId(index))
// -----------------------------------------------------------
val ProtoBuf.Property.getterIr: InlineIrBody
get() = this.getExtension(inlineGetterIrBody)
fun ProtoBuf.Property.Builder.setGetterIr(body: InlineIrBody): ProtoBuf.Property.Builder =
this.setExtension(inlineGetterIrBody, body)
val ProtoBuf.Property.setterIr: InlineIrBody
get() = this.getExtension(inlineSetterIrBody)
fun ProtoBuf.Property.Builder.setSetterIr(body: InlineIrBody): ProtoBuf.Property.Builder =
this.setExtension(inlineSetterIrBody, body)
val ProtoBuf.Constructor.constructorIr: InlineIrBody
get() = this.getExtension(inlineConstructorIrBody)
fun ProtoBuf.Constructor.Builder.setConstructorIr(body: InlineIrBody): ProtoBuf.Constructor.Builder =
this.setExtension(inlineConstructorIrBody, body)
val ProtoBuf.Function.inlineIr: InlineIrBody
get() = this.getExtension(inlineIrBody)
fun ProtoBuf.Function.Builder.setInlineIr(body: InlineIrBody): ProtoBuf.Function.Builder =
this.setExtension(inlineIrBody, body)
// -----------------------------------------------------------
fun inlineBody(encodedIR: String)
= KonanProtoBuf.InlineIrBody
.newBuilder()
.setEncodedIr(encodedIR)
.build()
// -----------------------------------------------------------
internal fun printType(proto: ProtoBuf.Type) {
println("debug text: " + proto.getExtension(KonanProtoBuf.typeText))
}
internal fun printTypeTable(proto: ProtoBuf.TypeTable) {
proto.getTypeList().forEach {
printType(it)
}
}
// -----------------------------------------------------------
internal val DeclarationDescriptor.typeParameterProtos: List<ProtoBuf.TypeParameter>
get() = when (this) {
// These are different typeParameterLists not
// having a common ancestor.
is DeserializedSimpleFunctionDescriptor
-> this.proto.typeParameterList
is DeserializedPropertyDescriptor
-> this.proto.typeParameterList
is DeserializedClassDescriptor
-> this.classProto.typeParameterList
is DeserializedTypeAliasDescriptor
-> this.proto.typeParameterList
is DeserializedClassConstructorDescriptor
-> listOf()
else -> error("Unexpected descriptor kind: $this")
}
@@ -0,0 +1,109 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isAccessor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isGetter
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSetter
import org.jetbrains.kotlin.backend.konan.irasdescriptors.name
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) {
// 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(packageFqName)
.setClassFqName(classFqName)
.setName(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()
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.llvm.localHash
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)
}
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 =
KonanProtoBuf.DescriptorUniqId.newBuilder().setIndex(index).build()
@@ -0,0 +1,72 @@
package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.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"
}
@@ -7,6 +7,10 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.substitute
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException
@@ -30,6 +34,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
@@ -40,6 +45,9 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.types.*
@@ -619,7 +627,12 @@ fun createField(
}
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
assert(this.descriptor.type == newDescriptor.type)
// Aggressive use of WrappedDescriptors during deserialization
// makes these types different.
// Let's hope they not really used afterwards.
//assert(this.descriptor.type == newDescriptor.type) {
// "type1 = ${this.descriptor.type} != type2 = ${newDescriptor.type}"
//}
return IrValueParameterImpl(
startOffset,
@@ -637,7 +650,7 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean
get() = this is IrSimpleType && this.hasQuestionMark
fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) =
if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType
if (hasQuestionMark) this.defaultType.makeNullable(false) else this.defaultType
fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean =
this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
-1
View File
@@ -3109,7 +3109,6 @@ task library_mismatch(type: RunStandaloneKonanTest) {
doFirst {
def konancScript = isWindows() ? "konanc.bat" : "konanc"
def konanc = "$dist/bin/$konancScript"
"$konanc $lib -p library -o $dir/1.2/empty -target $currentTarget -lv 1.2".execute().waitFor()
"$konanc $lib -p library -o $dir/3.4/empty -target $someOtherTarget".execute().waitFor()
"$konanc $lib -p library -o $dir/5.6/empty -target $currentTarget -lv 5.6".execute().waitFor()
+4 -1
View File
@@ -397,7 +397,10 @@ task bundle(type: (isWindows()) ? Zip : Tar) {
}
destinationDir = file('.')
if (!isWindows()) {
if (isWindows()) {
zip64 true
} else {
extension = 'tar.gz'
compression = Compression.GZIP
}
@@ -100,7 +100,7 @@ abstract class KonanTest extends JavaExec {
classpath = project.fileTree("$dist.canonicalPath/konan/lib/") {
include '*.jar'
}
jvmArgs "-Dkonan.home=${dist.canonicalPath}", "-Xmx2G",
jvmArgs "-Dkonan.home=${dist.canonicalPath}", "-Xmx4G",
"-Djava.library.path=${dist.canonicalPath}/konan/nativelib"
enableAssertions = true
def sources = File.createTempFile(name,".lst")
@@ -16,23 +16,30 @@ option optimize_for = LITE_RUNTIME;
// Konan extensions to the "descriptors" protobuf.
message DescriptorUniqId {
required int64 index = 1;
}
extend Package {
optional int32 package_fq_name = 171;
}
extend Class {
repeated Annotation class_annotation = 170;
optional DescriptorUniqId class_uniq_id = 171;
}
extend Constructor {
repeated Annotation constructor_annotation = 170;
optional InlineIrBody inline_constructor_ir_body = 171;
optional DescriptorUniqId constructor_uniq_id = 172;
}
extend Function {
repeated Annotation function_annotation = 170;
optional InlineIrBody inline_ir_body = 171;
optional int32 function_file = 172;
optional DescriptorUniqId function_uniq_id = 173;
}
extend Property {
@@ -45,15 +52,18 @@ extend Property {
optional InlineIrBody inline_getter_ir_body = 174;
optional InlineIrBody inline_setter_ir_body = 175;
optional int32 property_file = 176;
optional DescriptorUniqId property_uniq_id = 179;
}
extend EnumEntry {
repeated Annotation enum_entry_annotation = 170;
optional int32 enum_entry_ordinal = 171;
optional DescriptorUniqId enum_entry_uniq_id = 172;
}
extend ValueParameter {
repeated Annotation parameter_annotation = 170;
optional DescriptorUniqId value_param_uniq_id = 171;
}
extend Type {
@@ -63,6 +73,7 @@ extend Type {
extend TypeParameter {
repeated Annotation type_parameter_annotation = 170;
optional DescriptorUniqId type_param_uniq_id = 171;
}
message InlineIrBody {
@@ -1,3 +1,19 @@
/*
* Copyright 2010-2019 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.konan.library.resolver.impl
import org.jetbrains.kotlin.konan.file.File
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
+1
View File
@@ -24,3 +24,4 @@ testKotlinVersion=1.3.30-dev-964
konanVersion=1.2.0
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.workers.max=4
#kotlinProjectPath=/Users/jetbrains/kotlin-native/kotlin
@@ -1,4 +1,4 @@
depends = AudioToolbox CFNetwork CoreAudio CoreFoundation CoreGraphics CoreImage CoreText CoreVideo EAGL FileProvider Foundation IOSurface ImageIO Metal OpenGLESCommon QuartzCore Security UIKit darwin posix
depends = AudioToolbox CFNetwork CoreAudio CoreFoundation CoreGraphics CoreImage CoreMIDI CoreText CoreVideo EAGL FileProvider Foundation IOSurface ImageIO Metal OpenGLESCommon QuartzCore Security UIKit darwin posix
language = Objective-C
package = platform.CoreAudioKit
headers = CoreAudioKit/CoreAudioKit.h
+1
View File
@@ -33,6 +33,7 @@ public final class Array<T> {
}
}
@PublishedApi
@ExportForCompiler
internal constructor(@Suppress("UNUSED_PARAMETER") size: Int) {}
@@ -117,9 +117,11 @@ fun <T: Enum<T>> valuesForEnum(values: Array<T>): Array<T> {
return result as Array<T>
}
@PublishedApi
@TypedIntrinsic(IntrinsicType.CREATE_UNINITIALIZED_INSTANCE)
internal external fun <T> createUninitializedInstance(): T
@PublishedApi
@TypedIntrinsic(IntrinsicType.INIT_INSTANCE)
internal external fun initInstance(thiz: Any, constructorCall: Any): Unit
@@ -157,4 +159,4 @@ internal fun <T> listOfInternal(vararg elements: T): List<T> {
for (i in 0 until elements.size)
result.add(elements[i])
return result
}
}
@@ -42,6 +42,9 @@ interface KonanLibrary {
val moduleHeaderData: ByteArray
fun packageMetadataParts(fqName: String): Set<String>
fun packageMetadata(fqName: String, partName: String): ByteArray
val irHeader: ByteArray
fun irDeclaration(index: Long, isLocal: Boolean): ByteArray
}
val KonanLibrary.uniqueName
@@ -44,4 +44,15 @@ interface KonanLibraryLayout {
fun packageFragmentFile(packageFqName: String, partName: String) =
File(packageFragmentsDir(packageFqName), "$partName$KLIB_METADATA_FILE_EXTENSION_WITH_DOT")
val irDir
get() = File(libDir, "ir")
fun hiddenDeclarationFile(declarationId: String)
= File(irDir, "hidden_$declarationId.knd")
fun visibleDeclarationFile(declarationId: String)
= File(irDir, "visible_$declarationId.knd")
val wholeIrFile
get() = File(irDir, "irHeaders.kni")
val irIndex: File
get() = File(irDir, "uniqIdTableDump.txt")
}
@@ -3,4 +3,6 @@ package org.jetbrains.kotlin.konan.library
interface MetadataReader {
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray
fun loadWholeIr(libraryLayout: KonanLibraryLayout): ByteArray
fun loadIrDeclaraton(libraryLayout: KonanLibraryLayout, index: Long, isLocal: Boolean): ByteArray
}
@@ -10,4 +10,16 @@ internal object DefaultMetadataReaderImpl : MetadataReader {
override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray =
libraryLayout.packageFragmentFile(fqName, partName).readBytes()
override fun loadWholeIr(libraryLayout: KonanLibraryLayout): ByteArray =
libraryLayout.wholeIrFile.readBytes()
override fun loadIrDeclaraton(libraryLayout: KonanLibraryLayout, index: Long, isLocal: Boolean): ByteArray {
val name = index.toULong().toString(16)
val file = if (isLocal)
libraryLayout.hiddenDeclarationFile(name)
else
libraryLayout.visibleDeclarationFile(name)
return file.readBytes()
}
}
@@ -1,3 +1,19 @@
/*
* Copyright 2010-2018 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.konan.library.impl
import org.jetbrains.kotlin.konan.file.File
@@ -9,7 +25,6 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
import org.jetbrains.kotlin.konan.util.substitute
class KonanLibraryImpl(
override val libraryFile: File,
internal val target: KonanTarget?,
@@ -69,5 +84,9 @@ class KonanLibraryImpl(
}
}
override val irHeader: ByteArray by lazy { layout.inPlace { metadataReader.loadWholeIr(it) }}
override fun irDeclaration(index: Long, isLocal: Boolean) = layout.inPlace { metadataReader.loadIrDeclaraton(it, index, isLocal) }
override fun toString() = "$libraryName[default=$isDefault]"
}
}
@@ -20,11 +20,13 @@ import kotlin.system.measureTimeMillis
import org.jetbrains.kotlin.konan.file.*
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
fun printMillisec(message: String, body: () -> Unit) {
fun <T> printMillisec(message: String, body: () -> T): T {
var result: T? = null
val msec = measureTimeMillis{
body()
result = body()
}
println("$message: $msec msec")
return result!!
}
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function: