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
@@ -13,6 +13,10 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities 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.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -263,6 +263,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
// But we have to wait until the code generation phase, // But we have to wait until the code generation phase,
// to dump this information into generated file. // to dump this information into generated file.
var serializedLinkData: LinkData? = null var serializedLinkData: LinkData? = null
var serializedIr: ByteArray? = null
var dataFlowGraph: ByteArray? = null var dataFlowGraph: ByteArray? = null
@Deprecated("") @Deprecated("")
@@ -55,7 +55,7 @@ fun IrType.computePrimitiveBinaryTypeOrNull(): PrimitiveBinaryType? =
fun IrType.computeBinaryType(): BinaryType<IrClass> = IrTypeInlineClassesSupport.computeBinaryType(this) 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) fun IrClass.isUsedAsBoxClass(): Boolean = IrTypeInlineClassesSupport.isUsedAsBoxClass(this)
/** /**
@@ -5,16 +5,20 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.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.KonanSymbols
import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex
import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM
import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializationUtil import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
import org.jetbrains.kotlin.backend.konan.serialization.markBackingFields import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
@@ -62,9 +66,30 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
context.psi2IrGeneratorContext = generatorContext 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.irModule = module
context.ir.symbols = symbols context.ir.symbols = symbols
@@ -80,10 +105,23 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
phaser.phase(KonanPhase.GEN_SYNTHETIC_FIELDS) { phaser.phase(KonanPhase.GEN_SYNTHETIC_FIELDS) {
markBackingFields(context) 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) { 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 = context.serializedLinkData =
serializer.serializeModule(context.moduleDescriptor) serializer.serializeModule(context.moduleDescriptor, serializedIr)
} }
phaser.phase(KonanPhase.BACKEND) { phaser.phase(KonanPhase.BACKEND) {
phaser.phase(KonanPhase.LOWER) { 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.backend.konan.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment 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.checkDeclarationParents
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols 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) irModule.files.forEach(InteropLoweringPart1(context)::lower)
} }
val symbolTable = context.ir.symbols.symbolTable
do {
@Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context)
} while (symbolTable.unboundClasses.isNotEmpty())
irModule.patchDeclarationParents() irModule.patchDeclarationParents()
// validateIrModule(context, irModule) // Temporarily disabled until moving to new IR finished. // 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"), /* */ PSI_TO_IR("Psi to IR conversion"),
/* */ IR_GENERATOR_PLUGINS("Plugged-in ir generators"), /* */ IR_GENERATOR_PLUGINS("Plugged-in ir generators"),
/* */ GEN_SYNTHETIC_FIELDS("Generate synthetic fields"), /* */ 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), /* */ SERIALIZER("Serialize descriptor tree and inline IR bodies", GEN_SYNTHETIC_FIELDS),
/* */ BACKEND("All backend"), /* */ BACKEND("All backend"),
/* ... */ LOWER("IR Lowering"), /* ... */ 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), /* ... ... */ RETURNS_INSERTION("Returns insertion for Unit functions", AUTOBOX, LOWER_COROUTINES, LOWER_ENUMS),
/* ... */ BITCODE("LLVM BitCode Generation"), /* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"), /* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ BUILD_DFG("Data flow graph building"), /* ... ... */ BUILD_DFG("Data flow graph building", enabled = false),
/* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing"), /* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing", enabled = false),
/* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG), /* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG, enabled = false),
/* ... ... */ ESCAPE_ANALYSIS("Escape analysis", BUILD_DFG, DESERIALIZE_DFG, enabled = false), // TODO: Requires devirtualization. /* ... ... */ 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"), /* ... ... */ CODEGEN("Code Generation"),
/* ... ... */ C_STUBS("C stubs compilation"), /* ... ... */ C_STUBS("C stubs compilation"),
/* ... ... */ BITCODE_LINKER("Bitcode linking"), /* ... ... */ 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.findPackageView
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue
import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getExternalObjCMethodInfo
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal
import org.jetbrains.kotlin.descriptors.* 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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction 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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition 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.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.supertypes
private val interopPackageName = InteropFqNames.packageName internal val interopPackageName = InteropFqNames.packageName
private val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject")) internal val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject"))
private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass")) private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass"))
internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass")) internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass"))
private val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod")) 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 objCFactoryFqName = interopPackageName.child(Name.identifier("ObjCFactory"))
private val objCBridgeFqName = interopPackageName.child(Name.identifier("ObjCBridge")) private val objCBridgeFqName = interopPackageName.child(Name.identifier("ObjCBridge"))
@Deprecated("Use IR version rather than descriptor version")
fun ClassDescriptor.isObjCClass(): Boolean = 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 this.containingDeclaration.fqNameSafe != interopPackageName
fun KotlinType.isObjCObjectType(): Boolean = fun KotlinType.isObjCObjectType(): Boolean =
(this.supertypes() + this).any { TypeUtils.getClassDescriptor(it)?.fqNameSafe == objCObjectFqName } (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() && fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() &&
this.parentsWithSelf.filterIsInstance<ClassDescriptor>().any { this.parentsWithSelf.filterIsInstance<ClassDescriptor>().any {
it.annotations.findAnnotation(externalObjCClassFqName) != null 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 { fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().any {
it.fqNameSafe == objCClassFqName it.fqNameSafe == objCClassFqName
@@ -55,15 +70,27 @@ fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().a
fun FunctionDescriptor.isObjCClassMethod() = fun FunctionDescriptor.isObjCClassMethod() =
this.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() } this.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() }
@Deprecated("Use IR version rather than descriptor version")
fun FunctionDescriptor.isExternalObjCClassMethod() = fun FunctionDescriptor.isExternalObjCClassMethod() =
this.containingDeclaration.let { it is ClassDescriptor && it.isExternalObjCClass() } 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. // 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) = fun FunctionDescriptor.canObjCClassMethodBeCalledVirtually(overriddenDescriptor: FunctionDescriptor) =
overriddenDescriptor.isOverridable && this.kind.isReal && !this.isExternalObjCClassMethod() 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 ClassDescriptor.isKotlinObjCClass(): Boolean = this.isObjCClass() && !this.isExternalObjCClass()
fun IrClass.isKotlinObjCClass(): Boolean = this.isObjCClass() && !this.isExternalObjCClass()
data class ObjCMethodInfo(val bridge: FunctionDescriptor, data class ObjCMethodInfo(val bridge: FunctionDescriptor,
val selector: String, val selector: String,
val encoding: 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 * @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 { fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean {
val annotation = this.annotations.findAnnotation(objCConstructorFqName)!! val annotation = this.annotations.findAnnotation(objCConstructorFqName)!!
val value = annotation.allValueArguments[Name.identifier("designated")]!! val value = annotation.allValueArguments[Name.identifier("designated")]!!
@@ -190,6 +244,7 @@ fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean {
return (value as BooleanValue).value return (value as BooleanValue).value
} }
fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? { fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? {
return this.annotations.findAnnotation(objCConstructorFqName)?.let { return this.annotations.findAnnotation(objCConstructorFqName)?.let {
val initSelector = it.getStringValue("initSelector") 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? { fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? {
return this.descriptor.annotations.findAnnotation(objCConstructorFqName)?.let { 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? { fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? {
val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null
val bridgeName = factoryAnnotation.getStringValue("bridge") 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.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.simpleFunctions import org.jetbrains.kotlin.ir.util.simpleFunctions
internal class OverriddenFunctionDescriptor( internal class OverriddenFunctionDescriptor(
val descriptor: SimpleFunctionDescriptor, val descriptor: IrSimpleFunction,
overriddenDescriptor: SimpleFunctionDescriptor overriddenDescriptor: IrSimpleFunction
) { ) {
val overriddenDescriptor = overriddenDescriptor.original val overriddenDescriptor = overriddenDescriptor.original
@@ -40,7 +41,7 @@ internal class OverriddenFunctionDescriptor(
&& descriptor.target.overrides(overriddenDescriptor) && descriptor.target.overrides(overriddenDescriptor)
&& descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded() && descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded()
fun getImplementation(context: Context): SimpleFunctionDescriptor? { fun getImplementation(context: Context): IrSimpleFunction? {
val target = descriptor.target val target = descriptor.target
val implementation = if (!needBridge) val implementation = if (!needBridge)
target target
@@ -154,7 +155,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con
inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.uniqueId } inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.uniqueId }
} }
fun vtableIndex(function: SimpleFunctionDescriptor): Int { fun vtableIndex(function: IrSimpleFunction): Int {
val bridgeDirections = function.target.bridgeDirectionsTo(function.original) val bridgeDirections = function.target.bridgeDirectionsTo(function.original)
val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections } val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections }
if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString()) 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 // 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() = get() =
this.simpleFunctions() this.simpleFunctions()
.filter { (it.isOverridable || it.overriddenSymbols.isNotEmpty()) .filter { (it.isOverridable || it.overriddenSymbols.isNotEmpty())
@@ -5,15 +5,18 @@
package org.jetbrains.kotlin.backend.konan.descriptors 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.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ConstructorDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.ConstructorDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.DeclarationDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.DeclarationDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.PackageFragmentDescriptor 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.backend.konan.isInlined
import org.jetbrains.kotlin.descriptors.* 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.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.types.SimpleType 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 * 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) { if (this.isReal) {
return this return this
} }
@@ -72,7 +75,7 @@ internal fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction {
realSupers.toList().forEach { excludeOverridden(it) } 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. // 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) internal fun FunctionDescriptor.needBridgeTo(target: FunctionDescriptor)
= (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) } = (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 get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
internal val FunctionDescriptor.target: FunctionDescriptor get() = when (this) { internal val FunctionDescriptor.target: FunctionDescriptor get() = when (this) {
is SimpleFunctionDescriptor -> this.target is IrSimpleFunction -> this.target
is ConstructorDescriptor -> this is ConstructorDescriptor -> this
else -> error(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() { get() {
val result = mutableSetOf<SimpleFunctionDescriptor>() val result = mutableSetOf<IrSimpleFunction>()
fun traverse(function: SimpleFunctionDescriptor) { fun traverse(function: IrSimpleFunction) {
if (function in result) return if (function in result) return
result += function result += function
function.overriddenSymbols.forEach { traverse(it.owner) } function.overriddenSymbols.forEach { traverse(it.owner) }
@@ -200,8 +203,8 @@ val SimpleFunctionDescriptor.allOverriddenDescriptors: Set<SimpleFunctionDescrip
return result return result
} }
internal fun SimpleFunctionDescriptor.bridgeDirectionsTo( internal fun IrSimpleFunction.bridgeDirectionsTo(
overriddenDescriptor: SimpleFunctionDescriptor overriddenDescriptor: IrSimpleFunction
): BridgeDirections { ): BridgeDirections {
val ourDirections = BridgeDirections(this.valueParameters.size) val ourDirections = BridgeDirections(this.valueParameters.size)
for (index in ourDirections.array.indices) for (index in ourDirections.array.indices)
@@ -226,3 +229,23 @@ tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescrip
fun FunctionDescriptor.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean = 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.RuntimeNames
import org.jetbrains.kotlin.backend.konan.binaryTypeIsReference import org.jetbrains.kotlin.backend.konan.binaryTypeIsReference
import org.jetbrains.kotlin.backend.konan.isObjCClass 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.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType 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.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl 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.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue 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.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope 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 * 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) { if (this.kind.isReal) {
return this return this
} else { } else {
@@ -52,7 +57,7 @@ internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
val filtered = OverridingUtil.filterOutOverridden(overridden) val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first? // TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST") @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 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.isUnit() = this.defaultType.isUnit()
internal fun ClassDescriptor.isNothing() = this.defaultType.isNothing() internal fun ClassDescriptor.isNothing() = this.defaultType.isNothing()
@@ -159,9 +173,6 @@ internal val FunctionDescriptor.needsInlining: Boolean
return (this.isInline && !this.isExternal) return (this.isInline && !this.isExternal)
} }
internal val FunctionDescriptor.needsSerializedIr: Boolean
get() = (this.needsInlining && this.isExported())
fun AnnotationDescriptor.getStringValueOrNull(name: String): String? { fun AnnotationDescriptor.getStringValueOrNull(name: String): String? {
val constantValue = this.allValueArguments.entries.atMostOne { val constantValue = this.allValueArguments.entries.atMostOne {
it.key.asString() == name it.key.asString() == name
@@ -199,6 +210,9 @@ val ClassDescriptor.enumEntries: List<ClassDescriptor>
internal val DeclarationDescriptor.isExpectMember: Boolean internal val DeclarationDescriptor.isExpectMember: Boolean
get() = this is MemberDescriptor && this.isExpect 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? = internal fun KotlinType?.createExtensionReceiver(owner: CallableDescriptor): ReceiverParameterDescriptor? =
DescriptorFactory.createExtensionReceiverParameterForCallable( DescriptorFactory.createExtensionReceiverParameterForCallable(
owner, owner,
@@ -286,3 +300,5 @@ fun createAnnotation(
values.map { (name, value) -> Name.identifier(name) to StringValue(value) }.toMap(), values.map { (name, value) -> Name.identifier(name) to StringValue(value) }.toMap(),
SourceElement.NO_SOURCE 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.descriptors.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
val DeserializedPropertyDescriptor.konanBackingField: PropertyDescriptor? val DeserializedPropertyDescriptor.konanBackingField: PropertyDescriptor?
get() = get() =
@@ -48,4 +47,10 @@ internal val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCall
internal val CallableMemberDescriptor.isDeserializableCallable internal val CallableMemberDescriptor.isDeserializableCallable
get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor) 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 package org.jetbrains.kotlin.backend.konan.ir
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME 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.Ir
import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.konan.* 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.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* 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.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType 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.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection 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.types.typeWith
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils 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 import kotlin.properties.Delegates
// This is what Context collects about IR. // 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 kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl) val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
val getClassTypeInfo = internalFunction("getClassTypeInfo") val getClassTypeInfo = internalFunction("getClassTypeInfo")
val getObjectTypeInfo = internalFunction("getObjectTypeInfo") val getObjectTypeInfo = internalFunction("getObjectTypeInfo")
val kClassImpl = internalClass("KClassImpl") val kClassImpl = internalClass("KClassImpl")
@@ -537,3 +548,634 @@ private fun getArrayListClassDescriptor(context: Context): ClassDescriptor {
return classifier as 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 override val maxOffset: Int
get() = TODO("not implemented") //get() = TODO("not implemented")
get() = UNDEFINED_OFFSET
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int): SourceRangeInfo { 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.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.IrType 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.ir.types.toKotlinType
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module 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 val IrField.isDelegate get() = @Suppress("DEPRECATION") this.descriptor.isDelegated
internal fun IrFunction.getObjCMethodInfo() = this.descriptor.getObjCMethodInfo() 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.getExternalObjCMethodInfo() = this.descriptor.getExternalObjCMethodInfo()
internal fun IrFunction.isObjCClassMethod() = this.descriptor.isObjCClassMethod() 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 IrClass.isObjCMetaClass() = this.descriptor.isObjCMetaClass()
internal fun IrFunction.isExternalObjCClassMethod() = this.descriptor.isExternalObjCClassMethod()
internal val IrDeclaration.llvmSymbolOrigin get() = this.descriptor.llvmSymbolOrigin 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 DeclarationDescriptor = IrDeclaration
internal typealias FunctionDescriptor = IrFunction internal typealias FunctionDescriptor = IrFunction
internal typealias SimpleFunctionDescriptor = IrSimpleFunction
internal typealias ClassDescriptor = IrClass internal typealias ClassDescriptor = IrClass
internal typealias ConstructorDescriptor = IrConstructor internal typealias ConstructorDescriptor = IrConstructor
internal typealias ClassConstructorDescriptor = 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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl 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.types.*
import org.jetbrains.kotlin.ir.util.explicitParameters import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.name.ClassId 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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor 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 { fun List<IrCall>.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull {
it.annotationClass.fqNameSafe == fqName 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 package org.jetbrains.kotlin.backend.konan.library
import llvm.LLVMModuleRef import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.konan.serialization.UniqId
import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
import org.jetbrains.kotlin.konan.properties.Properties import org.jetbrains.kotlin.konan.properties.Properties
@@ -26,7 +27,14 @@ interface KonanLibraryWriter {
class LinkData( class LinkData(
val module: ByteArray, val module: ByteArray,
val fragments: List<List<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 { interface MetadataWriter {
@@ -52,6 +52,7 @@ class LibraryWriterImpl(
nativeDir.mkdirs() nativeDir.mkdirs()
includedDir.mkdirs() includedDir.mkdirs()
resourcesDir.mkdirs() resourcesDir.mkdirs()
irDir.mkdirs()
// TODO: <name>:<hash> will go somewhere around here. // TODO: <name>:<hash> will go somewhere around here.
manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName) manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName)
manifestProperties.writeKonanLibraryVersioning(versions) manifestProperties.writeKonanLibraryVersioning(versions)
@@ -12,6 +12,7 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra
fun addLinkData(linkData: LinkData) { fun addLinkData(linkData: LinkData) {
moduleHeaderFile.writeBytes(linkData.module) moduleHeaderFile.writeBytes(linkData.module)
wholeIrFile.writeBytes(linkData.ir!!.module)
linkData.fragments.forEachIndexed { index, it -> linkData.fragments.forEachIndexed { index, it ->
val packageFqName = linkData.fragmentNames[index] val packageFqName = linkData.fragmentNames[index]
val shortName = packageFqName.substringAfterLast(".") val shortName = packageFqName.substringAfterLast(".")
@@ -24,5 +25,15 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra
packageFragmentFile(packageFqName, "${withLeadingZeros(i)}_$shortName").writeBytes(fragment) 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 package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef 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.externalSymbolOrThrow
import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* 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.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.ModuleDescriptor 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), * 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. * 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 // TODO: revise
val descriptorAnnotations = this.descriptor.annotations val descriptorAnnotations = this.descriptor.annotations
if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) { if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) {
@@ -63,7 +62,7 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean {
if (this.isAnonymousObject) if (this.isAnonymousObject)
return false 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, // Currently code generator can access the constructor of the singleton,
// so ignore visibility of the constructor itself. // so ignore visibility of the constructor itself.
return constructedClass.isExported() return constructedClass.isExported()
@@ -151,11 +150,21 @@ private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, typ
private fun typeToHashString(type: IrType) private fun typeToHashString(type: IrType)
= acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type) = acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type)
private val FunctionDescriptor.signature: String internal val IrValueParameter.extensionReceiverNamePart: String
get() = "@${typeToHashString(this.type)}."
private val IrFunction.signature: String
get() { get() {
val extensionReceiverPart = this.extensionReceiverParameter?.let { "@${typeToHashString(it.type)}." } ?: "" val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
val argsPart = this.valueParameters.map { 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(";") }.joinToString(";")
// Distinguish value types and references - it's needed for calling virtual methods through bridges. // 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. // 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 // TODO: rename to indicate that it has signature included
internal val FunctionDescriptor.functionName: String internal val IrFunction.functionName: String
get() { get() {
with(this.original) { // basic support for generics with(this.original) { // basic support for generics
this.getObjCMethodInfo()?.let { (if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
return buildString { return buildString {
if (extensionReceiverParameter != null) { if (extensionReceiverParameter != null) {
append(extensionReceiverParameter!!.type.getClass()!!.name) append(extensionReceiverParameter!!.type.getClass()!!.name)
@@ -182,6 +191,20 @@ internal val FunctionDescriptor.functionName: String
append("objc:") append("objc:")
append(it.selector) 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" "$this\$$moduleName"
} }
internal val FunctionDescriptor.symbolName: String internal val IrFunction.symbolName: String
get() { get() {
if (!this.isExported()) { if (!this.isExported()) {
throw AssertionError(this.descriptor.toString()) throw AssertionError(this.descriptor.toString())
@@ -231,15 +254,15 @@ internal val IrField.symbolName: String
val containingDeclarationPart = parent.fqNameSafe.let { val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it." if (it.isRoot) "" else "$it."
} }
return "kprop:$containingDeclarationPart$name" return "kfield:$containingDeclarationPart$name"
} }
// TODO: bring here dependencies of this method? // 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 original = function.original
val returnType = when { val returnType = when {
original is ConstructorDescriptor -> voidType original is IrConstructor -> voidType
original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?. original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?.
else -> getLLVMReturnType(original.returnType) else -> getLLVMReturnType(original.returnType)
} }
@@ -259,19 +282,21 @@ internal fun RuntimeAware.getLlvmFunctionType(symbol: DataFlowIR.FunctionSymbol)
return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray()) return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray())
} }
internal val ClassDescriptor.typeInfoSymbolName: String internal val IrClass.typeInfoSymbolName: String
get() { get() {
assert (this.isExported()) assert (this.isExported())
return "ktype:" + this.fqNameSafe.toString() return "ktype:" + this.fqNameSafe.toString()
} }
internal val ClassDescriptor.writableTypeInfoSymbolName: String internal val IrClass.writableTypeInfoSymbolName: String
get() { get() {
assert (this.isExported()) assert (this.isExported())
return "ktypew:" + this.fqNameSafe.toString() return "ktypew:" + this.fqNameSafe.toString()
} }
internal val ClassDescriptor.objectInstanceFieldSymbolName: String internal val theUnitInstanceName = "kobj:kotlin.Unit"
internal val IrClass.objectInstanceFieldSymbolName: String
get() { get() {
assert (this.isExported()) assert (this.isExported())
assert (this.kind.isSingleton) assert (this.kind.isSingleton)
@@ -280,7 +305,7 @@ internal val ClassDescriptor.objectInstanceFieldSymbolName: String
return "kobjref:$fqNameSafe" return "kobjref:$fqNameSafe"
} }
internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String internal val IrClass.objectInstanceShadowFieldSymbolName: String
get() { get() {
assert (this.isExported()) assert (this.isExported())
assert (this.kind.isSingleton) assert (this.kind.isSingleton)
@@ -290,7 +315,7 @@ internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String
return "kshadowobjref:$fqNameSafe" return "kshadowobjref:$fqNameSafe"
} }
internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean internal val IrClass.typeInfoHasVtableAttached: Boolean
get() = !this.isAbstract() && !this.isExternalObjCClass() get() = !this.isAbstract() && !this.isExternalObjCClass()
internal fun ModuleDescriptor.privateFunctionSymbolName(index: Int, functionName: String?) = "private_functions_${name.asString()}_${functionName}_$index" 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.ClassConstructorDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor
import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor 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.backend.konan.llvm.objc.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.* 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 * if toString/eq/hc is invoked on an interface instance, we resolve
* owner as Any and dispatch it via vtable. * 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 owner = (anyMethod ?: descriptor).containingDeclaration as ClassDescriptor
val llvmMethod = if (!owner.isInterface) { val llvmMethod = if (!owner.isInterface) {
@@ -146,7 +146,7 @@ internal interface ContextUtils : RuntimeAware {
fun isExternal(descriptor: DeclarationDescriptor): Boolean { fun isExternal(descriptor: DeclarationDescriptor): Boolean {
val pkg = descriptor.findPackage() val pkg = descriptor.findPackage()
return when (pkg) { return when (pkg) {
is IrFile -> false is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor
is IrExternalPackageFragment -> true is IrExternalPackageFragment -> true
else -> error(pkg) else -> error(pkg)
} }
@@ -601,7 +601,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return return
} }
if (declaration.isObjCConstructor()) { if (declaration.isObjCConstructor) {
// Do not generate any ctors for external Objective-C classes. // Do not generate any ctors for external Objective-C classes.
return return
} }
@@ -1996,7 +1996,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateFunctionReference(expression: IrFunctionReference): LLVMValueRef { private fun evaluateFunctionReference(expression: IrFunctionReference): LLVMValueRef {
// TODO: consider creating separate IR element for pointer to function. // 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()) assert (expression.getArguments().isEmpty())
@@ -2142,7 +2144,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
descriptor: FunctionDescriptor, args: List<LLVMValueRef>, descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef { resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
//context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"} //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) return callVirtual(descriptor, args, resultLifetime)
else else
return callDirect(descriptor, args, resultLifetime) return callDirect(descriptor, args, resultLifetime)
@@ -42,10 +42,10 @@ internal class LlvmDeclarations(
private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>, private val staticFields: Map<IrField, StaticFieldLlvmDeclarations>,
private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) { private val unique: Map<UniqueKind, UniqueLlvmDeclarations>) {
fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?: 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] ?: fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?:
error(descriptor.toString()) error("$descriptor ${descriptor.name}")
fun forField(descriptor: IrField) = fields[descriptor] ?: fun forField(descriptor: IrField) = fields[descriptor] ?:
error(descriptor.toString()) error(descriptor.toString())
@@ -393,7 +393,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val descriptor = declaration val descriptor = declaration
val llvmFunctionType = getLlvmFunctionType(descriptor) val llvmFunctionType = getLlvmFunctionType(descriptor)
if ((descriptor is ConstructorDescriptor && descriptor.isObjCConstructor())) { if ((descriptor is ConstructorDescriptor && descriptor.isObjCConstructor)) {
return 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.computePrimitiveBinaryTypeOrNull
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* 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.IrField
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.backend.konan.lower 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.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope 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.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* 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.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.* 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.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.storage.LockBasedStorageManager 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, internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?, val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
@@ -71,6 +78,10 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
} }
override fun visitField(declaration: IrField) { 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.descriptor as? WrappedFieldDescriptor)?.bind(declaration)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
} }
@@ -96,7 +107,6 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
} }
}) })
result.patchDeclarationParents(parent) result.patchDeclarationParents(parent)
return result return result
} }
@@ -30,18 +30,28 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
* Note: org.jetbrains.kotlin.backend.common.lower.ExpectDeclarationsRemoving is copy of this lower. * Note: org.jetbrains.kotlin.backend.common.lower.ExpectDeclarationsRemoving is copy of this lower.
*/ */
internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass { internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
// All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`. // All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`.
irFile.declarations.removeAll { irFile.declarations.removeAll {
if (it.descriptor.isExpectMember) { if (it.descriptor.isExpectMember) {
copyDefaultArgumentsFromExpectToActual(it)
true true
} else { } else {
false 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) { private fun copyDefaultArgumentsFromExpectToActual(declaration: IrDeclaration) {
declaration.acceptVoid(object : IrElementVisitorVoid { 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.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters 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.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride 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.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isInlineParameter
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement 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.types.toKotlinType
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 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.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl 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>>() { internal class FunctionInlining(val context: Context): IrElementTransformerWithContext<Ref<Boolean>>() {
private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>() private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>() private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
@@ -138,8 +137,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
val result = super.visitFunctionNew(declaration, localData) val result = super.visitFunctionNew(declaration, localData)
data.value = data.value or localData.value data.value = data.value or localData.value
if (descriptor.needsInlining) if (descriptor.needsInlining) {
inlineFunctions[descriptor] = localData.value inlineFunctions[descriptor] = localData.value
}
return result return result
} }
@@ -163,19 +163,20 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
} }
data.value = data.value or callee.second data.value = data.value or callee.second
// TODO: do we still need this Ref<Boolean> mechanism?
val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false) val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false)
callee.first.transformChildren(this, childIsBad) // Process recursive inline. callee.first.transformChildren(this, childIsBad) // Process recursive inline.
inlineFunctions[functionDescriptor] = childIsBad.value inlineFunctions[functionDescriptor] = childIsBad.value
data.value = data.value or 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!!, val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!,
allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull(), context, this) allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull(), context, this)
return inliner.inline() return inliner.inline()
} }
//-------------------------------------------------------------------------// // TODO: do we really need this function anymore?
private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair<IrFunction, Boolean>? = private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair<IrFunction, Boolean>? =
when { when {
descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) -> descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) ->
@@ -189,7 +190,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
else -> else ->
context.ir.originalModuleIndex.functions[descriptor]?.let { it to false } 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.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) } constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
} }
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter val oldThis = (callee as IrConstructor).constructedClass.thisReceiver!!.descriptor
val newThis = currentScope.scope.createTemporaryVariable( val newThis = currentScope.scope.createTemporaryVariableWithWrappedDescriptor(
irExpression = constructorCall, irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this" nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
) )
@@ -399,7 +400,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val isInlinableLambdaArgument : Boolean val isInlinableLambdaArgument : Boolean
get() { get() {
if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false if (!parameter.isInlineParameter()) return false
if (argumentExpression is IrFunctionReference if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway. && !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 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. irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(), nameHint = callee.descriptor.name.toString(),
isMutable = false) isMutable = false)
@@ -86,7 +86,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private val outerClasses = mutableListOf<IrClass>() private val outerClasses = mutableListOf<IrClass>()
override fun visitClass(declaration: IrClass): IrStatement { override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.descriptor.isKotlinObjCClass()) { if (declaration.isKotlinObjCClass()) {
lowerKotlinObjCClass(declaration) lowerKotlinObjCClass(declaration)
} }
@@ -507,13 +507,13 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val constructedClass = outerClasses.peek()!! val constructedClass = outerClasses.peek()!!
val constructedClassDescriptor = constructedClass.descriptor val constructedClassDescriptor = constructedClass.descriptor
if (!constructedClassDescriptor.isObjCClass()) { if (!constructedClass.isObjCClass()) {
return expression return expression
} }
constructedClassDescriptor.containingDeclaration.let { classContainer -> constructedClass.parent.let { parent ->
if (classContainer is ClassDescriptor && classContainer.isObjCClass() && if (parent is IrClass && parent.isObjCClass() &&
constructedClassDescriptor == classContainer.companionObjectDescriptor) { constructedClass.isCompanion) {
// Note: it is actually not used; getting values of such objects is handled by code generator // Note: it is actually not used; getting values of such objects is handled by code generator
// in [FunctionGenerationContext.getObjectValue]. // in [FunctionGenerationContext.getObjectValue].
@@ -522,8 +522,8 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
} }
} }
if (!constructedClassDescriptor.isExternalObjCClass() && if (!constructedClass.isExternalObjCClass() &&
expression.descriptor.constructedClass.isExternalObjCClass()) { (expression.symbol.owner.constructedClass).isExternalObjCClass()) {
// Calling super constructor from Kotlin Objective-C class. // Calling super constructor from Kotlin Objective-C class.
@@ -531,7 +531,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initMethod = expression.descriptor.getObjCInitMethod()!! val initMethod = expression.descriptor.getObjCInitMethod()!!
if (!expression.descriptor.objCConstructorIsDesignated()) { if (!expression.symbol.owner.objCConstructorIsDesignated()) {
context.reportCompilationError( context.reportCompilationError(
"Unable to call non-designated initializer as super constructor", "Unable to call non-designated initializer as super constructor",
currentFile, currentFile,
@@ -582,7 +582,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val superClass = superQualifier?.let { getObjCClass(it) } ?: val superClass = superQualifier?.let { getObjCClass(it) } ?:
irCall(symbols.getNativeNullPtr, symbols.nativePtrType) 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 { return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
putValueArgument(0, superClass) putValueArgument(0, superClass)
putValueArgument(1, receiver) putValueArgument(1, receiver)
@@ -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.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor 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.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.reportWarning import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.backend.konan.KonanBackendContext 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.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name 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 import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class TestProcessor (val context: KonanBackendContext) { internal class TestProcessor (val context: KonanBackendContext) {
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.util.OperatorNameConventions 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 } it.allOverriddenDescriptors.atMostOne { it.parent == this }
} }
@@ -601,7 +601,7 @@ internal object DataFlowIR {
} }
else -> { 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 classDescriptor = it.containingDeclaration as? ClassDescriptor
val bridgeTarget = it.bridgeTarget val bridgeTarget = it.bridgeTarget
val isSpecialBridge = bridgeTarget.let { 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.backend.konan.Context
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.*
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.util.addChild import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -30,7 +27,9 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid
list?.add(declaration.backingField!!.descriptor) list?.add(declaration.backingField!!.descriptor)
} }
if (declaration.backingField == null || declaration.isDelegated) return 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) 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"; syntax = "proto2";
package org.jetbrains.kotlin.metadata; 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 java_outer_classname = "KonanIr";
option optimize_for = LITE_RUNTIME; option optimize_for = LITE_RUNTIME;
// This is subject to change. message DescriptorReference {
// One can think of it as a 'descriptor reference'. required string package_fq_name = 1;
// The real descriptor data is encoded in KonanLinkdData. required string class_fq_name = 2;
message KotlinDescriptor { required string name = 3;
enum Kind { optional UniqId uniq_id = 4;
FUNCTION = 1; optional bool is_getter = 5 [default = false];
VARIABLE = 2; optional bool is_setter = 6 [default = false];
CLASS = 3; optional bool is_backing_field = 7 [default = false];
VALUE_PARAMETER = 4; optional bool is_fake_override = 8 [default = false];
CONSTRUCTOR = 5; optional bool is_default_constructor = 9 [default = false];
TYPE_PARAMETER = 6; optional bool is_enum_entry = 10 [default = false];
RECEIVER = 7; optional bool is_enum_special = 11 [default = false];
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 UniqId { message UniqId {
required int64 index = 1; required uint64 index = 1;
} required bool isLocal = 2;
// 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
} }
message Coordinates { message Coordinates {
@@ -71,9 +28,127 @@ message Coordinates {
required int32 end_offset = 2; required int32 end_offset = 2;
} }
message TypeArguments { /* ------ Top Level---------------------------------------------- */
repeated KotlinType type_argument = 1;
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 --------------------------------------------- */ /* ------ IrExpressions --------------------------------------------- */
message IrBreak { message IrBreak {
@@ -87,10 +162,10 @@ message IrBlock {
} }
message MemberAccessCommon { message MemberAccessCommon {
optional IrExpression dispatch_receiver = 5; optional IrExpression dispatch_receiver = 1;
optional IrExpression extension_receiver = 6; optional IrExpression extension_receiver = 2;
repeated NullableIrExpression value_argument = 8; repeated NullableIrExpression value_argument = 3;
required TypeArguments type_arguments = 9; required TypeArguments type_arguments = 4;
} }
message IrCall { message IrCall {
@@ -101,37 +176,47 @@ message IrCall {
BINARY = 4; BINARY = 4;
} }
required Primitive kind = 1; required Primitive kind = 1;
required KotlinDescriptor descriptor = 2; required IrSymbol symbol = 2;
required MemberAccessCommon member_access = 3; required MemberAccessCommon member_access = 3;
optional KotlinDescriptor super = 4; optional IrSymbol super = 4;
} }
message IrCallableReference { message IrFunctionReference {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
required TypeArguments type_arguments = 2; 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 { message IrComposite {
repeated IrStatement statement = 1; repeated IrStatement statement = 1;
} }
message IrClassReference { message IrClassReference {
required KotlinDescriptor class_descriptor = 1; required IrSymbol class_symbol = 1;
required IrTypeIndex class_type = 2;
} }
message IrConst { message IrConst {
oneof value { oneof value {
bool null = 1; bool null = 1;
bool boolean = 2; bool boolean = 2;
int32 char = 3; int32 char = 3;
int32 byte = 4; int32 byte = 4;
int32 short = 5; int32 short = 5;
int32 int = 6; int32 int = 6;
int64 long = 7; int64 long = 7;
float float = 8; float float = 8;
double double = 9; double double = 9;
string string = 10; string string = 10;
} }
} }
@@ -141,7 +226,7 @@ message IrContinue {
} }
message IrDelegatingConstructorCall { message IrDelegatingConstructorCall {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2; required MemberAccessCommon member_access = 2;
} }
@@ -150,7 +235,7 @@ message IrDoWhile {
} }
message IrEnumConstructorCall { message IrEnumConstructorCall {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2; required MemberAccessCommon member_access = 2;
} }
@@ -159,14 +244,13 @@ message IrGetClass {
} }
message IrGetEnumValue { message IrGetEnumValue {
required KotlinType type = 1; required IrSymbol symbol = 2;
required KotlinDescriptor descriptor = 2;
} }
message FieldAccessCommon { message FieldAccessCommon {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
optional KotlinDescriptor super = 2; optional IrSymbol super = 2;
required IrExpression receiver = 3; optional IrExpression receiver = 3;
} }
message IrGetField { message IrGetField {
@@ -174,15 +258,15 @@ message IrGetField {
} }
message IrGetValue { message IrGetValue {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
} }
message IrGetObject { message IrGetObject {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
} }
message IrInstanceInitializerCall { message IrInstanceInitializerCall {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
} }
message Loop { message Loop {
@@ -193,7 +277,7 @@ message Loop {
} }
message IrReturn { message IrReturn {
required KotlinDescriptor return_target = 1; required IrSymbol return_target = 1;
required IrExpression value = 2; required IrExpression value = 2;
} }
@@ -203,7 +287,7 @@ message IrSetField {
} }
message IrSetVariable { message IrSetVariable {
required KotlinDescriptor descriptor = 1; required IrSymbol symbol = 1;
required IrExpression value = 2; required IrExpression value = 2;
} }
@@ -228,12 +312,12 @@ message IrTry {
message IrTypeOp { message IrTypeOp {
required IrTypeOperator operator = 1; required IrTypeOperator operator = 1;
required KotlinType operand = 2; required IrTypeIndex operand = 2;
required IrExpression argument = 3; required IrExpression argument = 3;
} }
message IrVararg { message IrVararg {
required KotlinType element_type = 1; required IrTypeIndex element_type = 1;
repeated IrVarargElement element = 2; repeated IrVarargElement element = 2;
} }
@@ -259,30 +343,31 @@ message IrOperation {
IrBlock block = 1; IrBlock block = 1;
IrBreak break = 2; IrBreak break = 2;
IrCall call = 3; IrCall call = 3;
IrCallableReference callable_reference = 4; IrClassReference class_reference = 4;
IrClassReference class_reference = 27; IrComposite composite = 5;
IrConst const = 5; IrConst const = 6;
IrComposite composite = 26; IrContinue continue = 7;
IrContinue continue = 6; IrDelegatingConstructorCall delegating_constructor_call = 8;
IrDelegatingConstructorCall delegating_constructor_call = 7; IrDoWhile do_while = 9;
IrDoWhile do_while = 25; IrEnumConstructorCall enum_constructor_call = 10;
IrEnumConstructorCall enum_constructor_call = 8; IrFunctionReference function_reference = 11;
IrGetClass get_class = 24; IrGetClass get_class = 12;
IrGetEnumValue get_enum_value = 9; IrGetEnumValue get_enum_value = 13;
IrGetField get_field = 10; IrGetField get_field = 14;
IrGetValue get_value = 11; IrGetObject get_object = 15;
IrGetObject get_object = 12; IrGetValue get_value = 16;
IrInstanceInitializerCall instance_initializer_call = 13; IrInstanceInitializerCall instance_initializer_call = 17;
IrReturn return = 14; IrPropertyReference property_reference = 18;
IrSetField set_field = 15; IrReturn return = 19;
IrSetVariable set_variable = 16; IrSetField set_field = 20;
IrStringConcat string_concat = 17; IrSetVariable set_variable = 21;
IrThrow throw = 18; IrStringConcat string_concat = 22;
IrTry try = 19; IrThrow throw = 23;
IrTypeOp type_op = 20; IrTry try = 24;
IrVararg vararg = 21; IrTypeOp type_op = 25;
IrWhen when = 22; IrVararg vararg = 26;
IrWhile while = 23; IrWhen when = 27;
IrWhile while = 28;
} }
} }
@@ -291,14 +376,17 @@ enum IrTypeOperator {
IMPLICIT_CAST = 2; IMPLICIT_CAST = 2;
IMPLICIT_NOTNULL = 3; IMPLICIT_NOTNULL = 3;
IMPLICIT_COERCION_TO_UNIT = 4; IMPLICIT_COERCION_TO_UNIT = 4;
SAFE_CAST = 5; IMPLICIT_INTEGER_COERCION = 5;
INSTANCEOF = 6; SAFE_CAST = 6;
NOT_INSTANCEOF = 7; INSTANCEOF = 7;
NOT_INSTANCEOF = 8;
SAM_CONVERSION = 9;
} }
message IrExpression { message IrExpression {
required IrOperation operation = 1; required IrOperation operation = 1;
required KotlinType type = 2; required IrTypeIndex type = 2;
required Coordinates coordinates = 3; required Coordinates coordinates = 3;
} }
@@ -306,59 +394,177 @@ message NullableIrExpression {
optional IrExpression expression = 1; optional IrExpression expression = 1;
} }
/* ------ Declarations --------------------------------------------- */ /* ------ Declarations --------------------------------------------- */
message IrTypeAlias {
// Nothing for now.
}
message IrFunction { message IrFunction {
message DefaultArgument { required IrSymbol symbol = 1;
required int32 position = 1; required IrFunctionBase base = 2;
required IrExpression value = 2; required ModalityKind modality = 3;
} required bool is_tailrec = 4;
optional IrStatement body = 1; required bool is_suspend = 5;
repeated DefaultArgument default_argument = 2; 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 IrProperty {
message IrField { optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
required IrExpression initializer = 1; required string name = 2;
} required string visibility = 3;
required bool is_delegated = 1; required ModalityKind modality = 4;
optional IrField backing_field = 2; required bool is_var = 5;
optional IrFunction getter = 3; required bool is_const = 6;
optional IrFunction setter = 4; 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 { message IrVariable {
optional IrExpression initializer = 1; 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 { 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 { message IrEnumEntry {
required IrExpression initializer = 1; required IrSymbol symbol = 1;
optional IrDeclaration corresponding_class = 2; 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 // TODO: we need an extension mechanism to accomodate new
// IR operators in upcoming releases. // IR operators in upcoming releases.
message IrDeclarator { message IrDeclarator {
oneof symbol { oneof declarator {
IrVar variable = 1; IrAnonymousInit ir_anonymous_init = 1;
IrFunction function = 2; IrClass ir_class = 2;
IrClass ir_class = 3; IrConstructor ir_constructor = 3;
IrEnumEntry ir_enum_entry = 4; 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 { message IrDeclaration {
required KotlinDescriptor descriptor = 1; required IrDeclarationOrigin origin = 1;
required Coordinates coordinates = 2; required Coordinates coordinates = 2;
required IrDeclarator declarator = 3; required Annotations annotations = 3;
repeated IrDeclaration nested = 4; required IrDeclarator declarator = 4;
required string file_name = 5; //repeated IrDeclaration nested = 5;
required string file_name = 5; // TODO: files should be communicated some other way, I suppose.
} }
/* ------- IrStatements --------------------------------------------- */ /* ------- IrStatements --------------------------------------------- */
@@ -377,6 +583,15 @@ message IrCatch {
required IrExpression result = 2; 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. // Let's try to map IrElement as well as IrStatement to IrStatement.
message IrStatement { message IrStatement {
required Coordinates coordinates = 1; required Coordinates coordinates = 1;
@@ -386,6 +601,6 @@ message IrStatement {
IrBlockBody block_body = 4; IrBlockBody block_body = 4;
IrBranch branch = 5; IrBranch branch = 5;
IrCatch catch = 6; 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.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember 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.backend.konan.library.LinkData
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf 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.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -32,7 +35,7 @@ import org.jetbrains.kotlin.serialization.konan.SourceFileMap
* with MemberDeserializer class. * 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 lateinit var serializerContext: SerializerContext
@@ -43,9 +46,8 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
val topSerializer: DescriptorSerializer, val topSerializer: DescriptorSerializer,
var classSerializer: DescriptorSerializer = topSerializer var classSerializer: DescriptorSerializer = topSerializer
) )
private fun createNewContext(): SerializerContext { private fun createNewContext(): SerializerContext {
val extension = KonanSerializerExtension(context, metadataVersion, sourceFileMap) val extension = KonanSerializerExtension(context, metadataVersion, sourceFileMap, declarationTable)
return SerializerContext( return SerializerContext(
extension, extension,
DescriptorSerializer.createTopLevel(extension) DescriptorSerializer.createTopLevel(extension)
@@ -63,9 +65,9 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
with(serializerContext) { with(serializerContext) {
val previousSerializer = classSerializer val previousSerializer = classSerializer
// TODO: this is to filter out object{}. Change me. // TODO: this is to filter out object{}. Change me.
if (classDescriptor.isExported()) // if (classDescriptor.isExported())
classSerializer = DescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer) // classSerializer = KonanDescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer)
val classProto = classSerializer.classProto(classDescriptor).build() val classProto = classSerializer.classProto(classDescriptor).build()
?: error("Class not serialized: $classDescriptor") ?: error("Class not serialized: $classDescriptor")
@@ -207,7 +209,7 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
.build() .build()
} }
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData { internal fun serializeModule(moduleDescriptor: ModuleDescriptor, serializedIr: SerializedIr): LinkData {
val libraryProto = KonanProtoBuf.LinkDataLibrary.newBuilder() val libraryProto = KonanProtoBuf.LinkDataLibrary.newBuilder()
libraryProto.moduleName = moduleDescriptor.name.asString() libraryProto.moduleName = moduleDescriptor.name.asString()
val fragments = mutableListOf<List<ByteArray>>() val fragments = mutableListOf<List<ByteArray>>()
@@ -233,7 +235,7 @@ internal class KonanSerializationUtil(val context: Context, private val metadata
} }
val libraryAsByteArray = libraryProto.build().toByteArray() 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 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.Context
import org.jetbrains.kotlin.backend.konan.descriptors.needsSerializedIr
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -22,13 +20,17 @@ import org.jetbrains.kotlin.serialization.konan.SourceFileMap
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
internal class KonanSerializerExtension(val context: Context, override val metadataVersion: BinaryVersion, internal class KonanSerializerExtension(val context: Context, override val metadataVersion: BinaryVersion,
val sourceFileMap: SourceFileMap) : val sourceFileMap: SourceFileMap, val declarationTable: DeclarationTable) :
KotlinSerializerExtensionBase(KonanSerializerProtocol), IrAwareExtension { KotlinSerializerExtensionBase(KonanSerializerProtocol) {
val inlineDescriptorTable = DescriptorTable(context.irBuiltIns)
override val stringTable = KonanStringTable() override val stringTable = KonanStringTable()
override fun shouldUseTypeTable(): Boolean = true 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) { 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. // representation of serialized types.
@@ -38,95 +40,58 @@ internal class KonanSerializerExtension(val context: Context, override val metad
super.serializeType(type, proto) 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) { 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. // Serialization doesn't preserve enum entry order, so we need to serialize ordinal.
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(descriptor) val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(descriptor)
proto.setExtension(KonanProtoBuf.enumEntryOrdinal, ordinal) proto.setExtension(KonanProtoBuf.enumEntryOrdinal, ordinal)
super.serializeEnumEntry(descriptor, proto) 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, override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable, versionRequirementTable: MutableVersionRequirementTable,
childSerializer: DescriptorSerializer) { childSerializer: DescriptorSerializer) {
uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.classUniqId, it) }
super.serializeClass(descriptor, proto, versionRequirementTable, childSerializer) 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) } 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, override fun serializeFunction(descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder,
childSerializer: DescriptorSerializer) { childSerializer: DescriptorSerializer) {
proto.setExtension(KonanProtoBuf.functionFile, sourceFileMap.assign(descriptor.source.containingFile)) proto.setExtension(KonanProtoBuf.functionFile, sourceFileMap.assign(descriptor.source.containingFile))
uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.functionUniqId, it) }
super.serializeFunction(descriptor, proto, childSerializer) super.serializeFunction(descriptor, proto, childSerializer)
if (descriptor.needsSerializedIr) {
addFunctionIR(proto, serializeInlineBody(descriptor, childSerializer))
}
} }
override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder, override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder,
versionRequirementTable: MutableVersionRequirementTable, versionRequirementTable: MutableVersionRequirementTable,
childSerializer: DescriptorSerializer) { childSerializer: DescriptorSerializer) {
val variable = originalVariables[descriptor]
if (variable != null) {
proto.setExtension(KonanProtoBuf.usedAsVariable, true)
}
proto.setExtension(KonanProtoBuf.propertyFile, sourceFileMap.assign(descriptor.source.containingFile)) proto.setExtension(KonanProtoBuf.propertyFile, sourceFileMap.assign(descriptor.source.containingFile))
uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.propertyUniqId, it) }
proto.setExtension(KonanProtoBuf.hasBackingField, proto.setExtension(KonanProtoBuf.hasBackingField,
context.ir.propertiesWithBackingFields.contains(descriptor)) context.ir.propertiesWithBackingFields.contains(descriptor))
super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer) 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 = override fun releaseCoroutines(): Boolean =
context.config.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) 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.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.* 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.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException 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.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol 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.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl 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.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor 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.name.Name
import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -619,7 +627,12 @@ fun createField(
} }
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { 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( return IrValueParameterImpl(
startOffset, startOffset,
@@ -637,7 +650,7 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean
get() = this is IrSimpleType && this.hasQuestionMark get() = this is IrSimpleType && this.hasQuestionMark
fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) = 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 = fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean =
this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
-1
View File
@@ -3109,7 +3109,6 @@ task library_mismatch(type: RunStandaloneKonanTest) {
doFirst { doFirst {
def konancScript = isWindows() ? "konanc.bat" : "konanc" def konancScript = isWindows() ? "konanc.bat" : "konanc"
def konanc = "$dist/bin/$konancScript" 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/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/3.4/empty -target $someOtherTarget".execute().waitFor()
"$konanc $lib -p library -o $dir/5.6/empty -target $currentTarget -lv 5.6".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('.') destinationDir = file('.')
if (!isWindows()) {
if (isWindows()) {
zip64 true
} else {
extension = 'tar.gz' extension = 'tar.gz'
compression = Compression.GZIP compression = Compression.GZIP
} }
@@ -100,7 +100,7 @@ abstract class KonanTest extends JavaExec {
classpath = project.fileTree("$dist.canonicalPath/konan/lib/") { classpath = project.fileTree("$dist.canonicalPath/konan/lib/") {
include '*.jar' include '*.jar'
} }
jvmArgs "-Dkonan.home=${dist.canonicalPath}", "-Xmx2G", jvmArgs "-Dkonan.home=${dist.canonicalPath}", "-Xmx4G",
"-Djava.library.path=${dist.canonicalPath}/konan/nativelib" "-Djava.library.path=${dist.canonicalPath}/konan/nativelib"
enableAssertions = true enableAssertions = true
def sources = File.createTempFile(name,".lst") def sources = File.createTempFile(name,".lst")
@@ -16,23 +16,30 @@ option optimize_for = LITE_RUNTIME;
// Konan extensions to the "descriptors" protobuf. // Konan extensions to the "descriptors" protobuf.
message DescriptorUniqId {
required int64 index = 1;
}
extend Package { extend Package {
optional int32 package_fq_name = 171; optional int32 package_fq_name = 171;
} }
extend Class { extend Class {
repeated Annotation class_annotation = 170; repeated Annotation class_annotation = 170;
optional DescriptorUniqId class_uniq_id = 171;
} }
extend Constructor { extend Constructor {
repeated Annotation constructor_annotation = 170; repeated Annotation constructor_annotation = 170;
optional InlineIrBody inline_constructor_ir_body = 171; optional InlineIrBody inline_constructor_ir_body = 171;
optional DescriptorUniqId constructor_uniq_id = 172;
} }
extend Function { extend Function {
repeated Annotation function_annotation = 170; repeated Annotation function_annotation = 170;
optional InlineIrBody inline_ir_body = 171; optional InlineIrBody inline_ir_body = 171;
optional int32 function_file = 172; optional int32 function_file = 172;
optional DescriptorUniqId function_uniq_id = 173;
} }
extend Property { extend Property {
@@ -45,15 +52,18 @@ extend Property {
optional InlineIrBody inline_getter_ir_body = 174; optional InlineIrBody inline_getter_ir_body = 174;
optional InlineIrBody inline_setter_ir_body = 175; optional InlineIrBody inline_setter_ir_body = 175;
optional int32 property_file = 176; optional int32 property_file = 176;
optional DescriptorUniqId property_uniq_id = 179;
} }
extend EnumEntry { extend EnumEntry {
repeated Annotation enum_entry_annotation = 170; repeated Annotation enum_entry_annotation = 170;
optional int32 enum_entry_ordinal = 171; optional int32 enum_entry_ordinal = 171;
optional DescriptorUniqId enum_entry_uniq_id = 172;
} }
extend ValueParameter { extend ValueParameter {
repeated Annotation parameter_annotation = 170; repeated Annotation parameter_annotation = 170;
optional DescriptorUniqId value_param_uniq_id = 171;
} }
extend Type { extend Type {
@@ -63,6 +73,7 @@ extend Type {
extend TypeParameter { extend TypeParameter {
repeated Annotation type_parameter_annotation = 170; repeated Annotation type_parameter_annotation = 170;
optional DescriptorUniqId type_param_uniq_id = 171;
} }
message InlineIrBody { 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 package org.jetbrains.kotlin.konan.library.resolver.impl
import org.jetbrains.kotlin.konan.file.File 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.descriptors.konan.KonanModuleDescriptorFactory
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.library.KonanLibrary 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.konan.library.resolver.PackageAccessedHandler
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
+1
View File
@@ -24,3 +24,4 @@ testKotlinVersion=1.3.30-dev-964
konanVersion=1.2.0 konanVersion=1.2.0
org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.workers.max=4 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 language = Objective-C
package = platform.CoreAudioKit package = platform.CoreAudioKit
headers = CoreAudioKit/CoreAudioKit.h headers = CoreAudioKit/CoreAudioKit.h
+1
View File
@@ -33,6 +33,7 @@ public final class Array<T> {
} }
} }
@PublishedApi
@ExportForCompiler @ExportForCompiler
internal constructor(@Suppress("UNUSED_PARAMETER") size: Int) {} 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> return result as Array<T>
} }
@PublishedApi
@TypedIntrinsic(IntrinsicType.CREATE_UNINITIALIZED_INSTANCE) @TypedIntrinsic(IntrinsicType.CREATE_UNINITIALIZED_INSTANCE)
internal external fun <T> createUninitializedInstance(): T internal external fun <T> createUninitializedInstance(): T
@PublishedApi
@TypedIntrinsic(IntrinsicType.INIT_INSTANCE) @TypedIntrinsic(IntrinsicType.INIT_INSTANCE)
internal external fun initInstance(thiz: Any, constructorCall: Any): Unit internal external fun initInstance(thiz: Any, constructorCall: Any): Unit
@@ -42,6 +42,9 @@ interface KonanLibrary {
val moduleHeaderData: ByteArray val moduleHeaderData: ByteArray
fun packageMetadataParts(fqName: String): Set<String> fun packageMetadataParts(fqName: String): Set<String>
fun packageMetadata(fqName: String, partName: String): ByteArray fun packageMetadata(fqName: String, partName: String): ByteArray
val irHeader: ByteArray
fun irDeclaration(index: Long, isLocal: Boolean): ByteArray
} }
val KonanLibrary.uniqueName val KonanLibrary.uniqueName
@@ -44,4 +44,15 @@ interface KonanLibraryLayout {
fun packageFragmentFile(packageFqName: String, partName: String) = fun packageFragmentFile(packageFqName: String, partName: String) =
File(packageFragmentsDir(packageFqName), "$partName$KLIB_METADATA_FILE_EXTENSION_WITH_DOT") 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 { interface MetadataReader {
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): 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 = override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray =
libraryLayout.packageFragmentFile(fqName, partName).readBytes() 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 package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.file.File 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.defaultTargetSubstitutions
import org.jetbrains.kotlin.konan.util.substitute import org.jetbrains.kotlin.konan.util.substitute
class KonanLibraryImpl( class KonanLibraryImpl(
override val libraryFile: File, override val libraryFile: File,
internal val target: KonanTarget?, 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]" override fun toString() = "$libraryName[default=$isDefault]"
} }
@@ -20,11 +20,13 @@ import kotlin.system.measureTimeMillis
import org.jetbrains.kotlin.konan.file.* import org.jetbrains.kotlin.konan.file.*
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function: // 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{ val msec = measureTimeMillis{
body() result = body()
} }
println("$message: $msec msec") println("$message: $msec msec")
return result!!
} }
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function: // FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function: