diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryType.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryType.kt index 176271467c4..10c8bff7ce2 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryType.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BinaryType.kt @@ -17,4 +17,4 @@ fun BinaryType<*>.primitiveBinaryTypeOrNull(): PrimitiveBinaryType? = when (this enum class PrimitiveBinaryType { BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, POINTER -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt index dea42b68383..ac84833150a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt @@ -13,6 +13,10 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction @@ -224,4 +228,4 @@ internal fun IrBuiltIns.getKotlinClass(cache: BoxCache): IrClass = when (cache) // TODO: consider adding box caches for unsigned types. enum class BoxCache { BOOLEAN, BYTE, SHORT, CHAR, INT, LONG -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 609375adc09..65cf8a13c1e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -263,6 +263,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { // But we have to wait until the code generation phase, // to dump this information into generated file. var serializedLinkData: LinkData? = null + var serializedIr: ByteArray? = null var dataFlowGraph: ByteArray? = null @Deprecated("") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt index de55e81eb08..8b0f51f02f9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InlineClasses.kt @@ -55,7 +55,7 @@ fun IrType.computePrimitiveBinaryTypeOrNull(): PrimitiveBinaryType? = fun IrType.computeBinaryType(): BinaryType = 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) /** diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt index 5b8fe15a3d1..d00888fb030 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanDriver.kt @@ -5,16 +5,20 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.backend.common.LoggingContext import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule +import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.ir.ModuleIndex import org.jetbrains.kotlin.backend.konan.llvm.emitLLVM -import org.jetbrains.kotlin.backend.konan.serialization.KonanSerializationUtil -import org.jetbrains.kotlin.backend.konan.serialization.markBackingFields +import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier +import org.jetbrains.kotlin.backend.konan.serialization.* import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings +import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator @@ -62,9 +66,30 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme @Suppress("DEPRECATION") context.psi2IrGeneratorContext = generatorContext - val symbols = KonanSymbols(context, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper) + val forwardDeclarationsModuleDescriptor = context.moduleDescriptor.allDependencyModules.firstOrNull { it.isForwardDeclarationModule } - val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles()) + val deserializer = KonanIrModuleDeserializer( + context.moduleDescriptor, + context as LoggingContext, + generatorContext.irBuiltIns, + generatorContext.symbolTable, + forwardDeclarationsModuleDescriptor + ) + + val irModules = context.moduleDescriptor.allDependencyModules.map { + val library = it.konanLibrary + if (library == null) { + return@map null + } + deserializer.deserializeIrModule(it, library.irHeader) + }.filterNotNull() + + val symbols = KonanSymbols(context, generatorContext.symbolTable, generatorContext.symbolTable.lazyWrapper) + val module = translator.generateModuleFragment(generatorContext, environment.getSourceFiles(), deserializer) + + irModules.forEach { + it.patchDeclarationParents() + } context.irModule = module context.ir.symbols = symbols @@ -80,10 +105,23 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme phaser.phase(KonanPhase.GEN_SYNTHETIC_FIELDS) { markBackingFields(context) } + + // TODO: We copy default value expressions from expects to actuals before IR serialization, + // because the current infrastructure doesn't allow us to get them at deserialization stage. + // That equires some design and implementation work. + phaser.phase(KonanPhase.COPY_DEFAULT_VALUES_TO_ACTUAL) { + context.irModule!!.files.forEach(ExpectToActualDefaultValueCopier(context)::lower) + } + + context.irModule!!.patchDeclarationParents() // why do we need it? + phaser.phase(KonanPhase.SERIALIZER) { - val serializer = KonanSerializationUtil(context, context.config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!) + val declarationTable = DeclarationTable(context.irModule!!.irBuiltins, DescriptorTable()) + val serializedIr = IrModuleSerializer(context, declarationTable/*, onlyForInlines = false*/).serializedIrModule(context.irModule!!) + + val serializer = KonanSerializationUtil(context, context.config.configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable) context.serializedLinkData = - serializer.serializeModule(context.moduleDescriptor) + serializer.serializeModule(context.moduleDescriptor, serializedIr) } phaser.phase(KonanPhase.BACKEND) { phaser.phase(KonanPhase.LOWER) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 7bc570b5f92..c29d8322015 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.name import org.jetbrains.kotlin.ir.util.checkDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols @@ -64,13 +65,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager) irModule.files.forEach(InteropLoweringPart1(context)::lower) } - val symbolTable = context.ir.symbols.symbolTable - - do { - @Suppress("DEPRECATION") - irModule.replaceUnboundSymbols(context) - } while (symbolTable.unboundClasses.isNotEmpty()) - irModule.patchDeclarationParents() // validateIrModule(context, irModule) // Temporarily disabled until moving to new IR finished. diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index f6509f6d3bb..77285c248f7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -17,6 +17,7 @@ enum class KonanPhase(val description: String, /* */ PSI_TO_IR("Psi to IR conversion"), /* */ IR_GENERATOR_PLUGINS("Plugged-in ir generators"), /* */ GEN_SYNTHETIC_FIELDS("Generate synthetic fields"), + /* */ COPY_DEFAULT_VALUES_TO_ACTUAL("Copy default values from expect to actual declarations"), /* */ SERIALIZER("Serialize descriptor tree and inline IR bodies", GEN_SYNTHETIC_FIELDS), /* */ BACKEND("All backend"), /* ... */ LOWER("IR Lowering"), @@ -52,11 +53,11 @@ enum class KonanPhase(val description: String, /* ... ... */ RETURNS_INSERTION("Returns insertion for Unit functions", AUTOBOX, LOWER_COROUTINES, LOWER_ENUMS), /* ... */ BITCODE("LLVM BitCode Generation"), /* ... ... */ RTTI("RTTI Generation"), - /* ... ... */ BUILD_DFG("Data flow graph building"), - /* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing"), - /* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG), + /* ... ... */ BUILD_DFG("Data flow graph building", enabled = false), + /* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing", enabled = false), + /* ... ... */ DEVIRTUALIZATION("Devirtualization", BUILD_DFG, DESERIALIZE_DFG, enabled = false), /* ... ... */ ESCAPE_ANALYSIS("Escape analysis", BUILD_DFG, DESERIALIZE_DFG, enabled = false), // TODO: Requires devirtualization. - /* ... ... */ SERIALIZE_DFG("Data flow graph serializing", BUILD_DFG), // TODO: Requires escape analysis. + /* ... ... */ SERIALIZE_DFG("Data flow graph serializing", BUILD_DFG, enabled = false), // TODO: Requires escape analysis. /* ... ... */ CODEGEN("Code Generation"), /* ... ... */ C_STUBS("C stubs compilation"), /* ... ... */ BITCODE_LINKER("Bitcode linking"), diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt index d3fb77fbda7..1ae31e0fc0e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ObjCInterop.kt @@ -8,14 +8,16 @@ package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.backend.konan.descriptors.findPackageView import org.jetbrains.kotlin.backend.konan.descriptors.getStringValue import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull -import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass -import org.jetbrains.kotlin.backend.konan.irasdescriptors.getExternalObjCMethodInfo -import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal +import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrConst +import org.jetbrains.kotlin.ir.expressions.IrConstKind +import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition @@ -27,8 +29,8 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.supertypes -private val interopPackageName = InteropFqNames.packageName -private val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject")) +internal val interopPackageName = InteropFqNames.packageName +internal val objCObjectFqName = interopPackageName.child(Name.identifier("ObjCObject")) private val objCClassFqName = interopPackageName.child(Name.identifier("ObjCClass")) internal val externalObjCClassFqName = interopPackageName.child(Name.identifier("ExternalObjCClass")) private val objCMethodFqName = interopPackageName.child(Name.identifier("ObjCMethod")) @@ -36,17 +38,30 @@ private val objCConstructorFqName = FqName("kotlinx.cinterop.ObjCConstructor") private val objCFactoryFqName = interopPackageName.child(Name.identifier("ObjCFactory")) private val objCBridgeFqName = interopPackageName.child(Name.identifier("ObjCBridge")) +@Deprecated("Use IR version rather than descriptor version") fun ClassDescriptor.isObjCClass(): Boolean = - this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } && + this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } && // TODO: this is not cheap. Cache me! this.containingDeclaration.fqNameSafe != interopPackageName fun KotlinType.isObjCObjectType(): Boolean = (this.supertypes() + this).any { TypeUtils.getClassDescriptor(it)?.fqNameSafe == objCObjectFqName } + +private fun IrClass.getAllSuperClassifiers(): List = + listOf(this) + this.superTypes.flatMap { (it.classifierOrFail.owner as IrClass).getAllSuperClassifiers() } + +internal fun IrClass.isObjCClass() = this.getAllSuperClassifiers().any { it.fqNameSafe == objCObjectFqName } && + this.parent.fqNameSafe != interopPackageName + +@Deprecated("Use IR version rather than descriptor version") fun ClassDescriptor.isExternalObjCClass(): Boolean = this.isObjCClass() && this.parentsWithSelf.filterIsInstance().any { it.annotations.findAnnotation(externalObjCClassFqName) != null } +fun IrClass.isExternalObjCClass(): Boolean = this.isObjCClass() && + (this as IrDeclaration).parentDeclarationsWithSelf.filterIsInstance().any { + it.annotations.findAnnotation(externalObjCClassFqName) != null + } fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().any { it.fqNameSafe == objCClassFqName @@ -55,15 +70,27 @@ fun ClassDescriptor.isObjCMetaClass(): Boolean = this.getAllSuperClassifiers().a fun FunctionDescriptor.isObjCClassMethod() = this.containingDeclaration.let { it is ClassDescriptor && it.isObjCClass() } +@Deprecated("Use IR version rather than descriptor version") fun FunctionDescriptor.isExternalObjCClassMethod() = this.containingDeclaration.let { it is ClassDescriptor && it.isExternalObjCClass() } +internal fun IrFunction.isExternalObjCClassMethod() = + this.parent.let {it is IrClass && it.isExternalObjCClass()} + // Special case: methods from Kotlin Objective-C classes can be called virtually from bridges. +@Deprecated("Use IR version rather than descriptor version") fun FunctionDescriptor.canObjCClassMethodBeCalledVirtually(overriddenDescriptor: FunctionDescriptor) = overriddenDescriptor.isOverridable && this.kind.isReal && !this.isExternalObjCClassMethod() +internal fun IrFunction.canObjCClassMethodBeCalledVirtually(overridden: IrFunction) = + overridden.isOverridable && this.origin != IrDeclarationOrigin.FAKE_OVERRIDE && !this.isExternalObjCClassMethod() + +@Deprecated("Use IR version rather than descriptor version") fun ClassDescriptor.isKotlinObjCClass(): Boolean = this.isObjCClass() && !this.isExternalObjCClass() +fun IrClass.isKotlinObjCClass(): Boolean = this.isObjCClass() && !this.isExternalObjCClass() + + data class ObjCMethodInfo(val bridge: FunctionDescriptor, val selector: String, val encoding: String, @@ -97,6 +124,20 @@ private fun objCMethodInfoByBridge(packageView: PackageViewDescriptor, bridgeNam ) } +fun IrSimpleFunction.objCMethodArgValue(argName: String): String? { + val methodAnnotation = this.annotations.findAnnotation(objCMethodFqName) ?: return null + methodAnnotation.symbol.owner.valueParameters.forEachIndexed { index, parameter -> + if (parameter.name.asString() == argName) { + val bridgeArgument = methodAnnotation.getValueArgument(index) as IrConst + return bridgeArgument.value + } + } + return null +} + +fun IrSimpleFunction.hasObjCMethodAnnotation() = + this.annotations.findAnnotation(objCMethodFqName) != null + /** * @param onlyExternal indicates whether to accept overriding methods from Kotlin classes */ @@ -183,6 +224,19 @@ class ObjCOverridabilityCondition : ExternalOverridabilityCondition { } +fun IrConstructor.objCConstructorIsDesignated(): Boolean { + val annotation = this.annotations.findAnnotation(objCConstructorFqName)!! + for (index in 0 until annotation.valueArgumentsCount) { + val parameter = annotation.symbol.owner.valueParameters[index] + if (parameter.name == Name.identifier("designated")) { + val actual = annotation.getValueArgument(index) as IrConst + return actual.value + } + } + error("Could not find 'designated' argument") +} + +@Deprecated("Use IR version rather than descriptor version") fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean { val annotation = this.annotations.findAnnotation(objCConstructorFqName)!! val value = annotation.allValueArguments[Name.identifier("designated")]!! @@ -190,6 +244,7 @@ fun ConstructorDescriptor.objCConstructorIsDesignated(): Boolean { return (value as BooleanValue).value } + fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? { return this.annotations.findAnnotation(objCConstructorFqName)?.let { val initSelector = it.getStringValue("initSelector") @@ -199,7 +254,7 @@ fun ConstructorDescriptor.getObjCInitMethod(): FunctionDescriptor? { } } -fun IrConstructor.isObjCConstructor(): Boolean = this.descriptor.annotations.hasAnnotation(objCConstructorFqName) +val IrConstructor.isObjCConstructor get() = this.descriptor.annotations.hasAnnotation(objCConstructorFqName) fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? { return this.descriptor.annotations.findAnnotation(objCConstructorFqName)?.let { @@ -210,6 +265,10 @@ fun IrConstructor.getObjCInitMethod(): IrSimpleFunction? { } } +val IrFunction.hasObjCFactoryAnnotation get() = this.descriptor.annotations.hasAnnotation(objCFactoryFqName) + +val IrFunction.hasObjCMethodAnnotation get() = this.descriptor.annotations.hasAnnotation(objCMethodFqName) + fun FunctionDescriptor.getObjCFactoryInitMethodInfo(): ObjCMethodInfo? { val factoryAnnotation = this.annotations.findAnnotation(objCFactoryFqName) ?: return null val bridgeName = factoryAnnotation.getStringValue("bridge") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt index b46e43c9b77..df928a42590 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassVtablesBuilder.kt @@ -12,11 +12,12 @@ import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.util.simpleFunctions internal class OverriddenFunctionDescriptor( - val descriptor: SimpleFunctionDescriptor, - overriddenDescriptor: SimpleFunctionDescriptor + val descriptor: IrSimpleFunction, + overriddenDescriptor: IrSimpleFunction ) { val overriddenDescriptor = overriddenDescriptor.original @@ -40,7 +41,7 @@ internal class OverriddenFunctionDescriptor( && descriptor.target.overrides(overriddenDescriptor) && descriptor.bridgeDirectionsTo(overriddenDescriptor).allNotNeeded() - fun getImplementation(context: Context): SimpleFunctionDescriptor? { + fun getImplementation(context: Context): IrSimpleFunction? { val target = descriptor.target val implementation = if (!needBridge) target @@ -154,7 +155,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con inheritedVtableSlots + filteredNewVtableSlots.sortedBy { it.overriddenDescriptor.uniqueId } } - fun vtableIndex(function: SimpleFunctionDescriptor): Int { + fun vtableIndex(function: IrSimpleFunction): Int { val bridgeDirections = function.target.bridgeDirectionsTo(function.original) val index = vtableEntries.indexOfFirst { it.descriptor == function.original && it.bridgeDirections == bridgeDirections } if (index < 0) throw Error(function.toString() + " not in vtable of " + classDescriptor.toString()) @@ -170,7 +171,7 @@ internal class ClassVtablesBuilder(val classDescriptor: ClassDescriptor, val con // TODO: probably method table should contain all accessible methods to improve binary compatibility } - private val IrClass.sortedOverridableOrOverridingMethods: List + private val IrClass.sortedOverridableOrOverridingMethods: List get() = this.simpleFunctions() .filter { (it.isOverridable || it.overriddenSymbols.isNotEmpty()) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt index 2e35d37380d..58f18bb4599 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt @@ -5,15 +5,18 @@ package org.jetbrains.kotlin.backend.konan.descriptors +import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.ConstructorDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.DeclarationDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.PackageFragmentDescriptor -import org.jetbrains.kotlin.backend.konan.irasdescriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.backend.konan.isInlined import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.types.isUnit import org.jetbrains.kotlin.types.SimpleType @@ -37,7 +40,7 @@ internal val ClassDescriptor.implementedInterfaces: List * * TODO: this method is actually a part of resolve and probably duplicates another one */ -internal fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction { +internal fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimpleFunction { if (this.isReal) { return this } @@ -72,7 +75,7 @@ internal fun IrSimpleFunction.resolveFakeOverride(): IrSimpleFunction { realSupers.toList().forEach { excludeOverridden(it) } } - return realSupers.first { it.modality != Modality.ABSTRACT } + return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT } } // TODO: don't forget to remove descriptor access here. @@ -131,11 +134,11 @@ private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index: internal fun FunctionDescriptor.needBridgeTo(target: FunctionDescriptor) = (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) } -internal val SimpleFunctionDescriptor.target: SimpleFunctionDescriptor +internal val IrSimpleFunction.target: IrSimpleFunction get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original internal val FunctionDescriptor.target: FunctionDescriptor get() = when (this) { - is SimpleFunctionDescriptor -> this.target + is IrSimpleFunction -> this.target is ConstructorDescriptor -> this else -> error(this) } @@ -185,11 +188,11 @@ internal class BridgeDirections(val array: Array) { } } -val SimpleFunctionDescriptor.allOverriddenDescriptors: Set +val IrSimpleFunction.allOverriddenDescriptors: Set get() { - val result = mutableSetOf() + val result = mutableSetOf() - fun traverse(function: SimpleFunctionDescriptor) { + fun traverse(function: IrSimpleFunction) { if (function in result) return result += function function.overriddenSymbols.forEach { traverse(it.owner) } @@ -200,8 +203,8 @@ val SimpleFunctionDescriptor.allOverriddenDescriptors: Set): Boolean = - this in map.values \ No newline at end of file + 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() +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt index a771c865ea8..8e3f81c2383 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.atMostOne import org.jetbrains.kotlin.backend.konan.RuntimeNames import org.jetbrains.kotlin.backend.konan.binaryTypeIsReference import org.jetbrains.kotlin.backend.konan.isObjCClass -import org.jetbrains.kotlin.backend.konan.serialization.isExported import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.builtins.isFunctionType @@ -20,12 +19,18 @@ import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin +import org.jetbrains.kotlin.descriptors.konan.konanModuleOrigin import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.constants.StringValue +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.util.isFunction +import org.jetbrains.kotlin.ir.util.isKFunction +import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -44,7 +49,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty * * TODO: this method is actually a part of resolve and probably duplicates another one */ -internal fun T.resolveFakeOverride(): T { +internal fun T.resolveFakeOverride(allowAbstract: Boolean = false): T { if (this.kind.isReal) { return this } else { @@ -52,7 +57,7 @@ internal fun T.resolveFakeOverride(): T { val filtered = OverridingUtil.filterOutOverridden(overridden) // TODO: is it correct to take first? @Suppress("UNCHECKED_CAST") - return filtered.first { it.modality != Modality.ABSTRACT } as T + return filtered.first { allowAbstract || it.modality != Modality.ABSTRACT } as T } } @@ -86,6 +91,15 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean this.isOperator && this.name == OperatorNameConventions.INVOKE } +internal val IrFunction.isFunctionInvoke: Boolean + get() { + val dispatchReceiver = dispatchReceiverParameter ?: return false + assert(!dispatchReceiver.type.isKFunction()) + + return dispatchReceiver.type.isFunction() && + /* this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE + } + internal fun ClassDescriptor.isUnit() = this.defaultType.isUnit() internal fun ClassDescriptor.isNothing() = this.defaultType.isNothing() @@ -159,9 +173,6 @@ internal val FunctionDescriptor.needsInlining: Boolean return (this.isInline && !this.isExternal) } -internal val FunctionDescriptor.needsSerializedIr: Boolean - get() = (this.needsInlining && this.isExported()) - fun AnnotationDescriptor.getStringValueOrNull(name: String): String? { val constantValue = this.allValueArguments.entries.atMostOne { it.key.asString() == name @@ -199,6 +210,9 @@ val ClassDescriptor.enumEntries: List internal val DeclarationDescriptor.isExpectMember: Boolean get() = this is MemberDescriptor && this.isExpect +internal val DeclarationDescriptor.isSerializableExpectClass: Boolean + get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this) + internal fun KotlinType?.createExtensionReceiver(owner: CallableDescriptor): ReceiverParameterDescriptor? = DescriptorFactory.createExtensionReceiverParameterForCallable( owner, @@ -286,3 +300,5 @@ fun createAnnotation( values.map { (name, value) -> Name.identifier(name) to StringValue(value) }.toMap(), SourceElement.NO_SOURCE ) + +val ModuleDescriptor.konanLibrary get() = (this.konanModuleOrigin as? DeserializedKonanModuleOrigin)?.library diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt index 75609de23e6..9562fadf03b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/utils.kt @@ -8,8 +8,7 @@ package org.jetbrains.kotlin.backend.konan.descriptors import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.* val DeserializedPropertyDescriptor.konanBackingField: PropertyDescriptor? get() = @@ -48,4 +47,10 @@ internal val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCall internal val CallableMemberDescriptor.isDeserializableCallable get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor) +fun DeclarationDescriptor.findTopLevelDescriptor(): DeclarationDescriptor { + return if (this.containingDeclaration is org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor) this.propertyIfAccessor + else this.containingDeclaration!!.findTopLevelDescriptor() +} +val ModuleDescriptor.isForwardDeclarationModule get() = + name == Name.special("") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 34913e07023..3c504cf3640 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.backend.konan.ir import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME +import org.jetbrains.kotlin.backend.common.RenderIrElementWithDescriptorsVisitor.Companion.DECLARATION_RENDERER +import org.jetbrains.kotlin.backend.common.descriptors.WrappedDeclarationDescriptor import org.jetbrains.kotlin.backend.common.ir.Ir import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.konan.* @@ -19,10 +21,13 @@ import org.jetbrains.kotlin.config.coroutinesPackageFqName import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrSimpleType @@ -30,13 +35,20 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.types.impl.originalKotlinType +import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.renderer.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.utils.Printer +import org.jetbrains.kotlin.utils.addIfNotNull +import java.io.StringWriter import kotlin.properties.Delegates // This is what Context collects about IR. @@ -462,7 +474,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl) val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl) - val getClassTypeInfo = internalFunction("getClassTypeInfo") val getObjectTypeInfo = internalFunction("getObjectTypeInfo") val kClassImpl = internalClass("KClassImpl") @@ -537,3 +548,634 @@ private fun getArrayListClassDescriptor(context: Context): ClassDescriptor { return classifier as ClassDescriptor } + +fun IrElement.render() = accept(RenderIrElementVisitor(), null) + +fun IrType.render() = + originalKotlinType?.let { + DECLARATION_RENDERER.renderType(it) + } ?: DECLARATION_RENDERER.renderType(this.toKotlinType()) + +class RenderIrElementVisitor : IrElementVisitor { + 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().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 visitConst(expression: IrConst, 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 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 { + + 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("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.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() ?: "" + + 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 Collection.dumpItems(caption: String, renderElement: (T) -> Unit) { + if (isEmpty()) return + indented(caption) { + forEach { + renderElement(it) + } + } + } + + private inline fun Collection.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() +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt index 6475d239e02..e1fed413754 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/KonanIr.kt @@ -86,10 +86,13 @@ class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.F //-------------------------------------------------------------------------// override val maxOffset: Int - get() = TODO("not implemented") + //get() = TODO("not implemented") + get() = UNDEFINED_OFFSET override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int): SourceRangeInfo { - TODO("not implemented") + //TODO("not implemented") + return SourceRangeInfo(name, beginOffset, -1, -1, endOffset, -1, -1) + } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/FakeIrUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/FakeIrUtils.kt index 4f5602ab050..c6db07c2714 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/FakeIrUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/FakeIrUtils.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.classifierOrFail import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -25,15 +26,10 @@ internal val IrDeclaration.module get() = this.descriptor.module internal val IrField.isDelegate get() = @Suppress("DEPRECATION") this.descriptor.isDelegated internal fun IrFunction.getObjCMethodInfo() = this.descriptor.getObjCMethodInfo() -internal fun IrClass.isExternalObjCClass() = this.descriptor.isExternalObjCClass() -internal fun IrClass.isKotlinObjCClass() = this.descriptor.isKotlinObjCClass() internal fun IrFunction.getExternalObjCMethodInfo() = this.descriptor.getExternalObjCMethodInfo() internal fun IrFunction.isObjCClassMethod() = this.descriptor.isObjCClassMethod() -internal fun IrFunction.canObjCClassMethodBeCalledVirtually(overridden: IrFunction) = - this.descriptor.canObjCClassMethodBeCalledVirtually(overridden.descriptor) -internal fun IrClass.isObjCClass() = this.descriptor.isObjCClass() + internal fun IrClass.isObjCMetaClass() = this.descriptor.isObjCMetaClass() -internal fun IrFunction.isExternalObjCClassMethod() = this.descriptor.isExternalObjCClassMethod() internal val IrDeclaration.llvmSymbolOrigin get() = this.descriptor.llvmSymbolOrigin diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/IrAsDescriptors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/IrAsDescriptors.kt index 3b36fa1ce88..219f64c4096 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/IrAsDescriptors.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/IrAsDescriptors.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol internal typealias DeclarationDescriptor = IrDeclaration internal typealias FunctionDescriptor = IrFunction -internal typealias SimpleFunctionDescriptor = IrSimpleFunction internal typealias ClassDescriptor = IrClass internal typealias ConstructorDescriptor = IrConstructor internal typealias ClassConstructorDescriptor = IrConstructor diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt index 911d6f439e4..6736b119e36 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl @@ -19,6 +20,8 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.explicitParameters import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.ir.util.isFunction +import org.jetbrains.kotlin.ir.util.isSuspendFunction import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor @@ -162,3 +165,17 @@ fun IrAnnotationContainer.hasAnnotation(fqName: FqName) = fun List.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull { it.annotationClass.fqNameSafe == fqName } + +fun IrValueParameter.isInlineParameter(): Boolean = + !this.isNoinline && (this.type.isFunction() || this.type.isSuspendFunction()) && !this.type.isMarkedNullable() + +val IrDeclaration.parentDeclarationsWithSelf: Sequence + 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 diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt index a34fca1d539..73d332f72c1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/KonanLibraryWriter.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.backend.konan.library import llvm.LLVMModuleRef +import org.jetbrains.kotlin.backend.konan.serialization.UniqId import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning import org.jetbrains.kotlin.konan.properties.Properties @@ -26,7 +27,14 @@ interface KonanLibraryWriter { class LinkData( val module: ByteArray, val fragments: List>, - val fragmentNames: List + val fragmentNames: List, + val ir: SerializedIr? = null +) + +class SerializedIr ( + val module: ByteArray, + val declarations: Map, + val debugIndex: Map ) interface MetadataWriter { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt index 3918c57ea9e..435dfad5dc5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/KonanLibraryWriterImpl.kt @@ -52,6 +52,7 @@ class LibraryWriterImpl( nativeDir.mkdirs() includedDir.mkdirs() resourcesDir.mkdirs() + irDir.mkdirs() // TODO: : will go somewhere around here. manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName) manifestProperties.writeKonanLibraryVersioning(versions) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/MetadataWriterImpl.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/MetadataWriterImpl.kt index be8d8bb7388..5d175f7ccc2 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/MetadataWriterImpl.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/library/impl/MetadataWriterImpl.kt @@ -12,6 +12,7 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra fun addLinkData(linkData: LinkData) { moduleHeaderFile.writeBytes(linkData.module) + wholeIrFile.writeBytes(linkData.ir!!.module) linkData.fragments.forEachIndexed { index, it -> val packageFqName = linkData.fragmentNames[index] val shortName = packageFqName.substringAfterLast(".") @@ -24,5 +25,15 @@ internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibra packageFragmentFile(packageFqName, "${withLeadingZeros(i)}_$shortName").writeBytes(fragment) } } + linkData.ir?.declarations?.forEach { + val index = it.key.index.toULong().toString(16) + val file = if (it.key.isLocal) + hiddenDeclarationFile(index) + else + visibleDeclarationFile(index) + file.writeBytes(it.value) + } + val lines = linkData.ir?.debugIndex.map { entry -> "${entry.key}: ${entry.value}" } + irIndex.writeLines(lines) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt index ab312ec2fe5..cd6f9d3f1b7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/BinaryInterface.kt @@ -6,12 +6,11 @@ package org.jetbrains.kotlin.backend.konan.llvm import llvm.LLVMTypeRef -import org.jetbrains.kotlin.backend.konan.RuntimeNames +import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.descriptors.externalSymbolOrThrow import org.jetbrains.kotlin.backend.konan.descriptors.getAnnotationValue import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.irasdescriptors.* -import org.jetbrains.kotlin.backend.konan.isInlined import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -38,7 +37,7 @@ import org.jetbrains.kotlin.name.Name * that doesn't depend on any internal transformations (e.g. IR lowering), * and so should be computable from the descriptor itself without checking a backend state. */ -internal tailrec fun DeclarationDescriptor.isExported(): Boolean { +internal tailrec fun IrDeclaration.isExported(): Boolean { // TODO: revise val descriptorAnnotations = this.descriptor.annotations if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) { @@ -63,7 +62,7 @@ internal tailrec fun DeclarationDescriptor.isExported(): Boolean { if (this.isAnonymousObject) return false - if (this is ConstructorDescriptor && constructedClass.kind.isSingleton) { + if (this is IrConstructor && constructedClass.kind.isSingleton) { // Currently code generator can access the constructor of the singleton, // so ignore visibility of the constructor itself. return constructedClass.isExported() @@ -151,11 +150,21 @@ private fun acyclicTypeMangler(visited: MutableSet, typ private fun typeToHashString(type: IrType) = acyclicTypeMangler(mutableSetOf(), type) -private val FunctionDescriptor.signature: String +internal val IrValueParameter.extensionReceiverNamePart: String + get() = "@${typeToHashString(this.type)}." + +private val IrFunction.signature: String get() { - val extensionReceiverPart = this.extensionReceiverParameter?.let { "@${typeToHashString(it.type)}." } ?: "" + val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: "" val argsPart = this.valueParameters.map { - "${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}" + + // TODO: there are clashes originating from ObjectiveC interop. + // kotlinx.cinterop.ObjCClassOf.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt + // and + // kotlinx.cinterop.ObjCClassOf.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt + + val argName = if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${it.name}:" else "" + "$argName${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}" }.joinToString(";") // Distinguish value types and references - it's needed for calling virtual methods through bridges. // Also is function has type arguments - frontend allows exactly matching overrides. @@ -170,10 +179,10 @@ private val FunctionDescriptor.signature: String } // TODO: rename to indicate that it has signature included -internal val FunctionDescriptor.functionName: String +internal val IrFunction.functionName: String get() { with(this.original) { // basic support for generics - this.getObjCMethodInfo()?.let { + (if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let { return buildString { if (extensionReceiverParameter != null) { append(extensionReceiverParameter!!.type.getClass()!!.name) @@ -182,6 +191,20 @@ internal val FunctionDescriptor.functionName: String append("objc:") append(it.selector) + if (this@with is IrConstructor && this@with.isObjCConstructor) append("#Constructor") + + // We happen to have the clashing combinations such as + //@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165") + //external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit + //@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172") + //external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit + // So disambiguate by the name of the bridge for now. + // TODO: idealy we'd never generate such identical declarations. + + if (this@with is IrSimpleFunction && this@with.hasObjCMethodAnnotation()) { + this@with.objCMethodArgValue("selector") ?.let { append("#$it") } + this@with.objCMethodArgValue("bridge") ?.let { append("#$it") } + } } } @@ -201,7 +224,7 @@ private fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility "$this\$$moduleName" } -internal val FunctionDescriptor.symbolName: String +internal val IrFunction.symbolName: String get() { if (!this.isExported()) { throw AssertionError(this.descriptor.toString()) @@ -231,15 +254,15 @@ internal val IrField.symbolName: String val containingDeclarationPart = parent.fqNameSafe.let { if (it.isRoot) "" else "$it." } - return "kprop:$containingDeclarationPart$name" + return "kfield:$containingDeclarationPart$name" } // TODO: bring here dependencies of this method? -internal fun RuntimeAware.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef { +internal fun RuntimeAware.getLlvmFunctionType(function: IrFunction): LLVMTypeRef { val original = function.original val returnType = when { - original is ConstructorDescriptor -> voidType + original is IrConstructor -> voidType original.isSuspend -> kObjHeaderPtr // Suspend functions return Any?. else -> getLLVMReturnType(original.returnType) } @@ -259,19 +282,21 @@ internal fun RuntimeAware.getLlvmFunctionType(symbol: DataFlowIR.FunctionSymbol) return functionType(returnType, isVarArg = false, paramTypes = *paramTypes.toTypedArray()) } -internal val ClassDescriptor.typeInfoSymbolName: String +internal val IrClass.typeInfoSymbolName: String get() { assert (this.isExported()) return "ktype:" + this.fqNameSafe.toString() } -internal val ClassDescriptor.writableTypeInfoSymbolName: String +internal val IrClass.writableTypeInfoSymbolName: String get() { assert (this.isExported()) return "ktypew:" + this.fqNameSafe.toString() } -internal val ClassDescriptor.objectInstanceFieldSymbolName: String +internal val theUnitInstanceName = "kobj:kotlin.Unit" + +internal val IrClass.objectInstanceFieldSymbolName: String get() { assert (this.isExported()) assert (this.kind.isSingleton) @@ -280,7 +305,7 @@ internal val ClassDescriptor.objectInstanceFieldSymbolName: String return "kobjref:$fqNameSafe" } -internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String +internal val IrClass.objectInstanceShadowFieldSymbolName: String get() { assert (this.isExported()) assert (this.kind.isSingleton) @@ -290,7 +315,7 @@ internal val ClassDescriptor.objectInstanceShadowFieldSymbolName: String return "kshadowobjref:$fqNameSafe" } -internal val ClassDescriptor.typeInfoHasVtableAttached: Boolean +internal val IrClass.typeInfoHasVtableAttached: Boolean get() = !this.isAbstract() && !this.isExternalObjCClass() internal fun ModuleDescriptor.privateFunctionSymbolName(index: Int, functionName: String?) = "private_functions_${name.asString()}_${functionName}_$index" diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt index 4fc209f7794..75eb3274043 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.ClassDescriptor import org.jetbrains.kotlin.backend.konan.irasdescriptors.FunctionDescriptor -import org.jetbrains.kotlin.backend.konan.irasdescriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.backend.konan.llvm.objc.* import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.declarations.* @@ -655,7 +654,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef, * if toString/eq/hc is invoked on an interface instance, we resolve * owner as Any and dispatch it via vtable. */ - val anyMethod = (descriptor as SimpleFunctionDescriptor).findOverriddenMethodOfAny() + val anyMethod = (descriptor as IrSimpleFunction).findOverriddenMethodOfAny() val owner = (anyMethod ?: descriptor).containingDeclaration as ClassDescriptor val llvmMethod = if (!owner.isInterface) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 9ac23504f0f..8d21d887f34 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -146,7 +146,7 @@ internal interface ContextUtils : RuntimeAware { fun isExternal(descriptor: DeclarationDescriptor): Boolean { val pkg = descriptor.findPackage() return when (pkg) { - is IrFile -> false + is IrFile -> pkg.packageFragmentDescriptor.containingDeclaration != context.moduleDescriptor is IrExternalPackageFragment -> true else -> error(pkg) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 8560de8250d..f011f606de5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -601,7 +601,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef { //context.log{"evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}"} - if (superClass == null && descriptor is SimpleFunctionDescriptor && descriptor.isOverridable) + if (superClass == null && descriptor is IrSimpleFunction && descriptor.isOverridable) return callVirtual(descriptor, args, resultLifetime) else return callDirect(descriptor, args, resultLifetime) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt index 93b9a9ace2b..d8d35a144fd 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmDeclarations.kt @@ -42,10 +42,10 @@ internal class LlvmDeclarations( private val staticFields: Map, private val unique: Map) { fun forFunction(descriptor: FunctionDescriptor) = functions[descriptor] ?: - error(descriptor.toString()) + error("${descriptor.toString()} ${descriptor.name} in ${(descriptor.parent as IrDeclaration).name}") fun forClass(descriptor: ClassDescriptor) = classes[descriptor] ?: - error(descriptor.toString()) + error("$descriptor ${descriptor.name}") fun forField(descriptor: IrField) = fields[descriptor] ?: error(descriptor.toString()) @@ -393,7 +393,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) : val descriptor = declaration val llvmFunctionType = getLlvmFunctionType(descriptor) - if ((descriptor is ConstructorDescriptor && descriptor.isObjCConstructor())) { + if ((descriptor is ConstructorDescriptor && descriptor.isObjCConstructor)) { return } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index d125617b6b9..7a24011e756 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.computePrimitiveBinaryTypeOrNull import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.* +import org.jetbrains.kotlin.backend.konan.isExternalObjCClassMethod import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.types.* diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt index 2b755b45029..de345ad0e20 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt @@ -337,4 +337,4 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass } } } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt index 503529db554..ef82572f774 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.backend.konan.lower -import org.jetbrains.kotlin.backend.common.* +import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope @@ -21,18 +21,25 @@ import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.symbols.impl.* +import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull +import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.visitors.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.storage.LockBasedStorageManager -import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeSubstitutor +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.Variance internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, val typeArguments: Map?, @@ -71,6 +78,10 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, } override fun visitField(declaration: IrField) { + // TODO: inlining a function returning an object + // we get PropertyDescriptors from whithin that object here. + // That is a bug, most probably. + // We workaround the issue with question marks here. (declaration.descriptor as? WrappedFieldDescriptor)?.bind(declaration) declaration.acceptChildrenVoid(this) } @@ -96,7 +107,6 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, declaration.acceptChildrenVoid(this) } }) - result.patchDeclarationParents(parent) return result } @@ -1013,4 +1023,4 @@ internal class DescriptorSubstitutorForExternalScope( return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol) } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt index 44c81321e84..1480cf3901d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ExpectDeclarationsRemoving.kt @@ -30,18 +30,28 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver * Note: org.jetbrains.kotlin.backend.common.lower.ExpectDeclarationsRemoving is copy of this lower. */ internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass { - override fun lower(irFile: IrFile) { // All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`. irFile.declarations.removeAll { if (it.descriptor.isExpectMember) { - copyDefaultArgumentsFromExpectToActual(it) true } else { false } } } +} + +internal class ExpectToActualDefaultValueCopier(val context: Context) : FileLoweringPass { + + override fun lower(irFile: IrFile) { + // All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`. + irFile.declarations.forEach { + if (it.descriptor.isExpectMember) { + copyDefaultArgumentsFromExpectToActual(it) + } + } + } private fun copyDefaultArgumentsFromExpectToActual(declaration: IrDeclaration) { declaration.acceptVoid(object : IrElementVisitorVoid { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index b5d00874617..13390ac55fd 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -9,16 +9,16 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters -import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin +import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining import org.jetbrains.kotlin.backend.konan.descriptors.propertyIfAccessor import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride -import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass +import org.jetbrains.kotlin.backend.konan.irasdescriptors.isInlineParameter import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrElement @@ -34,10 +34,10 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.referenceFunction import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjectionImpl @@ -119,7 +119,6 @@ internal class Ref(var value: T) internal class FunctionInlining(val context: Context): IrElementTransformerWithContext>() { - private val deserializer = DeserializerDriver(context) private val globalSubstituteMap = mutableMapOf() private val inlineFunctions = mutableMapOf() @@ -138,8 +137,9 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC val result = super.visitFunctionNew(declaration, localData) data.value = data.value or localData.value - if (descriptor.needsInlining) + if (descriptor.needsInlining) { inlineFunctions[descriptor] = localData.value + } return result } @@ -163,19 +163,20 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC } data.value = data.value or callee.second + // TODO: do we still need this Ref mechanism? val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false) callee.first.transformChildren(this, childIsBad) // Process recursive inline. inlineFunctions[functionDescriptor] = childIsBad.value data.value = data.value or childIsBad.value - val currentCalleeIsBad = argsAreBad.value or childIsBad.value or callee.second + + val currentCalleeIsBad = false val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!, allScopes.map { it.irElement }.filterIsInstance().lastOrNull(), context, this) return inliner.inline() } - //-------------------------------------------------------------------------// - + // TODO: do we really need this function anymore? private fun getFunctionDeclaration(descriptor: FunctionDescriptor): Pair? = when { descriptor.isBuiltInIntercepted(context.config.configuration.languageVersionSettings) -> @@ -189,7 +190,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC else -> context.ir.originalModuleIndex.functions[descriptor]?.let { it to false } - ?: deserializer.deserializeInlineBody(descriptor)?.let { it as IrFunction to true } + ?: context.ir.symbols.symbolTable.referenceFunction(descriptor).owner to true } } @@ -258,8 +259,8 @@ private class Inliner(val globalSubstituteMap: MutableMap() override fun visitClass(declaration: IrClass): IrStatement { - if (declaration.descriptor.isKotlinObjCClass()) { + if (declaration.isKotlinObjCClass()) { lowerKotlinObjCClass(declaration) } @@ -507,13 +507,13 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme val constructedClass = outerClasses.peek()!! val constructedClassDescriptor = constructedClass.descriptor - if (!constructedClassDescriptor.isObjCClass()) { + if (!constructedClass.isObjCClass()) { return expression } - constructedClassDescriptor.containingDeclaration.let { classContainer -> - if (classContainer is ClassDescriptor && classContainer.isObjCClass() && - constructedClassDescriptor == classContainer.companionObjectDescriptor) { + constructedClass.parent.let { parent -> + if (parent is IrClass && parent.isObjCClass() && + constructedClass.isCompanion) { // Note: it is actually not used; getting values of such objects is handled by code generator // in [FunctionGenerationContext.getObjectValue]. @@ -522,8 +522,8 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme } } - if (!constructedClassDescriptor.isExternalObjCClass() && - expression.descriptor.constructedClass.isExternalObjCClass()) { + if (!constructedClass.isExternalObjCClass() && + (expression.symbol.owner.constructedClass).isExternalObjCClass()) { // Calling super constructor from Kotlin Objective-C class. @@ -531,7 +531,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme val initMethod = expression.descriptor.getObjCInitMethod()!! - if (!expression.descriptor.objCConstructorIsDesignated()) { + if (!expression.symbol.owner.objCConstructorIsDesignated()) { context.reportCompilationError( "Unable to call non-designated initializer as super constructor", currentFile, @@ -582,7 +582,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme val superClass = superQualifier?.let { getObjCClass(it) } ?: irCall(symbols.getNativeNullPtr, symbols.nativePtrType) - val bridge = symbolTable.referenceSimpleFunction(info.bridge) + val bridge = symbols.lazySymbolTable.referenceSimpleFunction(info.bridge) return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply { putValueArgument(0, superClass) putValueArgument(1, receiver) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt index a0cbd25ea62..61bd1f46f2c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/SuspendFunctionsLowering.kt @@ -1103,4 +1103,4 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass scopeStack.peek()!!.add(declaration) } } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt index 4a407f03ce1..fb195c7462b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/TestProcessor.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.lower.SymbolWithIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.reportWarning import org.jetbrains.kotlin.backend.konan.KonanBackendContext @@ -37,6 +38,8 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult internal class TestProcessor (val context: KonanBackendContext) { @@ -608,4 +611,4 @@ internal class TestProcessor (val context: KonanBackendContext) { createTestSuites(it, annotationCollector) } } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt index 6bb08e0dad5..489df3f7f14 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGBuilder.kt @@ -33,7 +33,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.util.OperatorNameConventions -private fun IrClass.getOverridingOf(function: FunctionDescriptor) = (function as? SimpleFunctionDescriptor)?.let { +private fun IrClass.getOverridingOf(function: FunctionDescriptor) = (function as? IrSimpleFunction)?.let { it.allOverriddenDescriptors.atMostOne { it.parent == this } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt index 573659d3d9c..2821e766353 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DFGSerializer.kt @@ -1274,4 +1274,4 @@ internal object DFGSerializer { return ExternalModulesDFG(allTypes, publicTypesMap, publicFunctionsMap, functions) } -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt index 5489d6afa29..2c43d9dd781 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/optimizations/DataFlowIR.kt @@ -601,7 +601,7 @@ internal object DataFlowIR { } else -> { - val isAbstract = it is SimpleFunctionDescriptor && it.modality == Modality.ABSTRACT + val isAbstract = it is IrSimpleFunction && it.modality == Modality.ABSTRACT val classDescriptor = it.containingDeclaration as? ClassDescriptor val bridgeTarget = it.bridgeTarget val isSpecialBridge = bridgeTarget.let { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt index c71f4250c88..9992cc011df 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/BackingFieldVisitor.kt @@ -7,10 +7,7 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.util.addChild import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid @@ -30,7 +27,9 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid list?.add(declaration.backingField!!.descriptor) } if (declaration.backingField == null || declaration.isDelegated) return - assert(declaration.backingField!!.descriptor == declaration.descriptor) + assert(declaration.backingField!!.descriptor == declaration.descriptor) { + "backing field descriptor mismatch: ${declaration.backingField!!.descriptor} != ${declaration.descriptor}" + } context.ir.propertiesWithBackingFields.add(declaration.descriptor) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeclarationTable.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeclarationTable.kt new file mode 100644 index 00000000000..8b922206754 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeclarationTable.kt @@ -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 MutableMap.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() + 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() + val debugIndex = mutableMapOf() + 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 \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorTable.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorTable.kt deleted file mode 100644 index 7900bc283a3..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorTable.kt +++ /dev/null @@ -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() - 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() - - 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, 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(), 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() - } - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeserializeDescriptorReference.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeserializeDescriptorReference.kt new file mode 100644 index 00000000000..1ddfa5f1389 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeserializeDescriptorReference.kt @@ -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) { + + fun deserializeDescriptorReference(proto: KonanIr.DescriptorReference): DeclarationDescriptor { + val packageFqName = + if (proto.packageFqName == "") 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}") + } +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeserializerDriver.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeserializerDriver.kt deleted file mode 100644 index f2ca7bba1e5..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DeserializerDriver.kt +++ /dev/null @@ -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() - - 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(worker) - - inner class InlineBodyPrinter: EmptyDescriptorVisitorVoid() { - - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, data: Unit): Boolean { - if (descriptor.isDeserializableCallable) { - this@DeserializerDriver.deserializeInlineBody(descriptor) - } - - return true - } - } -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt deleted file mode 100644 index 6e43105daa8..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt +++ /dev/null @@ -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() - 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 { - 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, - 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, - descriptorProto: KonanIr.KotlinDescriptor): - DeserializedClassConstructorDescriptor { - val originalIndex = descriptorProto.originalIndex - return constructors.single { - it.uniqId == originalIndex - } as DeserializedClassConstructorDescriptor - } - - - fun selectAccessor( - functions: Collection, - 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, - 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) - } -} - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt deleted file mode 100644 index 2a493a80586..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt +++ /dev/null @@ -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() - } - -} - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrModuleDeserializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrModuleDeserializer.kt new file mode 100644 index 00000000000..189f56b1325 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrModuleDeserializer.kt @@ -0,0 +1,1135 @@ +/* + * 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.common.ir.DeclarationFactory +import org.jetbrains.kotlin.backend.common.ir.ir2string +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.* +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.* +import org.jetbrains.kotlin.ir.util.IrDeserializer +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.metadata.KonanIr +import org.jetbrains.kotlin.metadata.KonanIr.IrConst.ValueCase.* +import org.jetbrains.kotlin.metadata.KonanIr.IrDeclarator.DeclaratorCase.* +import org.jetbrains.kotlin.metadata.KonanIr.IrOperation.OperationCase.* +import org.jetbrains.kotlin.metadata.KonanIr.IrStatement.StatementCase +import org.jetbrains.kotlin.metadata.KonanIr.IrType.KindCase.* +import org.jetbrains.kotlin.metadata.KonanIr.IrTypeArgument.KindCase.STAR +import org.jetbrains.kotlin.metadata.KonanIr.IrTypeArgument.KindCase.TYPE +import org.jetbrains.kotlin.metadata.KonanIr.IrVarargElement.VarargElementCase +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.Variance + +// TODO: This code still has some uses of descriptors: +// 1. We use descriptors as keys for symbolTable -- probably symbol table related code should be refactored out from +// the deserializer. +// 2. Properties use descriptors but not symbols -- that causes lots of assymmetry all around. +// 3. Declarations are provided with wrapped descriptors. That is probably a legitimate descriptor use. + +abstract class IrModuleDeserializer( + val logger: LoggingContext, + val builtIns: IrBuiltIns, + val symbolTable: SymbolTable +) : IrDeserializer { + + abstract fun deserializeIrSymbol(proto: KonanIr.IrSymbol): IrSymbol + abstract fun deserializeIrType(proto: KonanIr.IrTypeIndex): IrType + abstract fun deserializeDescriptorReference(proto: KonanIr.DescriptorReference): DeclarationDescriptor + + private fun deserializeTypeArguments(proto: KonanIr.TypeArguments): List { + logger.log { "### deserializeTypeArguments" } + val result = mutableListOf() + proto.typeArgumentList.forEach { typeProto -> + val type = deserializeIrType(typeProto) + result.add(type) + logger.log { "$type" } + } + return result + } + + fun deserializeIrTypeVariance(variance: KonanIr.IrTypeVariance) = when (variance) { + KonanIr.IrTypeVariance.IN -> Variance.IN_VARIANCE + KonanIr.IrTypeVariance.OUT -> Variance.OUT_VARIANCE + KonanIr.IrTypeVariance.INV -> Variance.INVARIANT + } + + fun deserializeIrTypeArgument(proto: KonanIr.IrTypeArgument) = when (proto.kindCase) { + STAR -> IrStarProjectionImpl + TYPE -> makeTypeProjection( + deserializeIrType(proto.type.type), deserializeIrTypeVariance(proto.type.variance) + ) + else -> TODO("Unexpected projection kind") + + } + + fun deserializeAnnotations(annotations: KonanIr.Annotations): List { + return annotations.annotationList.map { + deserializeCall(it, 0, 0, builtIns.unitType) // TODO: need a proper deserialization here + } + } + + fun deserializeSimpleType(proto: KonanIr.IrSimpleType): IrSimpleType { + val arguments = proto.argumentList.map { deserializeIrTypeArgument(it) } + val annotations = deserializeAnnotations(proto.annotations) + val symbol = deserializeIrSymbol(proto.classifier) as? IrClassifierSymbol + //?: error("could not convert sym to ClassifierSym ${proto.classifier.kind} ${proto.classifier.uniqId.index} ${proto.classifier.uniqId.isLocal}") + ?: error("could not convert sym to ClassifierSymbol") + logger.log { "deserializeSimpleType: symbol=$symbol" } + val result = IrSimpleTypeImpl( + null, + symbol, + proto.hasQuestionMark, + arguments, + annotations + ) + logger.log { "ir_type = $result; render = ${result.render()}" } + return result + } + + fun deserializeDynamicType(proto: KonanIr.IrDynamicType): IrDynamicType { + val annotations = deserializeAnnotations(proto.annotations) + return IrDynamicTypeImpl(null, annotations, Variance.INVARIANT) + } + + fun deserializeErrorType(proto: KonanIr.IrErrorType): IrErrorType { + val annotations = deserializeAnnotations(proto.annotations) + return IrErrorTypeImpl(null, annotations, Variance.INVARIANT) + } + + fun deserializeIrTypeData(proto: KonanIr.IrType): IrType { + return when (proto.kindCase) { + SIMPLE -> deserializeSimpleType(proto.simple) + DYNAMIC -> deserializeDynamicType(proto.dynamic) + ERROR -> deserializeErrorType(proto.error) + else -> TODO("Unexpected IrType kind: ${proto.kindCase}") + } + } + + /* -------------------------------------------------------------- */ + + private fun deserializeBlockBody( + proto: KonanIr.IrBlockBody, + start: Int, end: Int + ): IrBlockBody { + + val statements = mutableListOf() + + val statementProtos = proto.statementList + statementProtos.forEach { + statements.add(deserializeStatement(it) as IrStatement) + } + + return IrBlockBodyImpl(start, end, statements) + } + + private fun deserializeBranch(proto: KonanIr.IrBranch, start: Int, end: Int): IrBranch { + + val condition = deserializeExpression(proto.condition) + val result = deserializeExpression(proto.result) + + return IrBranchImpl(start, end, condition, result) + } + + private fun deserializeCatch(proto: KonanIr.IrCatch, start: Int, end: Int): IrCatch { + val catchParameter = + deserializeDeclaration(proto.catchParameter, null) as IrVariable // TODO: we need a proper parent here + val result = deserializeExpression(proto.result) + + val catch = IrCatchImpl(start, end, catchParameter, result) + return catch + } + + private fun deserializeSyntheticBody(proto: KonanIr.IrSyntheticBody, start: Int, end: Int): IrSyntheticBody { + val kind = when (proto.kind) { + KonanIr.IrSyntheticBodyKind.ENUM_VALUES -> IrSyntheticBodyKind.ENUM_VALUES + KonanIr.IrSyntheticBodyKind.ENUM_VALUEOF -> IrSyntheticBodyKind.ENUM_VALUEOF + } + return IrSyntheticBodyImpl(start, end, kind) + } + + private fun deserializeStatement(proto: KonanIr.IrStatement): IrElement { + val start = proto.coordinates.startOffset + val end = proto.coordinates.endOffset + val element = when (proto.statementCase) { + StatementCase.BLOCK_BODY //proto.hasBlockBody() + -> deserializeBlockBody(proto.blockBody, start, end) + StatementCase.BRANCH //proto.hasBranch() + -> deserializeBranch(proto.branch, start, end) + StatementCase.CATCH //proto.hasCatch() + -> deserializeCatch(proto.catch, start, end) + StatementCase.DECLARATION // proto.hasDeclaration() + -> deserializeDeclaration(proto.declaration, null) // TODO: we need a proper parent here. + StatementCase.EXPRESSION // proto.hasExpression() + -> deserializeExpression(proto.expression) + StatementCase.SYNTHETIC_BODY // proto.hasSyntheticBody() + -> deserializeSyntheticBody(proto.syntheticBody, start, end) + else + -> TODO("Statement deserialization not implemented: ${proto.statementCase}") + } + + logger.log { "### Deserialized statement: ${ir2string(element)}" } + + return element + } + + private fun deserializeBlock(proto: KonanIr.IrBlock, start: Int, end: Int, type: IrType): IrBlock { + val statements = mutableListOf() + val statementProtos = proto.statementList + statementProtos.forEach { + statements.add(deserializeStatement(it) as IrStatement) + } + + val isLambdaOrigin = if (proto.isLambdaOrigin) IrStatementOrigin.LAMBDA else null + + return IrBlockImpl(start, end, type, isLambdaOrigin, statements) + } + + private fun deserializeMemberAccessCommon(access: IrMemberAccessExpression, proto: KonanIr.MemberAccessCommon) { + + proto.valueArgumentList.mapIndexed { i, arg -> + if (arg.hasExpression()) { + val expr = deserializeExpression(arg.expression) + access.putValueArgument(i, expr) + } + } + + deserializeTypeArguments(proto.typeArguments).forEachIndexed { index, type -> + access.putTypeArgument(index, type) + } + + if (proto.hasDispatchReceiver()) { + access.dispatchReceiver = deserializeExpression(proto.dispatchReceiver) + } + if (proto.hasExtensionReceiver()) { + access.extensionReceiver = deserializeExpression(proto.extensionReceiver) + } + } + + private fun deserializeClassReference( + proto: KonanIr.IrClassReference, + start: Int, + end: Int, + type: IrType + ): IrClassReference { + val symbol = deserializeIrSymbol(proto.classSymbol) as IrClassifierSymbol + val classType = deserializeIrType(proto.classType) + /** TODO: [createClassifierSymbolForClassReference] is internal function */ + return IrClassReferenceImpl(start, end, type, symbol, classType) + } + + private fun deserializeCall(proto: KonanIr.IrCall, start: Int, end: Int, type: IrType): IrCall { + val symbol = deserializeIrSymbol(proto.symbol) as IrFunctionSymbol + + val superSymbol = if (proto.hasSuper()) { + deserializeIrSymbol(proto.`super`) as IrClassSymbol + } else null + + val call: IrCall = when (proto.kind) { + KonanIr.IrCall.Primitive.NOT_PRIMITIVE -> + // TODO: implement the last three args here. + IrCallImpl( + start, end, type, + symbol, symbol.descriptor, + proto.memberAccess.typeArguments.typeArgumentCount, + proto.memberAccess.valueArgumentList.size, + null, superSymbol + ) + KonanIr.IrCall.Primitive.NULLARY -> + IrNullaryPrimitiveImpl(start, end, type, null, symbol) + KonanIr.IrCall.Primitive.UNARY -> + IrUnaryPrimitiveImpl(start, end, type, null, symbol) + KonanIr.IrCall.Primitive.BINARY -> + IrBinaryPrimitiveImpl(start, end, type, null, symbol) + else -> TODO("Unexpected primitive IrCall.") + } + deserializeMemberAccessCommon(call, proto.memberAccess) + return call + } + + private fun deserializeComposite(proto: KonanIr.IrComposite, start: Int, end: Int, type: IrType): IrComposite { + val statements = mutableListOf() + val statementProtos = proto.statementList + statementProtos.forEach { + statements.add(deserializeStatement(it) as IrStatement) + } + return IrCompositeImpl(start, end, type, null, statements) + } + + private fun deserializeDelegatingConstructorCall( + proto: KonanIr.IrDelegatingConstructorCall, + start: Int, + end: Int + ): IrDelegatingConstructorCall { + val symbol = deserializeIrSymbol(proto.symbol) as IrConstructorSymbol + val call = IrDelegatingConstructorCallImpl( + start, + end, + builtIns.unitType, + symbol, + symbol.descriptor, + proto.memberAccess.typeArguments.typeArgumentCount, + proto.memberAccess.valueArgumentList.size + ) + + deserializeMemberAccessCommon(call, proto.memberAccess) + return call + } + + + fun deserializeEnumConstructorCall( + proto: KonanIr.IrEnumConstructorCall, + start: Int, + end: Int, + type: IrType + ): IrEnumConstructorCall { + val symbol = deserializeIrSymbol(proto.symbol) as IrConstructorSymbol + val call = IrEnumConstructorCallImpl( + start, + end, + type, + symbol, + proto.memberAccess.typeArguments.typeArgumentList.size, + proto.memberAccess.valueArgumentList.size + ) + deserializeMemberAccessCommon(call, proto.memberAccess) + return call + } + + + private fun deserializeFunctionReference( + proto: KonanIr.IrFunctionReference, + start: Int, end: Int, type: IrType + ): IrFunctionReference { + + val symbol = deserializeIrSymbol(proto.symbol) as IrFunctionSymbol + val callable = IrFunctionReferenceImpl( + start, + end, + type, + symbol, + symbol.descriptor, + proto.memberAccess.typeArguments.typeArgumentCount, + proto.memberAccess.valueArgumentCount, + null + ) + deserializeMemberAccessCommon(callable, proto.memberAccess) + + return callable + } + + private fun deserializeGetClass(proto: KonanIr.IrGetClass, start: Int, end: Int, type: IrType): IrGetClass { + val argument = deserializeExpression(proto.argument) + return IrGetClassImpl(start, end, type, argument) + } + + private fun deserializeGetField(proto: KonanIr.IrGetField, start: Int, end: Int, type: IrType): IrGetField { + val access = proto.fieldAccess + val symbol = deserializeIrSymbol(access.symbol) as IrFieldSymbol + val superQualifier = if (access.hasSuper()) { + deserializeIrSymbol(access.symbol) as IrClassSymbol + } else null + val receiver = if (access.hasReceiver()) { + deserializeExpression(access.receiver) + } else null + + return IrGetFieldImpl(start, end, symbol, type, receiver, null, superQualifier) + } + + private fun deserializeGetValue(proto: KonanIr.IrGetValue, start: Int, end: Int, type: IrType): IrGetValue { + val symbol = deserializeIrSymbol(proto.symbol) as IrValueSymbol + // TODO: origin! + return IrGetValueImpl(start, end, type, symbol, null) + } + + private fun deserializeGetEnumValue(proto: KonanIr.IrGetEnumValue, start: Int, end: Int, type: IrType): IrGetEnumValue { + val symbol = deserializeIrSymbol(proto.symbol) as IrEnumEntrySymbol + return IrGetEnumValueImpl(start, end, type, symbol) + } + + private fun deserializeGetObject(proto: KonanIr.IrGetObject, start: Int, end: Int, type: IrType): IrGetObjectValue { + val symbol = deserializeIrSymbol(proto.symbol) as IrClassSymbol + return IrGetObjectValueImpl(start, end, type, symbol) + } + + private fun deserializeInstanceInitializerCall( + proto: KonanIr.IrInstanceInitializerCall, + start: Int, + end: Int + ): IrInstanceInitializerCall { + val symbol = deserializeIrSymbol(proto.symbol) as IrClassSymbol + return IrInstanceInitializerCallImpl(start, end, symbol, builtIns.unitType) + } + + private fun deserializePropertyReference( + proto: KonanIr.IrPropertyReference, + start: Int, end: Int, type: IrType + ): IrPropertyReference { + + val field = if (proto.hasField()) deserializeIrSymbol(proto.field) as IrFieldSymbol else null + val getter = if (proto.hasGetter()) deserializeIrSymbol(proto.getter) as IrSimpleFunctionSymbol else null + val setter = if (proto.hasSetter()) deserializeIrSymbol(proto.setter) as IrSimpleFunctionSymbol else null + val descriptor = WrappedPropertyDescriptor() + + val callable = IrPropertyReferenceImpl( + start, end, type, + descriptor, + proto.memberAccess.typeArguments.typeArgumentCount, + field, + getter, + setter, + null + ) + deserializeMemberAccessCommon(callable, proto.memberAccess) + return callable + } + + private fun deserializeReturn(proto: KonanIr.IrReturn, start: Int, end: Int, type: IrType): IrReturn { + val symbol = deserializeIrSymbol(proto.returnTarget) as IrReturnTargetSymbol + val value = deserializeExpression(proto.value) + return IrReturnImpl(start, end, builtIns.nothingType, symbol, value) + } + + private fun deserializeSetField(proto: KonanIr.IrSetField, start: Int, end: Int): IrSetField { + val access = proto.fieldAccess + val symbol = deserializeIrSymbol(access.symbol) as IrFieldSymbol + val superQualifier = if (access.hasSuper()) { + deserializeIrSymbol(access.symbol) as IrClassSymbol + } else null + val receiver = if (access.hasReceiver()) { + deserializeExpression(access.receiver) + } else null + val value = deserializeExpression(proto.value) + + return IrSetFieldImpl(start, end, symbol, receiver, value, builtIns.unitType, null, superQualifier) + } + + private fun deserializeSetVariable(proto: KonanIr.IrSetVariable, start: Int, end: Int): IrSetVariable { + val symbol = deserializeIrSymbol(proto.symbol) as IrVariableSymbol + val value = deserializeExpression(proto.value) + return IrSetVariableImpl(start, end, builtIns.unitType, symbol, value, null) + } + + private fun deserializeSpreadElement(proto: KonanIr.IrSpreadElement): IrSpreadElement { + val expression = deserializeExpression(proto.expression) + return IrSpreadElementImpl(proto.coordinates.startOffset, proto.coordinates.endOffset, expression) + } + + private fun deserializeStringConcat( + proto: KonanIr.IrStringConcat, + start: Int, + end: Int, + type: IrType + ): IrStringConcatenation { + val argumentProtos = proto.argumentList + val arguments = mutableListOf() + + argumentProtos.forEach { + arguments.add(deserializeExpression(it)) + } + return IrStringConcatenationImpl(start, end, type, arguments) + } + + private fun deserializeThrow(proto: KonanIr.IrThrow, start: Int, end: Int, type: IrType): IrThrowImpl { + return IrThrowImpl(start, end, builtIns.nothingType, deserializeExpression(proto.value)) + } + + private fun deserializeTry(proto: KonanIr.IrTry, start: Int, end: Int, type: IrType): IrTryImpl { + val result = deserializeExpression(proto.result) + val catches = mutableListOf() + proto.catchList.forEach { + catches.add(deserializeStatement(it) as IrCatch) + } + val finallyExpression = + if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null + return IrTryImpl(start, end, type, result, catches, finallyExpression) + } + + private fun deserializeTypeOperator(operator: KonanIr.IrTypeOperator) = when (operator) { + KonanIr.IrTypeOperator.CAST + -> IrTypeOperator.CAST + KonanIr.IrTypeOperator.IMPLICIT_CAST + -> IrTypeOperator.IMPLICIT_CAST + KonanIr.IrTypeOperator.IMPLICIT_NOTNULL + -> IrTypeOperator.IMPLICIT_NOTNULL + KonanIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT + -> IrTypeOperator.IMPLICIT_COERCION_TO_UNIT + KonanIr.IrTypeOperator.IMPLICIT_INTEGER_COERCION + -> IrTypeOperator.IMPLICIT_INTEGER_COERCION + KonanIr.IrTypeOperator.SAFE_CAST + -> IrTypeOperator.SAFE_CAST + KonanIr.IrTypeOperator.INSTANCEOF + -> IrTypeOperator.INSTANCEOF + KonanIr.IrTypeOperator.NOT_INSTANCEOF + -> IrTypeOperator.NOT_INSTANCEOF + KonanIr.IrTypeOperator.SAM_CONVERSION + -> IrTypeOperator.SAM_CONVERSION + } + + private fun deserializeTypeOp(proto: KonanIr.IrTypeOp, start: Int, end: Int, type: IrType): IrTypeOperatorCall { + val operator = deserializeTypeOperator(proto.operator) + val operand = deserializeIrType(proto.operand)//.brokenIr + val argument = deserializeExpression(proto.argument) + return IrTypeOperatorCallImpl(start, end, type, operator, operand).apply { + this.argument = argument + this.typeOperandClassifier = operand.classifierOrFail + } + } + + private fun deserializeVararg(proto: KonanIr.IrVararg, start: Int, end: Int, type: IrType): IrVararg { + val elementType = deserializeIrType(proto.elementType) + + val elements = mutableListOf() + proto.elementList.forEach { + elements.add(deserializeVarargElement(it)) + } + return IrVarargImpl(start, end, type, elementType, elements) + } + + private fun deserializeVarargElement(element: KonanIr.IrVarargElement): IrVarargElement { + return when (element.varargElementCase) { + VarargElementCase.EXPRESSION + -> deserializeExpression(element.expression) + VarargElementCase.SPREAD_ELEMENT + -> deserializeSpreadElement(element.spreadElement) + else + -> TODO("Unexpected vararg element") + } + } + + private fun deserializeWhen(proto: KonanIr.IrWhen, start: Int, end: Int, type: IrType): IrWhen { + val branches = mutableListOf() + + proto.branchList.forEach { + branches.add(deserializeStatement(it) as IrBranch) + } + + // TODO: provide some origin! + return IrWhenImpl(start, end, type, null, branches) + } + + private val loopIndex = mutableMapOf() + + private fun deserializeLoop(proto: KonanIr.Loop, loop: IrLoopBase): IrLoopBase { + val loopId = proto.loopId + loopIndex.getOrPut(loopId) { loop } + + val label = if (proto.hasLabel()) proto.label else null + val body = if (proto.hasBody()) deserializeExpression(proto.body) else null + val condition = deserializeExpression(proto.condition) + + loop.label = label + loop.condition = condition + loop.body = body + + return loop + } + + private fun deserializeDoWhile(proto: KonanIr.IrDoWhile, start: Int, end: Int, type: IrType): IrDoWhileLoop { + // we create the loop before deserializing the body, so that + // IrBreak statements have something to put into 'loop' field. + val loop = IrDoWhileLoopImpl(start, end, type, null) + deserializeLoop(proto.loop, loop) + return loop + } + + private fun deserializeWhile(proto: KonanIr.IrWhile, start: Int, end: Int, type: IrType): IrWhileLoop { + // we create the loop before deserializing the body, so that + // IrBreak statements have something to put into 'loop' field. + val loop = IrWhileLoopImpl(start, end, type, null) + deserializeLoop(proto.loop, loop) + return loop + } + + private fun deserializeBreak(proto: KonanIr.IrBreak, start: Int, end: Int, type: IrType): IrBreak { + val label = if (proto.hasLabel()) proto.label else null + val loopId = proto.loopId + val loop = loopIndex[loopId]!! + val irBreak = IrBreakImpl(start, end, type, loop) + irBreak.label = label + + return irBreak + } + + private fun deserializeContinue(proto: KonanIr.IrContinue, start: Int, end: Int, type: IrType): IrContinue { + val label = if (proto.hasLabel()) proto.label else null + val loopId = proto.loopId + val loop = loopIndex[loopId]!! + val irContinue = IrContinueImpl(start, end, type, loop) + irContinue.label = label + + return irContinue + } + + private fun deserializeConst(proto: KonanIr.IrConst, start: Int, end: Int, type: IrType): IrExpression = + when (proto.valueCase) { + NULL + -> IrConstImpl.constNull(start, end, type) + BOOLEAN + -> IrConstImpl.boolean(start, end, type, proto.boolean) + BYTE + -> IrConstImpl.byte(start, end, type, proto.byte.toByte()) + CHAR + -> IrConstImpl.char(start, end, type, proto.char.toChar()) + SHORT + -> IrConstImpl.short(start, end, type, proto.short.toShort()) + INT + -> IrConstImpl.int(start, end, type, proto.int) + LONG + -> IrConstImpl.long(start, end, type, proto.long) + STRING + -> IrConstImpl.string(start, end, type, proto.string) + FLOAT + -> IrConstImpl.float(start, end, type, proto.float) + DOUBLE + -> IrConstImpl.double(start, end, type, proto.double) + VALUE_NOT_SET + -> error("Const deserialization error: ${proto.valueCase} ") + } + + private fun deserializeOperation(proto: KonanIr.IrOperation, start: Int, end: Int, type: IrType): IrExpression = + when (proto.operationCase) { + BLOCK + -> deserializeBlock(proto.block, start, end, type) + BREAK + -> deserializeBreak(proto.`break`, start, end, type) + CLASS_REFERENCE + -> deserializeClassReference(proto.classReference, start, end, type) + CALL + -> deserializeCall(proto.call, start, end, type) + COMPOSITE + -> deserializeComposite(proto.composite, start, end, type) + CONST + -> deserializeConst(proto.const, start, end, type) + CONTINUE + -> deserializeContinue(proto.`continue`, start, end, type) + DELEGATING_CONSTRUCTOR_CALL + -> deserializeDelegatingConstructorCall(proto.delegatingConstructorCall, start, end) + DO_WHILE + -> deserializeDoWhile(proto.doWhile, start, end, type) + ENUM_CONSTRUCTOR_CALL + -> deserializeEnumConstructorCall(proto.enumConstructorCall, start, end, type) + FUNCTION_REFERENCE + -> deserializeFunctionReference(proto.functionReference, start, end, type) + GET_ENUM_VALUE + -> deserializeGetEnumValue(proto.getEnumValue, start, end, type) + GET_CLASS + -> deserializeGetClass(proto.getClass, start, end, type) + GET_FIELD + -> deserializeGetField(proto.getField, start, end, type) + GET_OBJECT + -> deserializeGetObject(proto.getObject, start, end, type) + GET_VALUE + -> deserializeGetValue(proto.getValue, start, end, type) + INSTANCE_INITIALIZER_CALL + -> deserializeInstanceInitializerCall(proto.instanceInitializerCall, start, end) + PROPERTY_REFERENCE + -> deserializePropertyReference(proto.propertyReference, start, end, type) + RETURN + -> deserializeReturn(proto.`return`, start, end, type) + SET_FIELD + -> deserializeSetField(proto.setField, start, end) + SET_VARIABLE + -> deserializeSetVariable(proto.setVariable, start, end) + STRING_CONCAT + -> deserializeStringConcat(proto.stringConcat, start, end, type) + THROW + -> deserializeThrow(proto.`throw`, start, end, type) + TRY + -> deserializeTry(proto.`try`, start, end, type) + TYPE_OP + -> deserializeTypeOp(proto.typeOp, start, end, type) + VARARG + -> deserializeVararg(proto.vararg, start, end, type) + WHEN + -> deserializeWhen(proto.`when`, start, end, type) + WHILE + -> deserializeWhile(proto.`while`, start, end, type) + OPERATION_NOT_SET + -> error("Expression deserialization not implemented: ${proto.operationCase}") + } + + private fun deserializeExpression(proto: KonanIr.IrExpression): IrExpression { + val start = proto.coordinates.startOffset + val end = proto.coordinates.endOffset + val type = deserializeIrType(proto.type) + val operation = proto.operation + val expression = deserializeOperation(operation, start, end, type) + + logger.log { "### Deserialized expression: ${ir2string(expression)} ir_type=$type" } + return expression + } + + private fun deserializeIrTypeParameter( + proto: KonanIr.IrTypeParameter, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ): IrTypeParameter { + val symbol = deserializeIrSymbol(proto.symbol) as IrTypeParameterSymbol + val name = Name.identifier(proto.name) + val variance = deserializeIrTypeVariance(proto.variance) + + val parameter = symbolTable.declareGlobalTypeParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + symbol.descriptor, { symbol -> + IrTypeParameterImpl(start, end, origin, symbol, name, proto.index, proto.isReified, variance) + } + ) + + val superTypes = proto.superTypeList.map { deserializeIrType(it) } + parameter.superTypes.addAll(superTypes) + + return parameter + } + + private fun deserializeIrTypeParameterContainer( + proto: KonanIr.IrTypeParameterContainer, + parent: IrDeclarationParent + ): List { + return proto.typeParameterList.map { + deserializeDeclaration( + it, + parent + ) as IrTypeParameter + } // TODO: we need proper start, end and origin here? + } + + private fun deserializeClassKind(kind: KonanIr.ClassKind) = when (kind) { + KonanIr.ClassKind.CLASS -> ClassKind.CLASS + KonanIr.ClassKind.INTERFACE -> ClassKind.INTERFACE + KonanIr.ClassKind.ENUM_CLASS -> ClassKind.ENUM_CLASS + KonanIr.ClassKind.ENUM_ENTRY -> ClassKind.ENUM_ENTRY + KonanIr.ClassKind.ANNOTATION_CLASS -> ClassKind.ANNOTATION_CLASS + KonanIr.ClassKind.OBJECT -> ClassKind.OBJECT + } + + private fun deserializeIrValueParameter( + proto: KonanIr.IrValueParameter, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ): IrValueParameter { + + val varargElementType = if (proto.hasVarargElementType()) deserializeIrType(proto.varargElementType) else null + val parameter = + IrValueParameterImpl( + start, end, origin, + deserializeIrSymbol(proto.symbol) as IrValueParameterSymbol, + Name.identifier(proto.name), + proto.index, + deserializeIrType(proto.type), + varargElementType, + proto.isCrossinline, + proto.isNoinline + ).apply { + defaultValue = if (proto.hasDefaultValue()) { + val expression = deserializeExpression(proto.defaultValue) + IrExpressionBodyImpl(expression) + } else null + } + + return parameter + } + + private fun deserializeIrClass(proto: KonanIr.IrClass, start: Int, end: Int, origin: IrDeclarationOrigin): IrClass { + + val symbol = deserializeIrSymbol(proto.symbol) as IrClassSymbol + + val clazz = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + symbol.descriptor, { symbol -> + IrClassImpl( + start, end, origin, + symbol, + Name.identifier(proto.name), + deserializeClassKind(proto.kind), + deserializeVisibility(proto.visibility), + deserializeModality(proto.modality), + proto.isCompanion, + proto.isInner, + proto.isData, + proto.isExternal, + proto.isInline + ) + }) + + proto.declarationContainer.declarationList.forEach { + val member = deserializeDeclaration(it, clazz) + clazz.addMember(member) + member.parent = clazz + } + + clazz.thisReceiver = deserializeDeclaration(proto.thisReceiver, clazz) as IrValueParameter + + val typeParameters = deserializeIrTypeParameterContainer(proto.typeParameters, clazz) + clazz.typeParameters.addAll(typeParameters) + + val superTypes = proto.superTypeList.map { deserializeIrType(it) } + clazz.superTypes.addAll(superTypes) + + return clazz + } + + private fun deserializeIrFunctionBase( + base: KonanIr.IrFunctionBase, + function: IrFunctionBase, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ) { + + function.body = if (base.hasBody()) deserializeStatement(base.body) as IrBody else null + + val valueParameters = base.valueParameterList.map { deserializeDeclaration(it, function) as IrValueParameter } + function.valueParameters.addAll(valueParameters) + function.dispatchReceiverParameter = if (base.hasDispatchReceiver()) deserializeDeclaration( + base.dispatchReceiver, + function + ) as IrValueParameter else null + function.extensionReceiverParameter = if (base.hasExtensionReceiver()) deserializeDeclaration( + base.extensionReceiver, + function + ) as IrValueParameter else null + val typeParameters = deserializeIrTypeParameterContainer(base.typeParameters, function) // TODO + function.typeParameters.addAll(typeParameters) + } + + private fun deserializeIrFunction( + proto: KonanIr.IrFunction, + start: Int, end: Int, origin: IrDeclarationOrigin, correspondingProperty: IrProperty? = null + ): IrSimpleFunction { + + logger.log { "### deserializing IrFunction ${proto.base.name}" } + val symbol = deserializeIrSymbol(proto.symbol) as IrSimpleFunctionSymbol + + val function = symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + symbol.descriptor, { + IrFunctionImpl( + start, end, origin, it, + Name.identifier(proto.base.name), + deserializeVisibility(proto.base.visibility), + deserializeModality(proto.modality), + deserializeIrType(proto.base.returnType), + proto.base.isInline, + proto.base.isExternal, + proto.isTailrec, + proto.isSuspend + ) + }) + + deserializeIrFunctionBase(proto.base, function as IrFunctionBase, start, end, origin) + val overridden = proto.overriddenList.map { deserializeIrSymbol(it) as IrSimpleFunctionSymbol } + function.overriddenSymbols.addAll(overridden) + + function.correspondingProperty = correspondingProperty + + return function + } + + private fun deserializeIrVariable( + proto: KonanIr.IrVariable, + start: Int, end: Int, origin: IrDeclarationOrigin + ): IrVariable { + + val initializer = if (proto.hasInitializer()) { + deserializeExpression(proto.initializer) + } else null + + val symbol = deserializeIrSymbol(proto.symbol) as IrVariableSymbol + val type = deserializeIrType(proto.type) + + val variable = IrVariableImpl( + start, + end, + origin, + symbol, + Name.identifier(proto.name), + type, + proto.isVar, + proto.isConst, + proto.isLateinit + ) + variable.initializer = initializer + return variable + } + + private fun deserializeIrEnumEntry( + proto: KonanIr.IrEnumEntry, + start: Int, end: Int, origin: IrDeclarationOrigin + ): IrEnumEntry { + val symbol = deserializeIrSymbol(proto.symbol) as IrEnumEntrySymbol + + val enumEntry = symbolTable.declareEnumEntry( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + irrelevantOrigin, + symbol.descriptor + ) { + IrEnumEntryImpl(start, end, origin, it, Name.identifier(proto.name)) + } + + if (proto.hasCorrespondingClass()) { + enumEntry.correspondingClass = deserializeDeclaration(proto.correspondingClass, null) as IrClass + } + if (proto.hasInitializer()) { + enumEntry.initializerExpression = deserializeExpression(proto.initializer) + } + + return enumEntry + } + + private fun deserializeIrAnonymousInit( + proto: KonanIr.IrAnonymousInit, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ): IrAnonymousInitializer { + val symbol = deserializeIrSymbol(proto.symbol) as IrAnonymousInitializerSymbol + val initializer = IrAnonymousInitializerImpl(start, end, origin, symbol) + initializer.body = deserializeBlockBody(proto.body.blockBody, start, end) + return initializer + } + + private fun deserializeVisibility(value: String): Visibility { // TODO: switch to enum + return when (value) { + "public" -> Visibilities.PUBLIC + "private" -> Visibilities.PRIVATE + "private_to_this" -> Visibilities.PRIVATE_TO_THIS + "protected" -> Visibilities.PROTECTED + "internal" -> Visibilities.INTERNAL + "invisible_fake" -> Visibilities.INVISIBLE_FAKE // TODO: eventually we should not serialize fake overrides, so this will be gone. + "local" -> Visibilities.LOCAL + else -> error("Unexpected visibility value: $value") + } + } + + private fun deserializeIrConstructor( + proto: KonanIr.IrConstructor, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ): IrConstructor { + val symbol = deserializeIrSymbol(proto.symbol) as IrConstructorSymbol + + val constructor = symbolTable.declareConstructor(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + symbol.descriptor, { + IrConstructorImpl( + start, end, origin, + it, + Name.identifier(proto.base.name), + deserializeVisibility(proto.base.visibility), + deserializeIrType(proto.base.returnType), + proto.base.isInline, + proto.base.isExternal, + proto.isPrimary + ) + + }) + + deserializeIrFunctionBase(proto.base, constructor as IrFunctionBase, start, end, origin) + return constructor + } + + private fun deserializeIrField(proto: KonanIr.IrField, start: Int, end: Int, origin: IrDeclarationOrigin): IrField { + + val symbol = deserializeIrSymbol(proto.symbol) as IrFieldSymbol + val type = deserializeIrType(proto.type) + val field = symbolTable.declareField(UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + irrelevantOrigin, + symbol.descriptor, + type, + { IrFieldImpl( + start, end, origin, + it, + Name.identifier(proto.name), + type, + deserializeVisibility(proto.visibility), + proto.isFinal, + proto.isExternal, + proto.isStatic + ) + } + ) + + val initializer = if (proto.hasInitializer()) deserializeExpression(proto.initializer) else null + field.initializer = initializer?.let { IrExpressionBodyImpl(it) } + + return field + } + + private fun deserializeModality(modality: KonanIr.ModalityKind) = when (modality) { + KonanIr.ModalityKind.OPEN_MODALITY -> Modality.OPEN + KonanIr.ModalityKind.SEALED_MODALITY -> Modality.SEALED + KonanIr.ModalityKind.FINAL_MODALITY -> Modality.FINAL + KonanIr.ModalityKind.ABSTRACT_MODALITY -> Modality.ABSTRACT + } + + private fun deserializeIrProperty( + proto: KonanIr.IrProperty, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ): IrProperty { + + val backingField = if (proto.hasBackingField()) { + deserializeIrField(proto.backingField, start, end, origin) + } else null + + val descriptor = + if (proto.hasDescriptor()) deserializeDescriptorReference(proto.descriptor) as PropertyDescriptor else null + ?: WrappedPropertyDescriptor() + + val property = IrPropertyImpl( + start, end, origin, + descriptor, + Name.identifier(proto.name), + deserializeVisibility(proto.visibility), + deserializeModality(proto.modality), + proto.isVar, + proto.isConst, + proto.isLateinit, + proto.isDelegated, + proto.isExternal + ) + + symbolTable.referenceProperty(descriptor, { property }) +/* + backingField?.descriptor?.let { + symbolTable.declareField(UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + irrelevantOrigin, + it, + builtIns.unitType, + { symbol -> backingField }) + } +*/ + property.backingField = backingField + backingField?.let { it.correspondingProperty = property } + + property.getter = + if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, property) else null + property.setter = + if (proto.hasSetter()) deserializeIrFunction(proto.setter, start, end, origin, property) else null + + property.getter?.let { + val descriptor = it.descriptor + if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it) + symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + descriptor, { symbol -> it }) + + } + property.setter?.let { + val descriptor = it.descriptor + if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it) + symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, + descriptor, { symbol -> it }) + } + + return property + } + + private fun deserializeIrTypeAlias( + proto: KonanIr.IrTypeAlias, + start: Int, + end: Int, + origin: IrDeclarationOrigin + ): IrDeclaration { + return IrErrorDeclarationImpl(start, end, WrappedClassDescriptor()) + } + + private val allKnownOrigins = + IrDeclarationOrigin::class.nestedClasses.toList() + DeclarationFactory.FIELD_FOR_OUTER_THIS::class + val originIndex = allKnownOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name } + val irrelevantOrigin = object : IrDeclarationOriginImpl("irrelevant") {} + + protected fun deserializeDeclaration(proto: KonanIr.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration { + + val start = proto.coordinates.startOffset + val end = proto.coordinates.endOffset + val origin = originIndex[proto.origin.name]!! + + val declarator = proto.declarator + + val declaration: IrDeclaration = when (declarator.declaratorCase) { + IR_ANONYMOUS_INIT + -> deserializeIrAnonymousInit(declarator.irAnonymousInit, start, end, origin) + IR_CONSTRUCTOR + -> deserializeIrConstructor(declarator.irConstructor, start, end, origin) + IR_FIELD + -> deserializeIrField(declarator.irField, start, end, origin) + IR_CLASS + -> deserializeIrClass(declarator.irClass, start, end, origin) + IR_FUNCTION + -> deserializeIrFunction(declarator.irFunction, start, end, origin) + IR_PROPERTY + -> deserializeIrProperty(declarator.irProperty, start, end, origin) + IR_TYPE_ALIAS + -> deserializeIrTypeAlias(declarator.irTypeAlias, start, end, origin) + IR_TYPE_PARAMETER + -> deserializeIrTypeParameter(declarator.irTypeParameter, start, end, origin) + IR_VARIABLE + -> deserializeIrVariable(declarator.irVariable, start, end, origin) + IR_VALUE_PARAMETER + -> deserializeIrValueParameter(declarator.irValueParameter, start, end, origin) + IR_ENUM_ENTRY + -> deserializeIrEnumEntry(declarator.irEnumEntry, start, end, origin) + DECLARATOR_NOT_SET + -> error("Declaration deserialization not implemented: ${declarator.declaratorCase}") + } + + val annotations = deserializeAnnotations(proto.annotations) + declaration.annotations.addAll(annotations) + + parent?.let { declaration.parent = it } + + val sourceFileName = proto.fileName + + val descriptor = declaration.descriptor + + if (descriptor is WrappedDeclarationDescriptor<*>) { + when (declaration) { + is IrValueParameter -> + if (descriptor is WrappedValueParameterDescriptor) descriptor.bind(declaration) + else (descriptor as WrappedReceiverParameterDescriptor).bind(declaration) + is IrVariable -> (descriptor as WrappedVariableDescriptor).bind(declaration) + is IrTypeParameter -> (descriptor as WrappedTypeParameterDescriptor).bind(declaration) + is IrAnonymousInitializer -> (descriptor as WrappedClassDescriptor).bind(parent!! as IrClass) + is IrClass -> (descriptor as WrappedClassDescriptor).bind(declaration) + is IrConstructor -> (descriptor as WrappedClassConstructorDescriptor).bind(declaration) + is IrField -> (descriptor as WrappedFieldDescriptor).bind(declaration) + is IrProperty -> (descriptor as WrappedPropertyDescriptor).bind(declaration) + is IrEnumEntry -> (descriptor as WrappedEnumEntryDescriptor).bind(declaration) + is IrSimpleFunction -> (descriptor as WrappedSimpleFunctionDescriptor).bind(declaration) + } + } + logger.log { "### Deserialized declaration: ${descriptor} -> ${ir2string(declaration)}" } + + return declaration + } +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrModuleSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrModuleSerializer.kt new file mode 100644 index 00000000000..f13c4532755 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrModuleSerializer.kt @@ -0,0 +1,1074 @@ +/* + * 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.ir.ir2string +import org.jetbrains.kotlin.backend.konan.descriptors.findTopLevelDeclaration +import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember +import org.jetbrains.kotlin.backend.konan.descriptors.isSerializableExpectClass +import org.jetbrains.kotlin.backend.konan.library.SerializedIr +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.ClassKind.* +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.SourceManager +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionBase +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrBinaryPrimitiveImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrNullaryPrimitiveImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrUnaryPrimitiveImpl +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl +import org.jetbrains.kotlin.metadata.KonanIr +import org.jetbrains.kotlin.types.SimpleType +import org.jetbrains.kotlin.types.StarProjectionImpl +import org.jetbrains.kotlin.types.Variance + +internal class IrModuleSerializer( + val logger: LoggingContext, + val declarationTable: DeclarationTable +) { + + private val loopIndex = mutableMapOf() + private var currentLoopIndex = 0 + val descriptorReferenceSerializer = DescriptorReferenceSerializer(declarationTable) + + // The same symbol can be used multiple times in a module + // so use this index to store symbol data only once. + val protoSymbolMap = mutableMapOf() + val protoSymbolArray = arrayListOf() + + // The same type can be used multiple times in a module + // so use this index to store type data only once. + val protoTypeMap = mutableMapOf() + val protoTypeArray = arrayListOf() + + /* ------- IrSymbols -------------------------------------------------------- */ + + fun protoSymbolKind(symbol: IrSymbol): KonanIr.IrSymbolKind = when (symbol) { + is IrAnonymousInitializerSymbol -> + KonanIr.IrSymbolKind.ANONYMOUS_INIT_SYMBOL + is IrClassSymbol -> + KonanIr.IrSymbolKind.CLASS_SYMBOL + is IrConstructorSymbol -> + KonanIr.IrSymbolKind.CONSTRUCTOR_SYMBOL + is IrTypeParameterSymbol -> + KonanIr.IrSymbolKind.TYPE_PARAMETER_SYMBOL + is IrEnumEntrySymbol -> + KonanIr.IrSymbolKind.ENUM_ENTRY_SYMBOL + is IrVariableSymbol -> + KonanIr.IrSymbolKind.VARIABLE_SYMBOL + is IrValueParameterSymbol -> + if (symbol.descriptor is ReceiverParameterDescriptor) // TODO: we use descriptor here. + KonanIr.IrSymbolKind.RECEIVER_PARAMETER_SYMBOL + else + KonanIr.IrSymbolKind.VALUE_PARAMETER_SYMBOL + is IrSimpleFunctionSymbol -> + KonanIr.IrSymbolKind.FUNCTION_SYMBOL + is IrReturnableBlockSymbol -> + KonanIr.IrSymbolKind.RETURNABLE_BLOCK_SYMBOL + is IrFieldSymbol -> + if (symbol.owner.correspondingProperty == null) + KonanIr.IrSymbolKind.STANDALONE_FIELD_SYMBOL + else + KonanIr.IrSymbolKind.FIELD_SYMBOL + else -> + TODO("Unexpected symbol kind: $symbol") + } + + fun serializeIrSymbolData(symbol: IrSymbol): KonanIr.IrSymbolData { + + val declaration = symbol.owner as? IrDeclaration ?: error("Expected IrDeclaration: ${symbol.owner}") + + val proto = KonanIr.IrSymbolData.newBuilder() + proto.kind = protoSymbolKind(symbol) + + val uniqId = + declarationTable.uniqIdByDeclaration(declaration) + proto.setUniqId(protoUniqId(uniqId)) + + val topLevelUniqId = + declarationTable.uniqIdByDeclaration((declaration).findTopLevelDeclaration()) + proto.setTopLevelUniqId(protoUniqId(topLevelUniqId)) + + descriptorReferenceSerializer.serializeDescriptorReference(declaration) ?. let { + proto.setDescriptorReference(it) + } + + return proto.build() + } + + fun serializeIrSymbol(symbol: IrSymbol): KonanIr.IrSymbol { + val proto = KonanIr.IrSymbol.newBuilder() + proto.index = protoSymbolMap.getOrPut(symbol) { + protoSymbolArray.add(serializeIrSymbolData(symbol)) + protoSymbolArray.size - 1 + } + return proto.build() + } + + /* ------- IrTypes ---------------------------------------------------------- */ + + // TODO: we, probably, need a type table. + + private fun serializeTypeArguments(call: IrMemberAccessExpression): KonanIr.TypeArguments { + val proto = KonanIr.TypeArguments.newBuilder() + for (i in 0 until call.typeArgumentsCount) { + proto.addTypeArgument(serializeIrType(call.getTypeArgument(i)!!)) + } + return proto.build() + } + + fun serializeIrTypeVariance(variance: Variance) = when (variance) { + Variance.IN_VARIANCE -> KonanIr.IrTypeVariance.IN + Variance.OUT_VARIANCE -> KonanIr.IrTypeVariance.OUT + Variance.INVARIANT -> KonanIr.IrTypeVariance.INV + } + + fun serializeAnnotations(annotations: List): KonanIr.Annotations { + val proto = KonanIr.Annotations.newBuilder() + annotations.forEach { + proto.addAnnotation(serializeCall(it)) + } + return proto.build() + } + + fun serializeIrTypeProjection(argument: IrTypeProjection) = KonanIr.IrTypeProjection.newBuilder() + .setVariance(serializeIrTypeVariance(argument.variance)) + .setType(serializeIrType(argument.type)) + .build() + + fun serializeTypeArgument(argument: IrTypeArgument): KonanIr.IrTypeArgument { + val proto = KonanIr.IrTypeArgument.newBuilder() + when (argument) { + is IrStarProjection -> + proto.star = KonanIr.IrStarProjection.newBuilder() + .build() // TODO: Do we need a singletone here? Or just an enum? + is IrTypeProjection -> + proto.type = serializeIrTypeProjection(argument) + else -> TODO("Unexpected type argument kind: $argument") + } + return proto.build() + } + + fun serializeSimpleType(type: IrSimpleType): KonanIr.IrSimpleType { + val proto = KonanIr.IrSimpleType.newBuilder() + .setAnnotations(serializeAnnotations(type.annotations)) + .setClassifier(serializeIrSymbol(type.classifier)) + .setHasQuestionMark(type.hasQuestionMark) + type.arguments.forEach { + proto.addArgument(serializeTypeArgument(it)) + } + return proto.build() + } + + fun serializeDynamicType(type: IrDynamicType) = KonanIr.IrDynamicType.newBuilder() + .setAnnotations(serializeAnnotations(type.annotations)) + .build() + + fun serializeErrorType(type: IrErrorType) = KonanIr.IrErrorType.newBuilder() + .setAnnotations(serializeAnnotations(type.annotations)) + .build() + + private fun serializeIrTypeData(type: IrType): KonanIr.IrType { + logger.log { "### serializing IrType: " + type } + val proto = KonanIr.IrType.newBuilder() + when (type) { + is IrSimpleType -> + proto.simple = serializeSimpleType(type) + is IrDynamicType -> + proto.dynamic = serializeDynamicType(type) + is IrErrorType -> + proto.error = serializeErrorType(type) + else -> TODO("IrType serialization not implemented yet: $type.") + } + return proto.build() + } + + enum class IrTypeKind { + SIMPLE, + DYNAMIC, + ERROR + } + + enum class IrTypeArgumentKind { + STAR, + PROJECTION + } + + // This is just IrType repacked as a data class, good to address a hash map. + data class IrTypeKey ( + val kind: IrTypeKind, + val classifier: IrClassifierSymbol?, + val hasQuestionMark: Boolean?, + val arguments: List?, + val annotations: List + ) + + data class IrTypeArgumentKey ( + val kind: IrTypeArgumentKind, + val variance: Variance?, + val type: IrTypeKey? + ) + + val IrType.toIrTypeKey: IrTypeKey get() = IrTypeKey( + kind = when (this) { + is IrSimpleType -> IrTypeKind.SIMPLE + is IrDynamicType -> IrTypeKind.DYNAMIC + is IrErrorType -> IrTypeKind.ERROR + else -> error("Unexpected IrType kind: $this") + }, + classifier = this.classifierOrNull, + hasQuestionMark = (this as? IrSimpleType)?.hasQuestionMark, + arguments = (this as? IrSimpleType)?.arguments?.map { it.toIrTypeArgumentKey }, + annotations = this.annotations + ) + + val IrTypeArgument.toIrTypeArgumentKey: IrTypeArgumentKey get() = IrTypeArgumentKey( + kind = when (this) { + is IrStarProjection -> IrTypeArgumentKind.STAR + is IrTypeProjection -> IrTypeArgumentKind.PROJECTION + else -> error("Unexpected type argument kind: $this") + }, + variance = (this as? IrTypeProjection)?.variance, + type = (this as? IrTypeProjection)?.type?.toIrTypeKey + ) + + fun serializeIrType(type: IrType): KonanIr.IrTypeIndex { + val proto = KonanIr.IrTypeIndex.newBuilder() + val key = type.toIrTypeKey + proto.index = protoTypeMap.getOrPut(key) { + // println("new type: $type ${(type as? IrSimpleType)?.classifier?.descriptor}${if((type as? IrSimpleType)?.hasQuestionMark ?: false) "?" else ""}") + // println("new key = $key") + protoTypeArray.add(serializeIrTypeData(type)) + protoTypeArray.size - 1 + } + return proto.build() + } + + /* -------------------------------------------------------------------------- */ + + private fun serializeBlockBody(expression: IrBlockBody): KonanIr.IrBlockBody { + val proto = KonanIr.IrBlockBody.newBuilder() + expression.statements.forEach { + proto.addStatement(serializeStatement(it)) + } + return proto.build() + } + + private fun serializeBranch(branch: IrBranch): KonanIr.IrBranch { + val proto = KonanIr.IrBranch.newBuilder() + + proto.condition = serializeExpression(branch.condition) + proto.result = serializeExpression(branch.result) + + return proto.build() + } + + private fun serializeBlock(block: IrBlock): KonanIr.IrBlock { + val isLambdaOrigin = + block.origin == IrStatementOrigin.LAMBDA || + block.origin == IrStatementOrigin.ANONYMOUS_FUNCTION + val proto = KonanIr.IrBlock.newBuilder() + .setIsLambdaOrigin(isLambdaOrigin) + block.statements.forEach { + proto.addStatement(serializeStatement(it)) + } + return proto.build() + } + + private fun serializeComposite(composite: IrComposite): KonanIr.IrComposite { + val proto = KonanIr.IrComposite.newBuilder() + composite.statements.forEach { + proto.addStatement(serializeStatement(it)) + } + return proto.build() + } + + private fun serializeCatch(catch: IrCatch): KonanIr.IrCatch { + val proto = KonanIr.IrCatch.newBuilder() + .setCatchParameter(serializeDeclaration(catch.catchParameter)) + .setResult(serializeExpression(catch.result)) + return proto.build() + } + + private fun serializeStringConcat(expression: IrStringConcatenation): KonanIr.IrStringConcat { + val proto = KonanIr.IrStringConcat.newBuilder() + expression.arguments.forEach { + proto.addArgument(serializeExpression(it)) + } + return proto.build() + } + + private fun irCallToPrimitiveKind(call: IrCall): KonanIr.IrCall.Primitive = when (call) { + is IrNullaryPrimitiveImpl + -> KonanIr.IrCall.Primitive.NULLARY + is IrUnaryPrimitiveImpl + -> KonanIr.IrCall.Primitive.UNARY + is IrBinaryPrimitiveImpl + -> KonanIr.IrCall.Primitive.BINARY + else + -> KonanIr.IrCall.Primitive.NOT_PRIMITIVE + } + + private fun serializeMemberAccessCommon(call: IrMemberAccessExpression): KonanIr.MemberAccessCommon { + val proto = KonanIr.MemberAccessCommon.newBuilder() + if (call.extensionReceiver != null) { + proto.extensionReceiver = serializeExpression(call.extensionReceiver!!) + } + + if (call.dispatchReceiver != null) { + proto.dispatchReceiver = serializeExpression(call.dispatchReceiver!!) + } + proto.typeArguments = serializeTypeArguments(call) + + for (index in 0..call.valueArgumentsCount - 1) { + val actual = call.getValueArgument(index) + val argOrNull = KonanIr.NullableIrExpression.newBuilder() + if (actual == null) { + // Am I observing an IR generation regression? + // I see a lack of arg for an empty vararg, + // rather than an empty vararg node. + + // TODO: how do we assert that without descriptora? + //assert(it.varargElementType != null || it.hasDefaultValue()) + } else { + argOrNull.expression = serializeExpression(actual) + } + proto.addValueArgument(argOrNull) + } + return proto.build() + } + + private fun serializeCall(call: IrCall): KonanIr.IrCall { + val proto = KonanIr.IrCall.newBuilder() + + proto.kind = irCallToPrimitiveKind(call) + proto.symbol = serializeIrSymbol(call.symbol) + + call.superQualifierSymbol?.let { + proto.`super` = serializeIrSymbol(it) + } + proto.memberAccess = serializeMemberAccessCommon(call) + return proto.build() + } + + private fun serializeFunctionReference(callable: IrFunctionReference): KonanIr.IrFunctionReference { + val proto = KonanIr.IrFunctionReference.newBuilder() + .setSymbol(serializeIrSymbol(callable.symbol)) + .setMemberAccess(serializeMemberAccessCommon(callable)) + callable.origin?.let { proto.origin = (it as IrStatementOriginImpl).debugName } + return proto.build() + } + + + private fun serializePropertyReference(callable: IrPropertyReference): KonanIr.IrPropertyReference { + val proto = KonanIr.IrPropertyReference.newBuilder() + .setMemberAccess(serializeMemberAccessCommon(callable)) + callable.field?.let { proto.field = serializeIrSymbol(it) } + callable.getter?.let { proto.getter = serializeIrSymbol(it) } + callable.setter?.let { proto.setter = serializeIrSymbol(it) } + callable.origin?.let { proto.origin = (it as IrStatementOriginImpl).debugName } + return proto.build() + } + + private fun serializeClassReference(expression: IrClassReference): KonanIr.IrClassReference { + val proto = KonanIr.IrClassReference.newBuilder() + .setClassSymbol(serializeIrSymbol(expression.symbol)) + .setClassType(serializeIrType(expression.classType)) + return proto.build() + } + + private fun serializeConst(value: IrConst<*>): KonanIr.IrConst { + val proto = KonanIr.IrConst.newBuilder() + when (value.kind) { + IrConstKind.Null -> proto.`null` = true + IrConstKind.Boolean -> proto.boolean = value.value as Boolean + IrConstKind.Byte -> proto.byte = (value.value as Byte).toInt() + IrConstKind.Char -> proto.char = (value.value as Char).toInt() + IrConstKind.Short -> proto.short = (value.value as Short).toInt() + IrConstKind.Int -> proto.int = value.value as Int + IrConstKind.Long -> proto.long = value.value as Long + IrConstKind.String -> proto.string = value.value as String + IrConstKind.Float -> proto.float = value.value as Float + IrConstKind.Double -> proto.double = value.value as Double + } + return proto.build() + } + + private fun serializeDelegatingConstructorCall(call: IrDelegatingConstructorCall): KonanIr.IrDelegatingConstructorCall { + val proto = KonanIr.IrDelegatingConstructorCall.newBuilder() + .setSymbol(serializeIrSymbol(call.symbol)) + .setMemberAccess(serializeMemberAccessCommon(call)) + return proto.build() + } + + private fun serializeDoWhile(expression: IrDoWhileLoop): KonanIr.IrDoWhile { + val proto = KonanIr.IrDoWhile.newBuilder() + .setLoop(serializeLoop(expression)) + + return proto.build() + } + + fun serializeEnumConstructorCall(call: IrEnumConstructorCall): KonanIr.IrEnumConstructorCall { + val proto = KonanIr.IrEnumConstructorCall.newBuilder() + .setSymbol(serializeIrSymbol(call.symbol)) + .setMemberAccess(serializeMemberAccessCommon(call)) + return proto.build() + } + + private fun serializeGetClass(expression: IrGetClass): KonanIr.IrGetClass { + val proto = KonanIr.IrGetClass.newBuilder() + .setArgument(serializeExpression(expression.argument)) + return proto.build() + } + + private fun serializeGetEnumValue(expression: IrGetEnumValue): KonanIr.IrGetEnumValue { + val proto = KonanIr.IrGetEnumValue.newBuilder() + .setSymbol(serializeIrSymbol(expression.symbol)) + return proto.build() + } + + private fun serializeFieldAccessCommon(expression: IrFieldAccessExpression): KonanIr.FieldAccessCommon { + val proto = KonanIr.FieldAccessCommon.newBuilder() + .setSymbol(serializeIrSymbol(expression.symbol)) + expression.superQualifierSymbol?.let { proto.`super` = serializeIrSymbol(it) } + expression.receiver?.let { proto.receiver = serializeExpression(it) } + return proto.build() + } + + private fun serializeGetField(expression: IrGetField): KonanIr.IrGetField { + val proto = KonanIr.IrGetField.newBuilder() + .setFieldAccess(serializeFieldAccessCommon(expression)) + return proto.build() + } + + private fun serializeGetValue(expression: IrGetValue): KonanIr.IrGetValue { + val proto = KonanIr.IrGetValue.newBuilder() + .setSymbol(serializeIrSymbol(expression.symbol)) + return proto.build() + } + + private fun serializeGetObject(expression: IrGetObjectValue): KonanIr.IrGetObject { + val proto = KonanIr.IrGetObject.newBuilder() + .setSymbol(serializeIrSymbol(expression.symbol)) + return proto.build() + } + + private fun serializeInstanceInitializerCall(call: IrInstanceInitializerCall): KonanIr.IrInstanceInitializerCall { + val proto = KonanIr.IrInstanceInitializerCall.newBuilder() + + proto.symbol = serializeIrSymbol(call.classSymbol) + + return proto.build() + } + + private fun serializeReturn(expression: IrReturn): KonanIr.IrReturn { + val proto = KonanIr.IrReturn.newBuilder() + .setReturnTarget(serializeIrSymbol(expression.returnTargetSymbol)) + .setValue(serializeExpression(expression.value)) + return proto.build() + } + + private fun serializeSetField(expression: IrSetField): KonanIr.IrSetField { + val proto = KonanIr.IrSetField.newBuilder() + .setFieldAccess(serializeFieldAccessCommon(expression)) + .setValue(serializeExpression(expression.value)) + return proto.build() + } + + private fun serializeSetVariable(expression: IrSetVariable): KonanIr.IrSetVariable { + val proto = KonanIr.IrSetVariable.newBuilder() + .setSymbol(serializeIrSymbol(expression.symbol)) + .setValue(serializeExpression(expression.value)) + return proto.build() + } + + private fun serializeSpreadElement(element: IrSpreadElement): KonanIr.IrSpreadElement { + val coordinates = serializeCoordinates(element.startOffset, element.endOffset) + return KonanIr.IrSpreadElement.newBuilder() + .setExpression(serializeExpression(element.expression)) + .setCoordinates(coordinates) + .build() + } + + private fun serializeSyntheticBody(expression: IrSyntheticBody) = KonanIr.IrSyntheticBody.newBuilder() + .setKind( + when (expression.kind) { + IrSyntheticBodyKind.ENUM_VALUES -> KonanIr.IrSyntheticBodyKind.ENUM_VALUES + IrSyntheticBodyKind.ENUM_VALUEOF -> KonanIr.IrSyntheticBodyKind.ENUM_VALUEOF + } + ) + .build() + + private fun serializeThrow(expression: IrThrow): KonanIr.IrThrow { + val proto = KonanIr.IrThrow.newBuilder() + .setValue(serializeExpression(expression.value)) + return proto.build() + } + + private fun serializeTry(expression: IrTry): KonanIr.IrTry { + val proto = KonanIr.IrTry.newBuilder() + .setResult(serializeExpression(expression.tryResult)) + val catchList = expression.catches + catchList.forEach { + proto.addCatch(serializeStatement(it)) + } + val finallyExpression = expression.finallyExpression + if (finallyExpression != null) { + proto.finally = serializeExpression(finallyExpression) + } + return proto.build() + } + + private fun serializeTypeOperator(operator: IrTypeOperator): KonanIr.IrTypeOperator = when (operator) { + IrTypeOperator.CAST + -> KonanIr.IrTypeOperator.CAST + IrTypeOperator.IMPLICIT_CAST + -> KonanIr.IrTypeOperator.IMPLICIT_CAST + IrTypeOperator.IMPLICIT_NOTNULL + -> KonanIr.IrTypeOperator.IMPLICIT_NOTNULL + IrTypeOperator.IMPLICIT_COERCION_TO_UNIT + -> KonanIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT + IrTypeOperator.IMPLICIT_INTEGER_COERCION + -> KonanIr.IrTypeOperator.IMPLICIT_INTEGER_COERCION + IrTypeOperator.SAFE_CAST + -> KonanIr.IrTypeOperator.SAFE_CAST + IrTypeOperator.INSTANCEOF + -> KonanIr.IrTypeOperator.INSTANCEOF + IrTypeOperator.NOT_INSTANCEOF + -> KonanIr.IrTypeOperator.NOT_INSTANCEOF + IrTypeOperator.SAM_CONVERSION + -> KonanIr.IrTypeOperator.SAM_CONVERSION + } + + private fun serializeTypeOp(expression: IrTypeOperatorCall): KonanIr.IrTypeOp { + val proto = KonanIr.IrTypeOp.newBuilder() + .setOperator(serializeTypeOperator(expression.operator)) + .setOperand(serializeIrType(expression.typeOperand)) + .setArgument(serializeExpression(expression.argument)) + return proto.build() + + } + + private fun serializeVararg(expression: IrVararg): KonanIr.IrVararg { + val proto = KonanIr.IrVararg.newBuilder() + .setElementType(serializeIrType(expression.varargElementType)) + expression.elements.forEach { + proto.addElement(serializeVarargElement(it)) + } + return proto.build() + } + + private fun serializeVarargElement(element: IrVarargElement): KonanIr.IrVarargElement { + val proto = KonanIr.IrVarargElement.newBuilder() + when (element) { + is IrExpression + -> proto.expression = serializeExpression(element) + is IrSpreadElement + -> proto.spreadElement = serializeSpreadElement(element) + else -> error("Unknown vararg element kind") + } + return proto.build() + } + + private fun serializeWhen(expression: IrWhen): KonanIr.IrWhen { + val proto = KonanIr.IrWhen.newBuilder() + + val branches = expression.branches + branches.forEach { + proto.addBranch(serializeStatement(it)) + } + + return proto.build() + } + + private fun serializeLoop(expression: IrLoop): KonanIr.Loop { + val proto = KonanIr.Loop.newBuilder() + .setCondition(serializeExpression(expression.condition)) + val label = expression.label + if (label != null) { + proto.label = label + } + + proto.loopId = currentLoopIndex + loopIndex[expression] = currentLoopIndex++ + + val body = expression.body + if (body != null) { + proto.body = serializeExpression(body) + } + + return proto.build() + } + + private fun serializeWhile(expression: IrWhileLoop): KonanIr.IrWhile { + val proto = KonanIr.IrWhile.newBuilder() + .setLoop(serializeLoop(expression)) + + return proto.build() + } + + private fun serializeBreak(expression: IrBreak): KonanIr.IrBreak { + val proto = KonanIr.IrBreak.newBuilder() + val label = expression.label + if (label != null) { + proto.label = label + } + val loopId = loopIndex[expression.loop]!! + proto.loopId = loopId + + return proto.build() + } + + private fun serializeContinue(expression: IrContinue): KonanIr.IrContinue { + val proto = KonanIr.IrContinue.newBuilder() + val label = expression.label + if (label != null) { + proto.label = label + } + val loopId = loopIndex[expression.loop]!! + proto.loopId = loopId + + return proto.build() + } + + private fun serializeCoordinates(start: Int, end: Int): KonanIr.Coordinates { + return KonanIr.Coordinates.newBuilder() + .setStartOffset(start) + .setEndOffset(end) + .build() + } + + private fun serializeExpression(expression: IrExpression): KonanIr.IrExpression { + logger.log { "### serializing Expression: ${ir2string(expression)}" } + + val coordinates = serializeCoordinates(expression.startOffset, expression.endOffset) + val proto = KonanIr.IrExpression.newBuilder() + .setType(serializeIrType(expression.type)) + .setCoordinates(coordinates) + + val operationProto = KonanIr.IrOperation.newBuilder() + + // TODO: make me a visitor. + when (expression) { + is IrBlock -> operationProto.block = serializeBlock(expression) + is IrBreak -> operationProto.`break` = serializeBreak(expression) + is IrClassReference + -> operationProto.classReference = serializeClassReference(expression) + is IrCall -> operationProto.call = serializeCall(expression) + + is IrComposite -> operationProto.composite = serializeComposite(expression) + is IrConst<*> -> operationProto.const = serializeConst(expression) + is IrContinue -> operationProto.`continue` = serializeContinue(expression) + is IrDelegatingConstructorCall + -> operationProto.delegatingConstructorCall = serializeDelegatingConstructorCall(expression) + is IrDoWhileLoop -> operationProto.doWhile = serializeDoWhile(expression) + is IrEnumConstructorCall + -> operationProto.enumConstructorCall = serializeEnumConstructorCall(expression) + is IrFunctionReference + -> operationProto.functionReference = serializeFunctionReference(expression) + is IrGetClass -> operationProto.getClass = serializeGetClass(expression) + is IrGetField -> operationProto.getField = serializeGetField(expression) + is IrGetValue -> operationProto.getValue = serializeGetValue(expression) + is IrGetEnumValue + -> operationProto.getEnumValue = serializeGetEnumValue(expression) + is IrGetObjectValue + -> operationProto.getObject = serializeGetObject(expression) + is IrInstanceInitializerCall + -> operationProto.instanceInitializerCall = serializeInstanceInitializerCall(expression) + is IrPropertyReference + -> operationProto.propertyReference = serializePropertyReference(expression) + is IrReturn -> operationProto.`return` = serializeReturn(expression) + is IrSetField -> operationProto.setField = serializeSetField(expression) + is IrSetVariable -> operationProto.setVariable = serializeSetVariable(expression) + is IrStringConcatenation + -> operationProto.stringConcat = serializeStringConcat(expression) + is IrThrow -> operationProto.`throw` = serializeThrow(expression) + is IrTry -> operationProto.`try` = serializeTry(expression) + is IrTypeOperatorCall + -> operationProto.typeOp = serializeTypeOp(expression) + is IrVararg -> operationProto.vararg = serializeVararg(expression) + is IrWhen -> operationProto.`when` = serializeWhen(expression) + is IrWhileLoop -> operationProto.`while` = serializeWhile(expression) + else -> { + TODO("Expression serialization not implemented yet: ${ir2string(expression)}.") + } + } + proto.setOperation(operationProto) + + return proto.build() + } + + private fun serializeStatement(statement: IrElement): KonanIr.IrStatement { + logger.log { "### serializing Statement: ${ir2string(statement)}" } + + val coordinates = serializeCoordinates(statement.startOffset, statement.endOffset) + val proto = KonanIr.IrStatement.newBuilder() + .setCoordinates(coordinates) + + when (statement) { + is IrDeclaration -> { + logger.log { " ###Declaration " }; proto.declaration = serializeDeclaration(statement) + } + is IrExpression -> { + logger.log { " ###Expression " }; proto.expression = serializeExpression(statement) + } + is IrBlockBody -> { + logger.log { " ###BlockBody " }; proto.blockBody = serializeBlockBody(statement) + } + is IrBranch -> { + logger.log { " ###Branch " }; proto.branch = serializeBranch(statement) + } + is IrCatch -> { + logger.log { " ###Catch " }; proto.catch = serializeCatch(statement) + } + is IrSyntheticBody -> { + logger.log { " ###SyntheticBody " }; proto.syntheticBody = serializeSyntheticBody(statement) + } + else -> { + TODO("Statement not implemented yet: ${ir2string(statement)}") + } + } + return proto.build() + } + + private fun serializeIrTypeAlias(typeAlias: IrTypeAlias) = KonanIr.IrTypeAlias.newBuilder().build() + + private fun serializeIrValueParameter(parameter: IrValueParameter): KonanIr.IrValueParameter { + val proto = KonanIr.IrValueParameter.newBuilder() + .setSymbol(serializeIrSymbol(parameter.symbol)) + .setName(parameter.name.toString()) + .setIndex(parameter.index) + .setType(serializeIrType(parameter.type)) + .setIsCrossinline(parameter.isCrossinline) + .setIsNoinline(parameter.isNoinline) + + parameter.varargElementType?.let { proto.setVarargElementType(serializeIrType(it)) } + parameter.defaultValue?.let { proto.setDefaultValue(serializeExpression(it.expression)) } + + return proto.build() + } + + private fun serializeIrTypeParameter(parameter: IrTypeParameter): KonanIr.IrTypeParameter { + val proto = KonanIr.IrTypeParameter.newBuilder() + .setSymbol(serializeIrSymbol(parameter.symbol)) + .setName(parameter.name.toString()) + .setIndex(parameter.index) + .setVariance(serializeIrTypeVariance(parameter.variance)) + .setIsReified(parameter.isReified) + parameter.superTypes.forEach { + proto.addSuperType(serializeIrType(it)) + } + return proto.build() + } + + private fun serializeIrTypeParameterContainer(typeParameters: List): KonanIr.IrTypeParameterContainer { + val proto = KonanIr.IrTypeParameterContainer.newBuilder() + typeParameters.forEach { + proto.addTypeParameter(serializeDeclaration(it)) + } + return proto.build() + } + + private fun serializeIrFunctionBase(function: IrFunctionBase): KonanIr.IrFunctionBase { + val proto = KonanIr.IrFunctionBase.newBuilder() + .setName(function.name.toString()) + .setVisibility(serializeVisibility(function.visibility)) + .setIsInline(function.isInline) + .setIsExternal(function.isExternal) + .setReturnType(serializeIrType(function.returnType)) + .setTypeParameters(serializeIrTypeParameterContainer(function.typeParameters)) + + function.dispatchReceiverParameter?.let { proto.setDispatchReceiver(serializeDeclaration(it)) } + function.extensionReceiverParameter?.let { proto.setExtensionReceiver(serializeDeclaration(it)) } + function.valueParameters.forEach { + //proto.addValueParameter(serializeIrValueParameter(it)) + proto.addValueParameter(serializeDeclaration(it)) + } + function.body?.let { proto.body = serializeStatement(it) } + return proto.build() + } + + private fun serializeModality(modality: Modality) = when (modality) { + Modality.FINAL -> KonanIr.ModalityKind.FINAL_MODALITY + Modality.SEALED -> KonanIr.ModalityKind.SEALED_MODALITY + Modality.OPEN -> KonanIr.ModalityKind.OPEN_MODALITY + Modality.ABSTRACT -> KonanIr.ModalityKind.ABSTRACT_MODALITY + } + + private fun serializeIrConstructor(declaration: IrConstructor): KonanIr.IrConstructor = + KonanIr.IrConstructor.newBuilder() + .setSymbol(serializeIrSymbol(declaration.symbol)) + .setBase(serializeIrFunctionBase(declaration as IrFunctionBase)) + .setIsPrimary(declaration.isPrimary) + .build() + + private fun serializeIrFunction(declaration: IrSimpleFunction): KonanIr.IrFunction { + val function = declaration// as IrFunctionImpl + val proto = KonanIr.IrFunction.newBuilder() + .setSymbol(serializeIrSymbol(function.symbol)) + .setModality(serializeModality(function.modality)) + .setIsTailrec(function.isTailrec) + .setIsSuspend(function.isSuspend) + + function.overriddenSymbols.forEach { + proto.addOverridden(serializeIrSymbol(it)) + } + + //function.correspondingProperty?.let { + // val uniqId = declarationTable.uniqIdByDeclaration(it) + // proto.setCorrespondingProperty(protoUniqId(uniqId)) + //} + + val base = serializeIrFunctionBase(function as IrFunctionBase) + proto.setBase(base) + + return proto.build() + } + + private fun serializeIrAnonymousInit(declaration: IrAnonymousInitializer) = KonanIr.IrAnonymousInit.newBuilder() + .setSymbol(serializeIrSymbol(declaration.symbol)) + .setBody(serializeStatement(declaration.body)) + .build() + + private fun serializeVisibility(visibility: Visibility): String { + return visibility.name + } + + private fun serializeIrProperty(property: IrProperty): KonanIr.IrProperty { + val index = declarationTable.uniqIdByDeclaration(property) + + val proto = KonanIr.IrProperty.newBuilder() + .setIsDelegated(property.isDelegated) + .setName(property.name.toString()) + .setVisibility(serializeVisibility(property.visibility)) + .setModality(serializeModality(property.modality)) + .setIsVar(property.isVar) + .setIsConst(property.isConst) + .setIsLateinit(property.isLateinit) + .setIsDelegated(property.isDelegated) + .setIsExternal(property.isExternal) + + descriptorReferenceSerializer.serializeDescriptorReference(property)?.let { proto.setDescriptor(it) } + + val backingField = property.backingField + val getter = property.getter + val setter = property.setter + if (backingField != null) + proto.backingField = serializeIrField(backingField) + if (getter != null) + proto.getter = serializeIrFunction(getter) + if (setter != null) + proto.setter = serializeIrFunction(setter) + + return proto.build() + } + + private fun serializeIrField(field: IrField): KonanIr.IrField { + val proto = KonanIr.IrField.newBuilder() + .setSymbol(serializeIrSymbol(field.symbol)) + .setName(field.name.toString()) + .setVisibility(serializeVisibility(field.visibility)) + .setIsFinal(field.isFinal) + .setIsExternal(field.isExternal) + .setIsStatic(field.isStatic) + .setType(serializeIrType(field.type)) + val initializer = field.initializer?.expression + if (initializer != null) { + proto.initializer = serializeExpression(initializer) + } + return proto.build() + } + + private fun serializeIrVariable(variable: IrVariable): KonanIr.IrVariable { + val proto = KonanIr.IrVariable.newBuilder() + .setSymbol(serializeIrSymbol(variable.symbol)) + .setName(variable.name.toString()) + .setType(serializeIrType(variable.type)) + .setIsConst(variable.isConst) + .setIsVar(variable.isVar) + .setIsLateinit(variable.isLateinit) + variable.initializer?.let { proto.initializer = serializeExpression(it) } + return proto.build() + } + + private fun serializeIrDeclarationContainer(declarations: List): KonanIr.IrDeclarationContainer { + val proto = KonanIr.IrDeclarationContainer.newBuilder() + declarations.forEach { + //if (it is IrDeclarationWithVisibility && it.visibility == Visibilities.INVISIBLE_FAKE) return@forEach + proto.addDeclaration(serializeDeclaration(it)) + } + return proto.build() + } + + private fun serializeClassKind(kind: ClassKind) = when (kind) { + CLASS -> KonanIr.ClassKind.CLASS + INTERFACE -> KonanIr.ClassKind.INTERFACE + ENUM_CLASS -> KonanIr.ClassKind.ENUM_CLASS + ENUM_ENTRY -> KonanIr.ClassKind.ENUM_ENTRY + ANNOTATION_CLASS -> KonanIr.ClassKind.ANNOTATION_CLASS + OBJECT -> KonanIr.ClassKind.OBJECT + } + + private fun serializeIrClass(clazz: IrClass): KonanIr.IrClass { + val proto = KonanIr.IrClass.newBuilder() + .setName(clazz.name.toString()) + .setSymbol(serializeIrSymbol(clazz.symbol)) + .setKind(serializeClassKind(clazz.kind)) + .setVisibility(serializeVisibility(clazz.visibility)) + .setModality(serializeModality(clazz.modality)) + .setIsCompanion(clazz.isCompanion) + .setIsInner(clazz.isInner) + .setIsData(clazz.isData) + .setIsExternal(clazz.isExternal) + .setIsInline(clazz.isInline) + .setTypeParameters(serializeIrTypeParameterContainer(clazz.typeParameters)) + .setDeclarationContainer(serializeIrDeclarationContainer(clazz.declarations)) + clazz.superTypes.forEach { + proto.addSuperType(serializeIrType(it)) + } + clazz.thisReceiver?.let { proto.thisReceiver = serializeDeclaration(it) } + + return proto.build() + } + + private fun serializeIrEnumEntry(enumEntry: IrEnumEntry): KonanIr.IrEnumEntry { + val proto = KonanIr.IrEnumEntry.newBuilder() + .setName(enumEntry.name.toString()) + .setSymbol(serializeIrSymbol(enumEntry.symbol)) + + enumEntry.initializerExpression?.let { + proto.initializer = serializeExpression(it) + } + enumEntry.correspondingClass?.let { + proto.correspondingClass = serializeDeclaration(it) + } + return proto.build() + } + + private fun serializeIrDeclarationOrigin(origin: IrDeclarationOrigin) = + KonanIr.IrDeclarationOrigin.newBuilder() + .setName((origin as IrDeclarationOriginImpl).name) + + private fun serializeDeclaration(declaration: IrDeclaration): KonanIr.IrDeclaration { + logger.log { "### serializing Declaration: ${ir2string(declaration)}" } + + val declarator = KonanIr.IrDeclarator.newBuilder() + + when (declaration) { + is IrTypeAlias + -> declarator.irTypeAlias = serializeIrTypeAlias(declaration) + is IrAnonymousInitializer + -> declarator.irAnonymousInit = serializeIrAnonymousInit(declaration) + is IrConstructor + -> declarator.irConstructor = serializeIrConstructor(declaration) + is IrField + -> declarator.irField = serializeIrField(declaration) + is IrSimpleFunction + -> declarator.irFunction = serializeIrFunction(declaration) + is IrTypeParameter + -> declarator.irTypeParameter = serializeIrTypeParameter(declaration) + is IrVariable + -> declarator.irVariable = serializeIrVariable(declaration) + is IrValueParameter + -> declarator.irValueParameter = serializeIrValueParameter(declaration) + is IrClass + -> declarator.irClass = serializeIrClass(declaration) + is IrEnumEntry + -> declarator.irEnumEntry = serializeIrEnumEntry(declaration) + is IrProperty + -> declarator.irProperty = serializeIrProperty(declaration) + else + -> TODO("Declaration serialization not supported yet: $declaration") + } + + val coordinates = serializeCoordinates(declaration.startOffset, declaration.endOffset) + val annotations = serializeAnnotations(declaration.annotations) + val origin = serializeIrDeclarationOrigin(declaration.origin) + val proto = KonanIr.IrDeclaration.newBuilder() + .setCoordinates(coordinates) + .setAnnotations(annotations) + .setOrigin(origin) + + + proto.setDeclarator(declarator) + + // TODO disabled for now. + //val fileName = context.ir.originalModuleIndex.declarationToFile[declaration.descriptor] + //proto.fileName = fileName + + proto.fileName = "some file name" + + return proto.build() + } + +// ---------- Top level ------------------------------------------------------ + + fun serializeFileEntry(entry: SourceManager.FileEntry) = KonanIr.FileEntry.newBuilder() + .setName(entry.name) + .build() + + val topLevelDeclarations = mutableMapOf() + + fun serializeIrFile(file: IrFile): KonanIr.IrFile { + val proto = KonanIr.IrFile.newBuilder() + .setFileEntry(serializeFileEntry(file.fileEntry)) + .setFqName(file.fqName.toString()) + + file.declarations.forEach { + if (it is IrTypeAlias) return@forEach + if (it.descriptor.isExpectMember && !it.descriptor.isSerializableExpectClass) { + return@forEach + } + + val byteArray = serializeDeclaration(it).toByteArray() + val uniqId = declarationTable.uniqIdByDeclaration(it) + topLevelDeclarations.put(uniqId, byteArray) + proto.addDeclarationId(protoUniqId(uniqId)) + } + return proto.build() + } + + fun serializeModule(module: IrModuleFragment): KonanIr.IrModule { + val proto = KonanIr.IrModule.newBuilder() + .setName(module.name.toString()) + module.files.forEach { + proto.addFile(serializeIrFile(it)) + } + proto.symbolTable = KonanIr.IrSymbolTable.newBuilder() + .addAllSymbols(protoSymbolArray) + .build() + + proto.typeTable = KonanIr.IrTypeTable.newBuilder() + .addAllTypes(protoTypeArray) + .build() + + return proto.build() + } + + + fun serializedIrModule(module: IrModuleFragment): SerializedIr { + val moduleHeader = serializeModule(module).toByteArray() + return SerializedIr(moduleHeader, topLevelDeclarations, declarationTable.debugIndex) + } +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrSerializationUtil.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrSerializationUtil.kt new file mode 100644 index 00000000000..2f81a1d4fd1 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrSerializationUtil.kt @@ -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.resolveFakeOverrideMaybeAbstract(): Set { + 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 + } +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto index bb2e091cbd2..a7d3f5b6f3c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto @@ -1,69 +1,26 @@ - syntax = "proto2"; package org.jetbrains.kotlin.metadata; -// FIXME(ddol): fix this import after moving `metadata` to main Kotlin repo - it should refer to the actual metadata.proto file from Kotlin project -import "org/jetbrains/kotlin/backend/konan/serialization/metadata.proto1"; option java_outer_classname = "KonanIr"; option optimize_for = LITE_RUNTIME; -// This is subject to change. -// One can think of it as a 'descriptor reference'. -// The real descriptor data is encoded in KonanLinkdData. -message KotlinDescriptor { - enum Kind { - FUNCTION = 1; - VARIABLE = 2; - CLASS = 3; - VALUE_PARAMETER = 4; - CONSTRUCTOR = 5; - TYPE_PARAMETER = 6; - RECEIVER = 7; - ACCESSOR = 8; - PROPERTY = 9; - } - // TODO: Use the string table index. - optional string name = 1; - required Kind kind = 2; - required UniqId uniq_id = 3; - required UniqId original_uniq_id = 4; - // index in fq name table - optional int32 class_or_package = 5; - - // Descriptor kind specific fields. - // TODO: consider introducing specific messages - // for functions, variables etc. - optional KotlinType type = 6; - repeated KotlinDescriptor value_parameter = 7; - repeated KotlinDescriptor type_parameter = 8; - optional UniqId dispatch_receiver_uniq_id = 9; - optional UniqId extension_receiver_uniq_id = 10; - optional KotlinType extension_receiver_type = 11; - optional LocalDeclaration ir_local_declaration = 12; +message DescriptorReference { + required string package_fq_name = 1; + required string class_fq_name = 2; + required string name = 3; + optional UniqId uniq_id = 4; + optional bool is_getter = 5 [default = false]; + optional bool is_setter = 6 [default = false]; + optional bool is_backing_field = 7 [default = false]; + optional bool is_fake_override = 8 [default = false]; + optional bool is_default_constructor = 9 [default = false]; + optional bool is_enum_entry = 10 [default = false]; + optional bool is_enum_special = 11 [default = false]; } message UniqId { - required int64 index = 1; -} - -// Inner descriptors used for inlining. -message DeclarationDescriptor { - // These are ProtoBuf.Function, ProtoBuf.Class etc - oneof descriptor { - Function function = 1; - Class clazz = 2; - Property property = 3; - Constructor constructor = 4; - } -} -message LocalDeclaration { - required DeclarationDescriptor descriptor = 1; -} - -message KotlinType { - required int32 index = 1; - required bool isCaptured = 2; // TODO: make it a flag set? - optional string debug_text = 3; // TODO: remove me + required uint64 index = 1; + required bool isLocal = 2; } message Coordinates { @@ -71,9 +28,127 @@ message Coordinates { required int32 end_offset = 2; } -message TypeArguments { - repeated KotlinType type_argument = 1; +/* ------ Top Level---------------------------------------------- */ + +message IrDeclarationContainer { + repeated IrDeclaration declaration = 1; } + +message FileEntry { // TODO: extend me. + required string name = 1; +} + +message IrFile { + repeated UniqId declaration_id = 1; + required FileEntry file_entry = 2; + // TODO: we need a better string management. See metadata serialization as an example. + required string fq_name = 3; +} + +message IrModule { + required string name = 1; + repeated IrFile file = 2; + required IrSymbolTable symbol_table = 3; + required IrTypeTable type_table = 4; +} + +/* ------ IrSymbols --------------------------------------------- */ + +enum IrSymbolKind { + FUNCTION_SYMBOL = 1; + CONSTRUCTOR_SYMBOL = 2; + ENUM_ENTRY_SYMBOL = 3; + FIELD_SYMBOL = 4; + VALUE_PARAMETER_SYMBOL = 5; + RETURNABLE_BLOCK_SYMBOL = 6; + CLASS_SYMBOL = 7; + TYPE_PARAMETER_SYMBOL = 8; + VARIABLE_SYMBOL = 9; + ANONYMOUS_INIT_SYMBOL = 10; + + STANDALONE_FIELD_SYMBOL = 11; // For fields without properties. WrappedFieldDescriptor, rather than WrappedPropertyDescriptor. + RECEIVER_PARAMETER_SYMBOL = 12; // ReceiverParameterDescriptor rather than ValueParameterDescriptor. +} + +message IrSymbolData { + required IrSymbolKind kind = 1; + required UniqId uniq_id = 2; + required UniqId top_level_uniq_id = 3; + optional string fqname = 4; + optional DescriptorReference descriptor_reference = 5; +} + +message IrSymbol { + required int32 index = 1; +} + +message IrSymbolTable { + repeated IrSymbolData symbols = 1; +} + +/* ------ IrTypes --------------------------------------------- */ + +enum IrTypeVariance { // Should we import metadata variance, or better stay separate? + IN = 0; + OUT = 1; + INV = 2; +} + +message Annotations { + repeated IrCall annotation = 1; +} + +message TypeArguments { + repeated IrTypeIndex type_argument = 1; +} + +message IrStarProjection { + optional bool void = 1; +} + +message IrTypeProjection { + required IrTypeVariance variance = 1; + required IrTypeIndex type = 2; +} + +message IrTypeArgument { + oneof kind { + IrStarProjection star = 1; + IrTypeProjection type = 2; + } +} + +message IrSimpleType { + required Annotations annotations = 1; + required IrSymbol classifier = 2; + required bool has_question_mark = 3; + repeated IrTypeArgument argument = 4; +} + +message IrDynamicType { + required Annotations annotations = 1; +} + +message IrErrorType { + required Annotations annotations = 1; +} + +message IrType { + oneof kind { + IrSimpleType simple = 1; + IrDynamicType dynamic = 2; + IrErrorType error = 3; + } +} + +message IrTypeTable { + repeated IrType types = 1; +} + +message IrTypeIndex { + required int32 index = 1; +} + /* ------ IrExpressions --------------------------------------------- */ message IrBreak { @@ -83,14 +158,14 @@ message IrBreak { message IrBlock { required bool is_lambda_origin = 1; - repeated IrStatement statement = 2; + repeated IrStatement statement = 2; } message MemberAccessCommon { - optional IrExpression dispatch_receiver = 5; - optional IrExpression extension_receiver = 6; - repeated NullableIrExpression value_argument = 8; - required TypeArguments type_arguments = 9; + optional IrExpression dispatch_receiver = 1; + optional IrExpression extension_receiver = 2; + repeated NullableIrExpression value_argument = 3; + required TypeArguments type_arguments = 4; } message IrCall { @@ -101,37 +176,47 @@ message IrCall { BINARY = 4; } required Primitive kind = 1; - required KotlinDescriptor descriptor = 2; + required IrSymbol symbol = 2; required MemberAccessCommon member_access = 3; - optional KotlinDescriptor super = 4; + optional IrSymbol super = 4; } -message IrCallableReference { - required KotlinDescriptor descriptor = 1; - required TypeArguments type_arguments = 2; +message IrFunctionReference { + required IrSymbol symbol = 1; + optional string origin = 2; + required MemberAccessCommon member_access = 3; } +message IrPropertyReference { + optional IrSymbol field = 1; + optional IrSymbol getter = 2; + optional IrSymbol setter = 3; + optional string origin = 4; + required MemberAccessCommon member_access = 5; +} + message IrComposite { repeated IrStatement statement = 1; } message IrClassReference { - required KotlinDescriptor class_descriptor = 1; + required IrSymbol class_symbol = 1; + required IrTypeIndex class_type = 2; } message IrConst { oneof value { - bool null = 1; - bool boolean = 2; - int32 char = 3; - int32 byte = 4; - int32 short = 5; - int32 int = 6; - int64 long = 7; - float float = 8; - double double = 9; - string string = 10; + bool null = 1; + bool boolean = 2; + int32 char = 3; + int32 byte = 4; + int32 short = 5; + int32 int = 6; + int64 long = 7; + float float = 8; + double double = 9; + string string = 10; } } @@ -141,7 +226,7 @@ message IrContinue { } message IrDelegatingConstructorCall { - required KotlinDescriptor descriptor = 1; + required IrSymbol symbol = 1; required MemberAccessCommon member_access = 2; } @@ -150,7 +235,7 @@ message IrDoWhile { } message IrEnumConstructorCall { - required KotlinDescriptor descriptor = 1; + required IrSymbol symbol = 1; required MemberAccessCommon member_access = 2; } @@ -159,14 +244,13 @@ message IrGetClass { } message IrGetEnumValue { - required KotlinType type = 1; - required KotlinDescriptor descriptor = 2; + required IrSymbol symbol = 2; } message FieldAccessCommon { - required KotlinDescriptor descriptor = 1; - optional KotlinDescriptor super = 2; - required IrExpression receiver = 3; + required IrSymbol symbol = 1; + optional IrSymbol super = 2; + optional IrExpression receiver = 3; } message IrGetField { @@ -174,15 +258,15 @@ message IrGetField { } message IrGetValue { - required KotlinDescriptor descriptor = 1; + required IrSymbol symbol = 1; } message IrGetObject { - required KotlinDescriptor descriptor = 1; + required IrSymbol symbol = 1; } message IrInstanceInitializerCall { - required KotlinDescriptor descriptor = 1; + required IrSymbol symbol = 1; } message Loop { @@ -193,7 +277,7 @@ message Loop { } message IrReturn { - required KotlinDescriptor return_target = 1; + required IrSymbol return_target = 1; required IrExpression value = 2; } @@ -203,7 +287,7 @@ message IrSetField { } message IrSetVariable { - required KotlinDescriptor descriptor = 1; + required IrSymbol symbol = 1; required IrExpression value = 2; } @@ -213,7 +297,7 @@ message IrSpreadElement { } message IrStringConcat { - repeated IrExpression argument = 1; + repeated IrExpression argument = 1; } message IrThrow { @@ -228,12 +312,12 @@ message IrTry { message IrTypeOp { required IrTypeOperator operator = 1; - required KotlinType operand = 2; + required IrTypeIndex operand = 2; required IrExpression argument = 3; } message IrVararg { - required KotlinType element_type = 1; + required IrTypeIndex element_type = 1; repeated IrVarargElement element = 2; } @@ -259,30 +343,31 @@ message IrOperation { IrBlock block = 1; IrBreak break = 2; IrCall call = 3; - IrCallableReference callable_reference = 4; - IrClassReference class_reference = 27; - IrConst const = 5; - IrComposite composite = 26; - IrContinue continue = 6; - IrDelegatingConstructorCall delegating_constructor_call = 7; - IrDoWhile do_while = 25; - IrEnumConstructorCall enum_constructor_call = 8; - IrGetClass get_class = 24; - IrGetEnumValue get_enum_value = 9; - IrGetField get_field = 10; - IrGetValue get_value = 11; - IrGetObject get_object = 12; - IrInstanceInitializerCall instance_initializer_call = 13; - IrReturn return = 14; - IrSetField set_field = 15; - IrSetVariable set_variable = 16; - IrStringConcat string_concat = 17; - IrThrow throw = 18; - IrTry try = 19; - IrTypeOp type_op = 20; - IrVararg vararg = 21; - IrWhen when = 22; - IrWhile while = 23; + IrClassReference class_reference = 4; + IrComposite composite = 5; + IrConst const = 6; + IrContinue continue = 7; + IrDelegatingConstructorCall delegating_constructor_call = 8; + IrDoWhile do_while = 9; + IrEnumConstructorCall enum_constructor_call = 10; + IrFunctionReference function_reference = 11; + IrGetClass get_class = 12; + IrGetEnumValue get_enum_value = 13; + IrGetField get_field = 14; + IrGetObject get_object = 15; + IrGetValue get_value = 16; + IrInstanceInitializerCall instance_initializer_call = 17; + IrPropertyReference property_reference = 18; + IrReturn return = 19; + IrSetField set_field = 20; + IrSetVariable set_variable = 21; + IrStringConcat string_concat = 22; + IrThrow throw = 23; + IrTry try = 24; + IrTypeOp type_op = 25; + IrVararg vararg = 26; + IrWhen when = 27; + IrWhile while = 28; } } @@ -291,14 +376,17 @@ enum IrTypeOperator { IMPLICIT_CAST = 2; IMPLICIT_NOTNULL = 3; IMPLICIT_COERCION_TO_UNIT = 4; - SAFE_CAST = 5; - INSTANCEOF = 6; - NOT_INSTANCEOF = 7; + IMPLICIT_INTEGER_COERCION = 5; + SAFE_CAST = 6; + INSTANCEOF = 7; + NOT_INSTANCEOF = 8; + SAM_CONVERSION = 9; } + message IrExpression { required IrOperation operation = 1; - required KotlinType type = 2; + required IrTypeIndex type = 2; required Coordinates coordinates = 3; } @@ -306,59 +394,177 @@ message NullableIrExpression { optional IrExpression expression = 1; } - /* ------ Declarations --------------------------------------------- */ +message IrTypeAlias { + // Nothing for now. +} + message IrFunction { - message DefaultArgument { - required int32 position = 1; - required IrExpression value = 2; - } - optional IrStatement body = 1; - repeated DefaultArgument default_argument = 2; + required IrSymbol symbol = 1; + required IrFunctionBase base = 2; + required ModalityKind modality = 3; + required bool is_tailrec = 4; + required bool is_suspend = 5; + repeated IrSymbol overridden = 6; + //optional UniqId corresponding_property = 7; +} + +message IrFunctionBase { + required string name = 1; + required string visibility = 2; + required bool is_inline = 3; + required bool is_external = 4; + required IrTypeParameterContainer type_parameters = 5; + optional IrDeclaration dispatch_receiver = 6; + optional IrDeclaration extension_receiver = 7; + repeated IrDeclaration value_parameter = 8; + optional IrStatement body = 9; + required IrTypeIndex return_type = 10; +} + +message IrConstructor { + required IrSymbol symbol = 1; + required IrFunctionBase base = 2; + required bool is_primary = 3; + +} + +message IrField { + required IrSymbol symbol = 1; + optional IrExpression initializer = 2; + required string name = 3; + required string visibility = 4; + required bool is_final = 5; + required bool is_external = 6; + required bool is_static = 7; + required IrTypeIndex type = 8; } message IrProperty { - message IrField { - required IrExpression initializer = 1; - } - required bool is_delegated = 1; - optional IrField backing_field = 2; - optional IrFunction getter = 3; - optional IrFunction setter = 4; + optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now. + required string name = 2; + required string visibility = 3; + required ModalityKind modality = 4; + required bool is_var = 5; + required bool is_const = 6; + required bool is_lateinit = 7; + required bool is_delegated = 8; + required bool is_external = 9; + optional IrField backing_field = 10; + optional IrFunction getter = 11; + optional IrFunction setter = 12; } -message IrVar { - optional IrExpression initializer = 1; +message IrVariable { + required string name = 1; + required IrSymbol symbol = 2; + required IrTypeIndex type = 3; + required bool is_var = 4; + required bool is_const = 5; + required bool is_lateinit = 6; + optional IrExpression initializer = 7; +} + +enum ClassKind { + CLASS = 1; + INTERFACE = 2; + ENUM_CLASS = 3; + ENUM_ENTRY = 4; + ANNOTATION_CLASS = 5; + OBJECT = 6; +} + +enum ModalityKind { // It is ModalityKind to not clash with Modality in descriptor metadata. + FINAL_MODALITY = 1; + SEALED_MODALITY = 2; + OPEN_MODALITY = 3; + ABSTRACT_MODALITY = 4; +} + +message IrValueParameter { + required IrSymbol symbol = 1; + required string name = 2; + required int32 index = 3; + required IrTypeIndex type = 4; + optional IrTypeIndex vararg_element_type = 5; + required bool is_crossinline = 6; + required bool is_noinline = 7; + optional IrExpression default_value = 8; +} + +message IrTypeParameter { + required IrSymbol symbol = 1; + required string name = 2; + required int32 index = 3; + required IrTypeVariance variance = 4; + repeated IrTypeIndex super_type = 5; + required bool is_reified = 6; +} + +message IrTypeParameterContainer { + repeated IrDeclaration type_parameter = 1; } message IrClass { - repeated IrDeclaration member = 1; + required IrSymbol symbol = 1; + required string name = 2; + required ClassKind kind = 3; + required string visibility = 4; + required ModalityKind modality = 5; + // TODO: consider using flags for the booleans. + required bool is_companion = 6; + required bool is_inner = 7; + required bool is_data = 8; + required bool is_external = 9; + required bool is_inline = 10; + optional IrDeclaration this_receiver = 11; + required IrTypeParameterContainer type_parameters = 12; + required IrDeclarationContainer declaration_container = 13; + repeated IrTypeIndex super_type = 14; } message IrEnumEntry { - required IrExpression initializer = 1; - optional IrDeclaration corresponding_class = 2; + required IrSymbol symbol = 1; + optional IrExpression initializer = 2; + optional IrDeclaration corresponding_class = 3; + required string name = 4; +} + +message IrAnonymousInit { + required IrSymbol symbol = 1; + required IrStatement body = 2; } // TODO: we need an extension mechanism to accomodate new // IR operators in upcoming releases. message IrDeclarator { - oneof symbol { - IrVar variable = 1; - IrFunction function = 2; - IrClass ir_class = 3; + oneof declarator { + IrAnonymousInit ir_anonymous_init = 1; + IrClass ir_class = 2; + IrConstructor ir_constructor = 3; IrEnumEntry ir_enum_entry = 4; - IrProperty ir_property = 5; + IrField ir_field = 5; + IrFunction ir_function = 6; + IrProperty ir_property = 7; + IrTypeAlias ir_type_alias = 8; + IrTypeParameter ir_type_parameter = 9; + IrVariable ir_variable = 10; + IrValueParameter ir_value_parameter = 11; } } +message IrDeclarationOrigin { + required string name = 1; +} + message IrDeclaration { - required KotlinDescriptor descriptor = 1; + required IrDeclarationOrigin origin = 1; required Coordinates coordinates = 2; - required IrDeclarator declarator = 3; - repeated IrDeclaration nested = 4; - required string file_name = 5; + required Annotations annotations = 3; + required IrDeclarator declarator = 4; + //repeated IrDeclaration nested = 5; + required string file_name = 5; // TODO: files should be communicated some other way, I suppose. } /* ------- IrStatements --------------------------------------------- */ @@ -377,6 +583,15 @@ message IrCatch { required IrExpression result = 2; } +enum IrSyntheticBodyKind { + ENUM_VALUES = 1; + ENUM_VALUEOF = 2; +} + +message IrSyntheticBody { + required IrSyntheticBodyKind kind = 1; +} + // Let's try to map IrElement as well as IrStatement to IrStatement. message IrStatement { required Coordinates coordinates = 1; @@ -386,6 +601,6 @@ message IrStatement { IrBlockBody block_body = 4; IrBranch branch = 5; IrCatch catch = 6; + IrSyntheticBody synthetic_body = 7; } } - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleDeserializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleDeserializer.kt new file mode 100644 index 00000000000..cdce02fc719 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrModuleDeserializer.kt @@ -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() + val reachableTopLevels = mutableSetOf() + val deserializedTopLevels = mutableSetOf() + val forwardDeclarations = mutableSetOf() + + var deserializedModuleDescriptor: ModuleDescriptor? = null + var deserializedModuleProtoSymbolTables = mutableMapOf() + var deserializedModuleProtoTypeTables = mutableMapOf() + + val resolvedForwardDeclarations = mutableMapOf() + 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() + + 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 == "") 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) + } +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializationUtil.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializationUtil.kt index 09340383b5f..081510ad38d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializationUtil.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializationUtil.kt @@ -7,11 +7,14 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember +import org.jetbrains.kotlin.backend.konan.descriptors.isSerializableExpectClass import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf +import org.jetbrains.kotlin.backend.konan.library.SerializedIr +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -32,7 +35,7 @@ import org.jetbrains.kotlin.serialization.konan.SourceFileMap * with MemberDeserializer class. */ -internal class KonanSerializationUtil(val context: Context, private val metadataVersion: BinaryVersion) { +internal class KonanSerializationUtil(val context: Context, val metadataVersion: BinaryVersion, val declarationTable: DeclarationTable) { lateinit var serializerContext: SerializerContext @@ -43,9 +46,8 @@ internal class KonanSerializationUtil(val context: Context, private val metadata val topSerializer: DescriptorSerializer, var classSerializer: DescriptorSerializer = topSerializer ) - private fun createNewContext(): SerializerContext { - val extension = KonanSerializerExtension(context, metadataVersion, sourceFileMap) + val extension = KonanSerializerExtension(context, metadataVersion, sourceFileMap, declarationTable) return SerializerContext( extension, DescriptorSerializer.createTopLevel(extension) @@ -63,9 +65,9 @@ internal class KonanSerializationUtil(val context: Context, private val metadata with(serializerContext) { val previousSerializer = classSerializer - // TODO: this is to filter out object{}. Change me. - if (classDescriptor.isExported()) - classSerializer = DescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer) + // TODO: this is to filter out object{}. Change me. + // if (classDescriptor.isExported()) + // classSerializer = KonanDescriptorSerializer.create(classDescriptor, serializerExtension, classSerializer) val classProto = classSerializer.classProto(classDescriptor).build() ?: error("Class not serialized: $classDescriptor") @@ -207,7 +209,7 @@ internal class KonanSerializationUtil(val context: Context, private val metadata .build() } - internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData { + internal fun serializeModule(moduleDescriptor: ModuleDescriptor, serializedIr: SerializedIr): LinkData { val libraryProto = KonanProtoBuf.LinkDataLibrary.newBuilder() libraryProto.moduleName = moduleDescriptor.name.asString() val fragments = mutableListOf>() @@ -233,7 +235,7 @@ internal class KonanSerializationUtil(val context: Context, private val metadata } val libraryAsByteArray = libraryProto.build().toByteArray() - return LinkData(libraryAsByteArray, fragments, fragmentNames) + return LinkData(libraryAsByteArray, fragments, fragmentNames, serializedIr) } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt index bcd014e55cd..54f8c85fc51 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanSerializerExtension.kt @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.backend.konan.serialization -import org.jetbrains.kotlin.backend.common.onlyIf import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.descriptors.needsSerializedIr import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* @@ -22,15 +20,19 @@ import org.jetbrains.kotlin.serialization.konan.SourceFileMap import org.jetbrains.kotlin.types.KotlinType internal class KonanSerializerExtension(val context: Context, override val metadataVersion: BinaryVersion, - val sourceFileMap: SourceFileMap) : - KotlinSerializerExtensionBase(KonanSerializerProtocol), IrAwareExtension { + val sourceFileMap: SourceFileMap, val declarationTable: DeclarationTable) : + KotlinSerializerExtensionBase(KonanSerializerProtocol) { - val inlineDescriptorTable = DescriptorTable(context.irBuiltIns) override val stringTable = KonanStringTable() override fun shouldUseTypeTable(): Boolean = true + fun uniqId(descriptor: DeclarationDescriptor): KonanProtoBuf.DescriptorUniqId? { + val index = declarationTable.descriptorTable.get(descriptor) + return index?.let { newDescriptorUniqId(it) } + } + override fun serializeType(type: KotlinType, proto: ProtoBuf.Type.Builder) { - // TODO: For debugging purpose we store the textual + // TODO: For debugging purpose we store the textual // representation of serialized types. // To be removed. proto.setExtension(KonanProtoBuf.typeText, type.toString()) @@ -38,95 +40,58 @@ internal class KonanSerializerExtension(val context: Context, override val metad super.serializeType(type, proto) } + override fun serializeTypeParameter(typeParameter: TypeParameterDescriptor, proto: ProtoBuf.TypeParameter.Builder) { + uniqId(typeParameter) ?.let { proto.setExtension(KonanProtoBuf.typeParamUniqId, it) } + super.serializeTypeParameter(typeParameter, proto) + } + + override fun serializeValueParameter(descriptor: ValueParameterDescriptor, proto: ProtoBuf.ValueParameter.Builder) { + uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.valueParamUniqId, it) } + super.serializeValueParameter(descriptor, proto) + } + override fun serializeEnumEntry(descriptor: ClassDescriptor, proto: ProtoBuf.EnumEntry.Builder) { + uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.enumEntryUniqId, it) } // Serialization doesn't preserve enum entry order, so we need to serialize ordinal. val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(descriptor) proto.setExtension(KonanProtoBuf.enumEntryOrdinal, ordinal) super.serializeEnumEntry(descriptor, proto) } - override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder, - childSerializer: DescriptorSerializer) { - super.serializeConstructor(descriptor, proto, childSerializer) - if (descriptor.needsSerializedIr) { - addConstructorIR(proto, serializeInlineBody(descriptor, childSerializer)) - } - } - override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder, versionRequirementTable: MutableVersionRequirementTable, childSerializer: DescriptorSerializer) { + uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.classUniqId, it) } super.serializeClass(descriptor, proto, versionRequirementTable, childSerializer) - context.ir.classesDelegatedBackingFields[descriptor]?.forEach { - proto.addProperty(childSerializer.propertyProto(it)) - } - // Invocation of the propertyProto above can add more types - // to the type table that should also be serialized. childSerializer.typeTable.serialize()?.let { proto.mergeTypeTable(it) } } + override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder, + childSerializer: DescriptorSerializer) { + uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.constructorUniqId, it) } + super.serializeConstructor(descriptor, proto, childSerializer) + } + + override fun serializeFunction(descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder, childSerializer: DescriptorSerializer) { proto.setExtension(KonanProtoBuf.functionFile, sourceFileMap.assign(descriptor.source.containingFile)) + uniqId(descriptor) ?. let { proto.setExtension(KonanProtoBuf.functionUniqId, it) } super.serializeFunction(descriptor, proto, childSerializer) - if (descriptor.needsSerializedIr) { - addFunctionIR(proto, serializeInlineBody(descriptor, childSerializer)) - } } override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder, versionRequirementTable: MutableVersionRequirementTable, childSerializer: DescriptorSerializer) { - val variable = originalVariables[descriptor] - if (variable != null) { - proto.setExtension(KonanProtoBuf.usedAsVariable, true) - } proto.setExtension(KonanProtoBuf.propertyFile, sourceFileMap.assign(descriptor.source.containingFile)) + uniqId(descriptor) ?.let { proto.setExtension(KonanProtoBuf.propertyUniqId, it) } proto.setExtension(KonanProtoBuf.hasBackingField, context.ir.propertiesWithBackingFields.contains(descriptor)) super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer) - - /* Konan specific chunk */ - descriptor.getter?.onlyIf({ needsSerializedIr }) { - addGetterIR(proto, serializeInlineBody(it, childSerializer)) - } - descriptor.setter?.onlyIf({ needsSerializedIr }) { - addSetterIR(proto, serializeInlineBody(it, childSerializer)) - } - } - - override fun addFunctionIR(proto: ProtoBuf.Function.Builder, serializedIR: String) - = proto.setInlineIr(inlineBody(serializedIR)) - - override fun addConstructorIR(proto: ProtoBuf.Constructor.Builder, serializedIR: String) - = proto.setConstructorIr(inlineBody(serializedIR)) - - override fun addGetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String) - = proto.setGetterIr(inlineBody(serializedIR)) - - override fun addSetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String) - = proto.setSetterIr(inlineBody(serializedIR)) - - override fun serializeInlineBody(descriptor: FunctionDescriptor, serializer: DescriptorSerializer): String { - - return IrSerializer( - context, inlineDescriptorTable, stringTable, serializer, descriptor).serializeInlineBody() } override fun releaseCoroutines(): Boolean = context.config.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) + } - -internal interface IrAwareExtension { - - fun serializeInlineBody(descriptor: FunctionDescriptor, serializer: DescriptorSerializer): String - - fun addFunctionIR(proto: ProtoBuf.Function.Builder, serializedIR: String): ProtoBuf.Function.Builder - - fun addConstructorIR(proto: ProtoBuf.Constructor.Builder, serializedIR: String): ProtoBuf.Constructor.Builder - - fun addSetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String): ProtoBuf.Property.Builder - - fun addGetterIR(proto: ProtoBuf.Property.Builder, serializedIR: String): ProtoBuf.Property.Builder -} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/LocalDeclarationDeserializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/LocalDeclarationDeserializer.kt deleted file mode 100644 index 56c624c3a07..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/LocalDeclarationDeserializer.kt +++ /dev/null @@ -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 = - (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>() - - 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) - } -} - - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/LocalDeclarationSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/LocalDeclarationSerializer.kt deleted file mode 100644 index fe0c478b089..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/LocalDeclarationSerializer.kt +++ /dev/null @@ -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() - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/ProtobufUtil.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/ProtobufUtil.kt deleted file mode 100644 index 27dee75487f..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/ProtobufUtil.kt +++ /dev/null @@ -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 - 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") - } - - diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeDescriptorReference.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeDescriptorReference.kt new file mode 100644 index 00000000000..581e67ec358 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeDescriptorReference.kt @@ -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() + } +} + + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt deleted file mode 100644 index b4f53124b02..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/SerializeIr.kt +++ /dev/null @@ -1,1342 +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.deserializedPropertyIfAccessor -import org.jetbrains.kotlin.backend.konan.descriptors.isDeserializableCallable -import org.jetbrains.kotlin.backend.common.ir.ir2string -import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole -import org.jetbrains.kotlin.backend.konan.llvm.base64Decode -import org.jetbrains.kotlin.backend.konan.llvm.base64Encode -import org.jetbrains.kotlin.backend.konan.lower.DeepCopyIrTreeWithDescriptors -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.DEFINED -import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrEnumEntryImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.* -import org.jetbrains.kotlin.ir.symbols.impl.* -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.util.* -import org.jetbrains.kotlin.metadata.KonanIr -import org.jetbrains.kotlin.metadata.KonanIr.IrConst.ValueCase.* -import org.jetbrains.kotlin.metadata.KonanIr.IrOperation.OperationCase.* -import org.jetbrains.kotlin.metadata.KonanIr.IrVarargElement.VarargElementCase.* -import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf -import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue -import org.jetbrains.kotlin.resolve.descriptorUtil.parents -import org.jetbrains.kotlin.serialization.DescriptorSerializer -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassConstructorDescriptor -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor -import org.jetbrains.kotlin.serialization.konan.KonanSerializerProtocol -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjectionImpl -import org.jetbrains.kotlin.types.TypeSubstitutor - - -internal class IrSerializer(val context: Context, - descriptorTable: DescriptorTable, - stringTable: KonanStringTable, - rootFunctionSerializer: DescriptorSerializer, - private var rootFunction: FunctionDescriptor) { - - private val loopIndex = mutableMapOf() - private var currentLoopIndex = 0 - private val localDeclarationSerializer - = LocalDeclarationSerializer(context, rootFunctionSerializer) - private val irDescriptorSerializer - = IrDescriptorSerializer(context, descriptorTable, - stringTable, localDeclarationSerializer, rootFunction) - - fun serializeInlineBody(): String { - val declaration = context.ir.originalModuleIndex.functions[rootFunction]!! - context.log{"INLINE: ${ir2stringWhole(declaration)}"} - return encodeDeclaration(declaration) - } - - private fun serializeKotlinType(type: KotlinType): KonanIr.KotlinType { - context.log{"### serializing KotlinType: " + type} - return irDescriptorSerializer.serializeKotlinType(type) - } - - private fun serializeKotlinType(type: IrType) = serializeKotlinType(type.toKotlinType()) - - private fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor { - context.log{"### serializeDescriptor $descriptor"} - - // Behind this call starts a large world of - // descriptor serialization for IR. - return irDescriptorSerializer.serializeDescriptor(descriptor) - } - - private fun serializeCoordinates(start: Int, end: Int): KonanIr.Coordinates { - return KonanIr.Coordinates.newBuilder() - .setStartOffset(start) - .setEndOffset(end) - .build() - } - - private fun serializeTypeArguments(call: IrMemberAccessExpression): KonanIr.TypeArguments { - val proto = KonanIr.TypeArguments.newBuilder() - for (i in 0 until call.typeArgumentsCount) { - proto.addTypeArgument(serializeKotlinType(call.getTypeArgument(i)!!)) - } - return proto.build() - } - - /* -------------------------------------------------------------------------- */ - - private fun serializeBlockBody(expression: IrBlockBody): KonanIr.IrBlockBody { - val proto = KonanIr.IrBlockBody.newBuilder() - expression.statements.forEach { - proto.addStatement(serializeStatement(it)) - } - return proto.build() - } - - private fun serializeBranch(branch: IrBranch): KonanIr.IrBranch { - val proto = KonanIr.IrBranch.newBuilder() - - proto.condition = serializeExpression(branch.condition) - proto.result = serializeExpression(branch.result) - - return proto.build() - } - - private fun serializeBlock(block: IrBlock): KonanIr.IrBlock { - val isLambdaOrigin = - block.origin == IrStatementOrigin.LAMBDA || - block.origin == IrStatementOrigin.ANONYMOUS_FUNCTION - val proto = KonanIr.IrBlock.newBuilder() - .setIsLambdaOrigin(isLambdaOrigin) - block.statements.forEach { - proto.addStatement(serializeStatement(it)) - } - return proto.build() - } - - private fun serializeComposite(composite: IrComposite): KonanIr.IrComposite { - val proto = KonanIr.IrComposite.newBuilder() - composite.statements.forEach { - proto.addStatement(serializeStatement(it)) - } - return proto.build() - } - - private fun serializeCatch(catch: IrCatch): KonanIr.IrCatch { - val proto = KonanIr.IrCatch.newBuilder() - .setCatchParameter(serializeDeclaration(catch.catchParameter)) - .setResult(serializeExpression(catch.result)) - return proto.build() - } - - private fun serializeStringConcat(expression: IrStringConcatenation): KonanIr.IrStringConcat { - val proto = KonanIr.IrStringConcat.newBuilder() - expression.arguments.forEach { - proto.addArgument(serializeExpression(it)) - } - return proto.build() - } - - private fun irCallToPrimitiveKind(call: IrCall): KonanIr.IrCall.Primitive = when (call) { - is IrNullaryPrimitiveImpl - -> KonanIr.IrCall.Primitive.NULLARY - is IrUnaryPrimitiveImpl - -> KonanIr.IrCall.Primitive.UNARY - is IrBinaryPrimitiveImpl - -> KonanIr.IrCall.Primitive.BINARY - else - -> KonanIr.IrCall.Primitive.NOT_PRIMITIVE - } - - private fun serializeMemberAccessCommon(call: IrMemberAccessExpression): KonanIr.MemberAccessCommon { - val proto = KonanIr.MemberAccessCommon.newBuilder() - if (call.extensionReceiver != null) { - proto.extensionReceiver = serializeExpression(call.extensionReceiver!!) - } - - if (call.dispatchReceiver != null) { - proto.dispatchReceiver = serializeExpression(call.dispatchReceiver!!) - } - proto.typeArguments = serializeTypeArguments(call) - - call.descriptor.valueParameters.forEach { - val actual = call.getValueArgument(it.index) - val argOrNull = KonanIr.NullableIrExpression.newBuilder() - if (actual == null) { - // Am I observing an IR generation regression? - // I see a lack of arg for an empty vararg, - // rather than an empty vararg node. - assert(it.varargElementType != null || it.hasDefaultValue()) - } else { - argOrNull.expression = serializeExpression(actual) - } - proto.addValueArgument(argOrNull) - } - return proto.build() - } - - private fun serializeCall(call: IrCall): KonanIr.IrCall { - val proto = KonanIr.IrCall.newBuilder() - - proto.kind = irCallToPrimitiveKind(call) - proto.descriptor = serializeDescriptor(call.descriptor) - - if (call.superQualifier != null) { - proto.`super` = serializeDescriptor(call.superQualifier!!) - } - proto.memberAccess = serializeMemberAccessCommon(call) - return proto.build() - } - - private fun serializeCallableReference(callable: IrCallableReference): KonanIr.IrCallableReference { - val proto = KonanIr.IrCallableReference.newBuilder() - .setDescriptor(serializeDescriptor(callable.descriptor)) - .setTypeArguments(serializeTypeArguments(callable)) - - return proto.build() - } - - private fun serializeClassReference(expression: IrClassReference): KonanIr.IrClassReference { - val proto = KonanIr.IrClassReference.newBuilder() - .setClassDescriptor(serializeDescriptor(expression.symbol.descriptor)) - return proto.build() - } - - private fun serializeConst(value: IrConst<*>): KonanIr.IrConst { - val proto = KonanIr.IrConst.newBuilder() - when (value.kind) { - IrConstKind.Null -> proto.`null` = true - IrConstKind.Boolean -> proto.boolean = value.value as Boolean - IrConstKind.Byte -> proto.byte = (value.value as Byte).toInt() - IrConstKind.Char -> proto.char = (value.value as Char).toInt() - IrConstKind.Short -> proto.short = (value.value as Short).toInt() - IrConstKind.Int -> proto.int = value.value as Int - IrConstKind.Long -> proto.long = value.value as Long - IrConstKind.String -> proto.string = value.value as String - IrConstKind.Float -> proto.float = value.value as Float - IrConstKind.Double -> proto.double = value.value as Double - else -> { - TODO("Const type serialization not implemented yet: ${ir2string(value)}") - } - } - return proto.build() - } - - private fun serializeDelegatingConstructorCall(call: IrDelegatingConstructorCall): KonanIr.IrDelegatingConstructorCall { - val proto = KonanIr.IrDelegatingConstructorCall.newBuilder() - .setDescriptor(serializeDescriptor(call.descriptor)) - .setMemberAccess(serializeMemberAccessCommon(call)) - return proto.build() - } - - private fun serializeDoWhile(expression: IrDoWhileLoop): KonanIr.IrDoWhile { - val proto = KonanIr.IrDoWhile.newBuilder() - .setLoop(serializeLoop(expression)) - - return proto.build() - } - - fun serializeEnumConstructorCall(call: IrEnumConstructorCall): KonanIr.IrEnumConstructorCall { - val proto = KonanIr.IrEnumConstructorCall.newBuilder() - .setDescriptor(serializeDescriptor(call.descriptor)) - .setMemberAccess(serializeMemberAccessCommon(call)) - return proto.build() - } - - private fun serializeGetClass(expression: IrGetClass): KonanIr.IrGetClass { - val proto = KonanIr.IrGetClass.newBuilder() - .setArgument(serializeExpression(expression.argument)) - return proto.build() - } - - private fun serializeGetEnumValue(expression: IrGetEnumValue): KonanIr.IrGetEnumValue { - val proto = KonanIr.IrGetEnumValue.newBuilder() - .setType(serializeKotlinType(expression.type)) - .setDescriptor(serializeDescriptor(expression.descriptor)) - return proto.build() - } - - private fun serializeFieldAccessCommon(expression: IrFieldAccessExpression): KonanIr.FieldAccessCommon { - val proto = KonanIr.FieldAccessCommon.newBuilder() - .setDescriptor(serializeDescriptor(expression.descriptor)) - val superQualifier = expression.superQualifier - if (superQualifier != null) - proto.`super` = serializeDescriptor(superQualifier) - val receiver = expression.receiver - if (receiver != null) - proto.receiver = serializeExpression(receiver) - return proto.build() - } - - private fun serializeGetField(expression: IrGetField): KonanIr.IrGetField { - val proto = KonanIr.IrGetField.newBuilder() - .setFieldAccess(serializeFieldAccessCommon(expression)) - return proto.build() - } - - private fun serializeGetValue(expression: IrGetValue): KonanIr.IrGetValue { - val proto = KonanIr.IrGetValue.newBuilder() - .setDescriptor(serializeDescriptor(expression.descriptor)) - return proto.build() - } - - private fun serializeGetObject(expression: IrGetObjectValue): KonanIr.IrGetObject { - val proto = KonanIr.IrGetObject.newBuilder() - .setDescriptor(serializeDescriptor(expression.descriptor)) - return proto.build() - } - - private fun serializeInstanceInitializerCall(call: IrInstanceInitializerCall): KonanIr.IrInstanceInitializerCall { - val proto = KonanIr.IrInstanceInitializerCall.newBuilder() - - proto.descriptor = serializeDescriptor(call.classDescriptor) - - return proto.build() - } - - private fun serializeReturn(expression: IrReturn): KonanIr.IrReturn { - val proto = KonanIr.IrReturn.newBuilder() - .setReturnTarget(serializeDescriptor(expression.returnTarget)) - .setValue(serializeExpression(expression.value)) - return proto.build() - } - - private fun serializeSetField(expression: IrSetField): KonanIr.IrSetField { - val proto = KonanIr.IrSetField.newBuilder() - .setFieldAccess(serializeFieldAccessCommon(expression)) - .setValue(serializeExpression(expression.value)) - return proto.build() - } - - private fun serializeSetVariable(expression: IrSetVariable): KonanIr.IrSetVariable { - val proto = KonanIr.IrSetVariable.newBuilder() - .setDescriptor(serializeDescriptor(expression.descriptor)) - .setValue(serializeExpression(expression.value)) - return proto.build() - } - - private fun serializeSpreadElement(element: IrSpreadElement): KonanIr.IrSpreadElement { - val coordinates = serializeCoordinates(element.startOffset, element.endOffset) - return KonanIr.IrSpreadElement.newBuilder() - .setExpression(serializeExpression(element.expression)) - .setCoordinates(coordinates) - .build() - } - - private fun serializeThrow(expression: IrThrow): KonanIr.IrThrow { - val proto = KonanIr.IrThrow.newBuilder() - .setValue(serializeExpression(expression.value)) - return proto.build() - } - - private fun serializeTry(expression: IrTry): KonanIr.IrTry { - val proto = KonanIr.IrTry.newBuilder() - .setResult(serializeExpression(expression.tryResult)) - val catchList = expression.catches - catchList.forEach { - proto.addCatch(serializeStatement(it)) - } - val finallyExpression = expression.finallyExpression - if (finallyExpression != null) { - proto.finally = serializeExpression(finallyExpression) - } - return proto.build() - } - - private fun serializeTypeOperator(operator: IrTypeOperator): KonanIr.IrTypeOperator = when (operator) { - IrTypeOperator.CAST - -> KonanIr.IrTypeOperator.CAST - IrTypeOperator.IMPLICIT_CAST - -> KonanIr.IrTypeOperator.IMPLICIT_CAST - IrTypeOperator.IMPLICIT_NOTNULL - -> KonanIr.IrTypeOperator.IMPLICIT_NOTNULL - IrTypeOperator.IMPLICIT_COERCION_TO_UNIT - -> KonanIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT - IrTypeOperator.SAFE_CAST - -> KonanIr.IrTypeOperator.SAFE_CAST - IrTypeOperator.INSTANCEOF - -> KonanIr.IrTypeOperator.INSTANCEOF - IrTypeOperator.NOT_INSTANCEOF - -> KonanIr.IrTypeOperator.NOT_INSTANCEOF - else -> TODO("Unknown type operator") - } - - private fun serializeTypeOp(expression: IrTypeOperatorCall): KonanIr.IrTypeOp { - val proto = KonanIr.IrTypeOp.newBuilder() - .setOperator(serializeTypeOperator(expression.operator)) - .setOperand(serializeKotlinType(expression.typeOperand)) - .setArgument(serializeExpression(expression.argument)) - return proto.build() - - } - - private fun serializeVararg(expression: IrVararg): KonanIr.IrVararg { - val proto = KonanIr.IrVararg.newBuilder() - .setElementType(serializeKotlinType(expression.varargElementType)) - expression.elements.forEach { - proto.addElement(serializeVarargElement(it)) - } - return proto.build() - } - - private fun serializeVarargElement(element: IrVarargElement): KonanIr.IrVarargElement { - val proto = KonanIr.IrVarargElement.newBuilder() - when (element) { - is IrExpression - -> proto.expression = serializeExpression(element) - is IrSpreadElement - -> proto.spreadElement = serializeSpreadElement(element) - else -> TODO("Unknown vararg element kind") - } - return proto.build() - } - - private fun serializeWhen(expression: IrWhen): KonanIr.IrWhen { - val proto = KonanIr.IrWhen.newBuilder() - - val branches = expression.branches - branches.forEach { - proto.addBranch(serializeStatement(it)) - } - - return proto.build() - } - - private fun serializeLoop(expression: IrLoop): KonanIr.Loop { - val proto = KonanIr.Loop.newBuilder() - .setCondition(serializeExpression(expression.condition)) - val label = expression.label - if (label != null) { - proto.label = label - } - - proto.loopId = currentLoopIndex - loopIndex[expression] = currentLoopIndex++ - - val body = expression.body - if (body != null) { - proto.body = serializeExpression(body) - } - - return proto.build() - } - - private fun serializeWhile(expression: IrWhileLoop): KonanIr.IrWhile { - val proto = KonanIr.IrWhile.newBuilder() - .setLoop(serializeLoop(expression)) - - return proto.build() - } - - private fun serializeBreak(expression: IrBreak): KonanIr.IrBreak { - val proto = KonanIr.IrBreak.newBuilder() - val label = expression.label - if (label != null) { - proto.label = label - } - val loopId = loopIndex[expression.loop]!! - proto.loopId = loopId - - return proto.build() - } - - private fun serializeContinue(expression: IrContinue): KonanIr.IrContinue { - val proto = KonanIr.IrContinue.newBuilder() - val label = expression.label - if (label != null) { - proto.label = label - } - val loopId = loopIndex[expression.loop]!! - proto.loopId = loopId - - return proto.build() - } - - private fun serializeExpression(expression: IrExpression): KonanIr.IrExpression { - context.log{"### serializing Expression: ${ir2string(expression)}"} - - val coordinates = serializeCoordinates(expression.startOffset, expression.endOffset) - val proto = KonanIr.IrExpression.newBuilder() - .setType(serializeKotlinType(expression.type)) - .setCoordinates(coordinates) - - val operationProto = KonanIr.IrOperation.newBuilder() - - when (expression) { - is IrBlock -> operationProto.block = serializeBlock(expression) - is IrBreak -> operationProto.`break` = serializeBreak(expression) - is IrClassReference - -> operationProto.classReference = serializeClassReference(expression) - is IrCall -> operationProto.call = serializeCall(expression) - is IrCallableReference - -> operationProto.callableReference = serializeCallableReference(expression) - is IrComposite -> operationProto.composite = serializeComposite(expression) - is IrConst<*> -> operationProto.const = serializeConst(expression) - is IrContinue -> operationProto.`continue` = serializeContinue(expression) - is IrDelegatingConstructorCall - -> operationProto.delegatingConstructorCall = serializeDelegatingConstructorCall(expression) - is IrDoWhileLoop -> operationProto.doWhile = serializeDoWhile(expression) - is IrGetClass -> operationProto.getClass = serializeGetClass(expression) - is IrGetField -> operationProto.getField = serializeGetField(expression) - is IrGetValue -> operationProto.getValue = serializeGetValue(expression) - is IrGetEnumValue - -> operationProto.getEnumValue = serializeGetEnumValue(expression) - is IrGetObjectValue - -> operationProto.getObject = serializeGetObject(expression) - is IrInstanceInitializerCall - -> operationProto.instanceInitializerCall = serializeInstanceInitializerCall(expression) - is IrReturn -> operationProto.`return` = serializeReturn(expression) - is IrSetField -> operationProto.setField = serializeSetField(expression) - is IrSetVariable -> operationProto.setVariable = serializeSetVariable(expression) - is IrStringConcatenation - -> operationProto.stringConcat = serializeStringConcat(expression) - is IrThrow -> operationProto.`throw` = serializeThrow(expression) - is IrTry -> operationProto.`try` = serializeTry(expression) - is IrTypeOperatorCall - -> operationProto.typeOp = serializeTypeOp(expression) - is IrVararg -> operationProto.vararg = serializeVararg(expression) - is IrWhen -> operationProto.`when` = serializeWhen(expression) - is IrWhileLoop -> operationProto.`while` = serializeWhile(expression) - else -> { - TODO("Expression serialization not implemented yet: ${ir2string(expression)}.") - } - } - proto.setOperation(operationProto) - - return proto.build() - } - - private fun serializeStatement(statement: IrElement): KonanIr.IrStatement { - context.log{"### serializing Statement: ${ir2string(statement)}"} - - val coordinates = serializeCoordinates(statement.startOffset, statement.endOffset) - val proto = KonanIr.IrStatement.newBuilder() - .setCoordinates(coordinates) - - when (statement) { - is IrDeclaration -> proto.declaration = serializeDeclaration(statement) - is IrExpression -> proto.expression = serializeExpression(statement) - is IrBlockBody -> proto.blockBody = serializeBlockBody(statement) - is IrBranch -> proto.branch = serializeBranch(statement) - is IrCatch -> proto.catch = serializeCatch(statement) - else -> { - TODO("Statement not implemented yet: ${ir2string(statement)}") - } - } - return proto.build() - } - - private fun serializeIrFunction(function: IrFunction): KonanIr.IrFunction { - val proto = KonanIr.IrFunction.newBuilder() - val body = function.body - if (body != null) proto.body = serializeStatement(body) - - function.descriptor.valueParameters.forEachIndexed { index, it -> - val default = function.getDefault(it) - if (default != null) { - val pair = KonanIr.IrFunction.DefaultArgument.newBuilder() - pair.position = index - pair.value = serializeExpression(default.expression) - proto.addDefaultArgument(pair) - } - } - return proto.build() - } - - private fun serializeIrProperty(property: IrProperty): KonanIr.IrProperty { - val proto = KonanIr.IrProperty.newBuilder() - .setIsDelegated(property.isDelegated) - val backingField = property.backingField - val getter = property.getter - val setter = property.setter - if (backingField != null) - proto.backingField = serializeIrField(backingField) - if (getter != null) - proto.getter = serializeIrFunction(getter) - if (setter != null) - proto.setter = serializeIrFunction(setter) - - return proto.build() - } - - private fun serializeIrField(field: IrField): KonanIr.IrProperty.IrField { - val proto = KonanIr.IrProperty.IrField.newBuilder() - val initializer = field.initializer?.expression - if (initializer != null) { - proto.initializer = serializeExpression(initializer) - } - return proto.build() - } - - private fun serializeIrVariable(variable: IrVariable): KonanIr.IrVar { - val proto = KonanIr.IrVar.newBuilder() - val initializer = variable.initializer - if (initializer != null) { - proto.initializer = serializeExpression(initializer) - } - return proto.build() - } - - private fun serializeIrClass(@Suppress("UNUSED_PARAMETER") clazz: IrClass): KonanIr.IrClass { - val proto = KonanIr.IrClass.newBuilder() - - // TODO: As of now we get here only for anonymous local objects. - // There is still some work needed to support them. - // Until it is done, let's pretend all IrClasses are empty. - // So that we don't have to deal with their type tables. - /* - val declarations = clazz.declarations - declarations.forEach { - val descriptor = it.descriptor - if (descriptor !is CallableMemberDescriptor || descriptor.kind.isReal) { - proto.addMember(serializeDeclaration(it)) - } - } - */ - return proto.build() - } - - private fun serializeIrEnumEntry(enumEntry: IrEnumEntry): KonanIr.IrEnumEntry { - val proto = KonanIr.IrEnumEntry.newBuilder() - val initializer = enumEntry.initializerExpression!! - proto.initializer = serializeExpression(initializer) - val correspondingClass = enumEntry.correspondingClass - if (correspondingClass != null) { - proto.correspondingClass = serializeDeclaration(correspondingClass) - } - return proto.build() - } - - private fun serializeDeclaration(declaration: IrDeclaration): KonanIr.IrDeclaration { - context.log{"### serializing Declaration: ${ir2string(declaration)}"} - - val descriptor = declaration.descriptor - - if (descriptor != rootFunction && - declaration !is IrVariable) { - localDeclarationSerializer.pushContext(descriptor) - } - - var kotlinDescriptor = serializeDescriptor(descriptor) - var realDescriptor: KonanIr.DeclarationDescriptor? = null - if (descriptor != rootFunction) { - realDescriptor = localDeclarationSerializer.serializeLocalDeclaration(descriptor) - } - val declarator = KonanIr.IrDeclarator.newBuilder() - - when (declaration) { - is IrFunction - -> declarator.function = serializeIrFunction(declaration) - is IrVariable - -> declarator.variable = serializeIrVariable(declaration) - is IrClass - -> declarator.irClass = serializeIrClass(declaration) - is IrEnumEntry - -> declarator.irEnumEntry = serializeIrEnumEntry(declaration) - is IrProperty - -> declarator.irProperty = serializeIrProperty(declaration) - else - -> { - TODO("Declaration serialization not supported yet: $declaration") - } - } - - if (declaration !is IrVariable) { - localDeclarationSerializer.popContext() - } - - if (descriptor != rootFunction) { - val localDeclaration = KonanIr.LocalDeclaration - .newBuilder() - .setDescriptor(realDescriptor!!) - .build() - kotlinDescriptor = kotlinDescriptor - .toBuilder() - .setIrLocalDeclaration(localDeclaration) - .build() - } - - val coordinates = serializeCoordinates(declaration.startOffset, declaration.endOffset) - val proto = KonanIr.IrDeclaration.newBuilder() - //.setKind(declaration.irKind()) - .setDescriptor(kotlinDescriptor) - .setCoordinates(coordinates) - - - proto.setDeclarator(declarator) - val fileName = context.ir.originalModuleIndex.declarationToFile[declaration.descriptor] - proto.fileName = fileName - - return proto.build() - } - - private fun encodeDeclaration(declaration: IrDeclaration): String { - val proto = serializeDeclaration(declaration) - val byteArray = proto.toByteArray() - return base64Encode(byteArray) - } - - -} - -// --------- Deserializer part ----------------------------- - -internal class IrDeserializer(val context: Context, - private val rootFunction: FunctionDescriptor) { - - private val loopIndex = mutableMapOf() - - private val rootMember = rootFunction.deserializedPropertyIfAccessor - private val localDeserializer = LocalDeclarationDeserializer(rootMember) - - private val descriptorDeserializer = IrDescriptorDeserializer( - context, rootMember, localDeserializer) - - private fun deserializeKotlinType(proto: KonanIr.KotlinType) - = descriptorDeserializer.deserializeKotlinType(proto) - - private fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor) - = descriptorDeserializer.deserializeDescriptor(proto) - - private fun deserializeTypeArguments(proto: KonanIr.TypeArguments): List { - context.log{"### deserializeTypeArguments"} - val result = mutableListOf() - proto.typeArgumentList.forEach { type -> - val kotlinType = deserializeKotlinType(type) - result.add(kotlinType.brokenIr) - context.log{"$kotlinType"} - } - return result - } - - private fun deserializeBlockBody(proto: KonanIr.IrBlockBody, - start: Int, end: Int): IrBlockBody { - - val statements = mutableListOf() - - val statementProtos = proto.statementList - statementProtos.forEach { - statements.add(deserializeStatement(it) as IrStatement) - } - - return IrBlockBodyImpl(start, end, statements) - } - - private fun deserializeBranch(proto: KonanIr.IrBranch, start: Int, end: Int): IrBranch { - - val condition = deserializeExpression(proto.condition) - val result = deserializeExpression(proto.result) - - return IrBranchImpl(start, end, condition, result) - } - - private fun deserializeCatch(proto: KonanIr.IrCatch, start: Int, end: Int): IrCatch { - val catchParameter = deserializeDeclaration(proto.catchParameter) as IrVariable - val result = deserializeExpression(proto.result) - - return IrCatchImpl(start, end, catchParameter, result) - } - - private fun deserializeStatement(proto: KonanIr.IrStatement): IrElement { - val start = proto.coordinates.startOffset - val end = proto.coordinates.endOffset - val element = when { - proto.hasBlockBody() - -> deserializeBlockBody(proto.blockBody, start, end) - proto.hasBranch() - -> deserializeBranch(proto.branch, start, end) - proto.hasCatch() - -> deserializeCatch(proto.catch, start, end) - proto.hasDeclaration() - -> deserializeDeclaration(proto.declaration) - proto.hasExpression() - -> deserializeExpression(proto.expression) - else -> { - TODO("Statement deserialization not implemented") - } - } - - context.log{"### Deserialized statement: ${ir2string(element)}"} - - return element - } - - private val KotlinType.ir: IrType get() = context.ir.translateErased(this) - private val KotlinType.brokenIr: IrType get() = context.ir.translateBroken(this) - - private fun deserializeBlock(proto: KonanIr.IrBlock, start: Int, end: Int, type: KotlinType): IrBlock { - val statements = mutableListOf() - val statementProtos = proto.statementList - statementProtos.forEach { - statements.add(deserializeStatement(it) as IrStatement) - } - - val isLambdaOrigin = if (proto.isLambdaOrigin) IrStatementOrigin.LAMBDA else null - - return IrBlockImpl(start, end, type.ir, isLambdaOrigin, statements) - } - - private fun deserializeMemberAccessCommon(access: IrMemberAccessExpression, proto: KonanIr.MemberAccessCommon) { - - proto.valueArgumentList.mapIndexed { i, arg -> - val exprOrNull = if (arg.hasExpression()) - deserializeExpression(arg.expression) - else null - access.putValueArgument(i, exprOrNull) - } - - deserializeTypeArguments(proto.typeArguments).forEachIndexed { index, type -> - access.putTypeArgument(index, type) - } - - if (proto.hasDispatchReceiver()) { - access.dispatchReceiver = deserializeExpression(proto.dispatchReceiver) - } - if (proto.hasExtensionReceiver()) { - access.extensionReceiver = deserializeExpression(proto.extensionReceiver) - } - } - - private fun deserializeClassReference(proto: KonanIr.IrClassReference, start: Int, end: Int, type: KotlinType): IrClassReference { - val descriptor = deserializeDescriptor(proto.classDescriptor) as ClassifierDescriptor - /** TODO: [createClassifierSymbolForClassReference] is internal function */ - @Suppress("DEPRECATION") - return IrClassReferenceImpl(start, end, type.ir, descriptor, descriptor.defaultType.ir) - } - - private fun deserializeCall(proto: KonanIr.IrCall, start: Int, end: Int, type: KotlinType): IrCall { - val descriptor = deserializeDescriptor(proto.descriptor) as FunctionDescriptor - - val superDescriptor = if (proto.hasSuper()) { - deserializeDescriptor(proto.`super`) as ClassDescriptor - } else null - - val call: IrCall = when (proto.kind) { - KonanIr.IrCall.Primitive.NOT_PRIMITIVE -> - // TODO: implement the last three args here. - IrCallImpl(start, end, type.ir, createFunctionSymbol(descriptor), descriptor, proto.memberAccess.typeArguments.typeArgumentCount, null, createClassSymbolOrNull(superDescriptor)) - KonanIr.IrCall.Primitive.NULLARY -> - IrNullaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor)) - KonanIr.IrCall.Primitive.UNARY -> - IrUnaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor)) - KonanIr.IrCall.Primitive.BINARY -> - IrBinaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor)) - else -> TODO("Unexpected primitive IrCall.") - } - deserializeMemberAccessCommon(call, proto.memberAccess) - return call - } - - private fun deserializeCallableReference(proto: KonanIr.IrCallableReference, - start: Int, end: Int, type: KotlinType): IrCallableReference { - - val descriptor = deserializeDescriptor(proto.descriptor) as CallableDescriptor - val callable = when (descriptor) { - is FunctionDescriptor -> IrFunctionReferenceImpl(start, end, type.ir, createFunctionSymbol(descriptor), descriptor, proto.typeArguments.typeArgumentCount, null) - else -> TODO() - } - - deserializeTypeArguments(proto.typeArguments).forEachIndexed { index, argType -> - callable.putTypeArgument(index, argType) - } - return callable - } - - private fun deserializeComposite(proto: KonanIr.IrComposite, start: Int, end: Int, type: KotlinType): IrComposite { - val statements = mutableListOf() - val statementProtos = proto.statementList - statementProtos.forEach { - statements.add(deserializeStatement(it) as IrStatement) - } - return IrCompositeImpl(start, end, type.ir, null, statements) - } - - private fun deserializeDelegatingConstructorCall(proto: KonanIr.IrDelegatingConstructorCall, start: Int, end: Int): IrDelegatingConstructorCall { - val descriptor = deserializeDescriptor(proto.descriptor) as ClassConstructorDescriptor - val call = IrDelegatingConstructorCallImpl(start, end, context.irBuiltIns.unitType, IrConstructorSymbolImpl(descriptor.original), descriptor, proto.memberAccess.typeArguments.typeArgumentCount) - - deserializeMemberAccessCommon(call, proto.memberAccess) - return call - } - - private fun deserializeGetClass(proto: KonanIr.IrGetClass, start: Int, end: Int, type: KotlinType): IrGetClass { - val argument = deserializeExpression(proto.argument) - return IrGetClassImpl(start, end, type.ir, argument) - } - - private fun deserializeGetField(proto: KonanIr.IrGetField, start: Int, end: Int): IrGetField { - val access = proto.fieldAccess - val descriptor = deserializeDescriptor(access.descriptor) as PropertyDescriptor - val superQualifier = if (access.hasSuper()) { - deserializeDescriptor(access.descriptor) as ClassDescriptor - } else null - val receiver = if (access.hasReceiver()) { - deserializeExpression(access.receiver) - } else null - - return IrGetFieldImpl(start, end, IrFieldSymbolImpl(descriptor), descriptor.type.ir, receiver, null, createClassSymbolOrNull(superQualifier)) - } - - private fun deserializeGetValue(proto: KonanIr.IrGetValue, start: Int, end: Int): IrGetValue { - val descriptor = deserializeDescriptor(proto.descriptor) as ValueDescriptor - - // TODO: origin! - return IrGetValueImpl(start, end, descriptor.type.ir, createValueSymbol(descriptor), null) - } - - private fun deserializeGetEnumValue(proto: KonanIr.IrGetEnumValue, start: Int, end: Int): IrGetEnumValue { - val type = deserializeKotlinType(proto.type) - val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor - - return IrGetEnumValueImpl(start, end, type.ir, IrEnumEntrySymbolImpl(descriptor)) - } - - private fun deserializeGetObject(proto: KonanIr.IrGetObject, start: Int, end: Int, type: KotlinType): IrGetObjectValue { - val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor - return IrGetObjectValueImpl(start, end, type.ir, IrClassSymbolImpl(descriptor)) - } - - private fun deserializeInstanceInitializerCall(proto: KonanIr.IrInstanceInitializerCall, start: Int, end: Int): IrInstanceInitializerCall { - val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor - - return IrInstanceInitializerCallImpl(start, end, IrClassSymbolImpl(descriptor), context.irBuiltIns.unitType) - } - - private fun deserializeReturn(proto: KonanIr.IrReturn, start: Int, end: Int, type: KotlinType): IrReturn { - val descriptor = - deserializeDescriptor(proto.returnTarget) as FunctionDescriptor - val value = deserializeExpression(proto.value) - return IrReturnImpl(start, end, context.irBuiltIns.nothingType, createFunctionSymbol(descriptor), value) - } - - private fun deserializeSetField(proto: KonanIr.IrSetField, start: Int, end: Int): IrSetField { - val access = proto.fieldAccess - val descriptor = deserializeDescriptor(access.descriptor) as PropertyDescriptor - val superQualifier = if (access.hasSuper()) { - deserializeDescriptor(access.descriptor) as ClassDescriptor - } else null - val receiver = if (access.hasReceiver()) { - deserializeExpression(access.receiver) - } else null - val value = deserializeExpression(proto.value) - - return IrSetFieldImpl(start, end, IrFieldSymbolImpl(descriptor), receiver, value, context.irBuiltIns.unitType, null, createClassSymbolOrNull(superQualifier)) - } - - private fun deserializeSetVariable(proto: KonanIr.IrSetVariable, start: Int, end: Int): IrSetVariable { - val descriptor = deserializeDescriptor(proto.descriptor) as VariableDescriptor - val value = deserializeExpression(proto.value) - return IrSetVariableImpl(start, end, context.irBuiltIns.unitType, IrVariableSymbolImpl(descriptor), value, null) - } - - private fun deserializeSpreadElement(proto: KonanIr.IrSpreadElement): IrSpreadElement { - val expression = deserializeExpression(proto.expression) - return IrSpreadElementImpl(proto.coordinates.startOffset, proto.coordinates.endOffset, expression) - } - - private fun deserializeStringConcat(proto: KonanIr.IrStringConcat, start: Int, end: Int, type: KotlinType): IrStringConcatenation { - val argumentProtos = proto.argumentList - val arguments = mutableListOf() - - argumentProtos.forEach { - arguments.add(deserializeExpression(it)) - } - return IrStringConcatenationImpl(start, end, type.ir, arguments) - } - - private fun deserializeThrow(proto: KonanIr.IrThrow, start: Int, end: Int, type: KotlinType): IrThrowImpl { - return IrThrowImpl(start, end, context.irBuiltIns.nothingType, deserializeExpression(proto.value)) - } - - private fun deserializeTry(proto: KonanIr.IrTry, start: Int, end: Int, type: KotlinType): IrTryImpl { - val result = deserializeExpression(proto.result) - val catches = mutableListOf() - proto.catchList.forEach { - catches.add(deserializeStatement(it) as IrCatch) - } - val finallyExpression = - if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null - return IrTryImpl(start, end, type.ir, result, catches, finallyExpression) - } - - private fun deserializeTypeOperator(operator: KonanIr.IrTypeOperator): IrTypeOperator { - when (operator) { - KonanIr.IrTypeOperator.CAST - -> return IrTypeOperator.CAST - KonanIr.IrTypeOperator.IMPLICIT_CAST - -> return IrTypeOperator.IMPLICIT_CAST - KonanIr.IrTypeOperator.IMPLICIT_NOTNULL - -> return IrTypeOperator.IMPLICIT_NOTNULL - KonanIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT - -> return IrTypeOperator.IMPLICIT_COERCION_TO_UNIT - KonanIr.IrTypeOperator.SAFE_CAST - -> return IrTypeOperator.SAFE_CAST - KonanIr.IrTypeOperator.INSTANCEOF - -> return IrTypeOperator.INSTANCEOF - KonanIr.IrTypeOperator.NOT_INSTANCEOF - -> return IrTypeOperator.NOT_INSTANCEOF - else -> TODO("Unknown type operator") - } - } - - private fun deserializeTypeOp(proto: KonanIr.IrTypeOp, start: Int, end: Int, type: KotlinType) : IrTypeOperatorCall { - val operator = deserializeTypeOperator(proto.operator) - val operand = deserializeKotlinType(proto.operand).brokenIr - val argument = deserializeExpression(proto.argument) - return IrTypeOperatorCallImpl(start, end, type.ir, operator, operand).apply { - this.argument = argument - this.typeOperandClassifier = operand.classifierOrFail - } - } - - private fun deserializeVararg(proto: KonanIr.IrVararg, start: Int, end: Int, type: KotlinType): IrVararg { - val elementType = deserializeKotlinType(proto.elementType) - - val elements = mutableListOf() - proto.elementList.forEach { - elements.add(deserializeVarargElement(it)) - } - return IrVarargImpl(start, end, type.ir, elementType.ir, elements) - } - - private fun deserializeVarargElement(element: KonanIr.IrVarargElement): IrVarargElement { - return when (element.varargElementCase) { - EXPRESSION - -> deserializeExpression(element.expression) - SPREAD_ELEMENT - -> deserializeSpreadElement(element.spreadElement) - else - -> TODO("Unexpected vararg element") - } - } - - private fun deserializeWhen(proto: KonanIr.IrWhen, start: Int, end: Int, type: KotlinType): IrWhen { - val branches = mutableListOf() - - proto.branchList.forEach { - branches.add(deserializeStatement(it) as IrBranch) - } - - // TODO: provide some origin! - return IrWhenImpl(start, end, type.ir, null, branches) - } - - private fun deserializeLoop(proto: KonanIr.Loop, loop: IrLoopBase): IrLoopBase { - val loopId = proto.loopId - loopIndex.getOrPut(loopId){loop} - - val label = if (proto.hasLabel()) proto.label else null - val body = if (proto.hasBody()) deserializeExpression(proto.body) else null - val condition = deserializeExpression(proto.condition) - - loop.label = label - loop.condition = condition - loop.body = body - - return loop - } - - private fun deserializeDoWhile(proto: KonanIr.IrDoWhile, start: Int, end: Int, type: KotlinType): IrDoWhileLoop { - // we create the loop before deserializing the body, so that - // IrBreak statements have something to put into 'loop' field. - val loop = IrDoWhileLoopImpl(start, end, type.ir, null) - deserializeLoop(proto.loop, loop) - return loop - } - - private fun deserializeWhile(proto: KonanIr.IrWhile, start: Int, end: Int, type: KotlinType): IrWhileLoop { - // we create the loop before deserializing the body, so that - // IrBreak statements have something to put into 'loop' field. - val loop = IrWhileLoopImpl(start, end, type.ir, null) - deserializeLoop(proto.loop, loop) - return loop - } - - private fun deserializeBreak(proto: KonanIr.IrBreak, start: Int, end: Int, type: KotlinType): IrBreak { - val label = if(proto.hasLabel()) proto.label else null - val loopId = proto.loopId - val loop = loopIndex[loopId]!! - val irBreak = IrBreakImpl(start, end, type.ir, loop) - irBreak.label = label - - return irBreak - } - - private fun deserializeContinue(proto: KonanIr.IrContinue, start: Int, end: Int, type: KotlinType): IrContinue { - val label = if(proto.hasLabel()) proto.label else null - val loopId = proto.loopId - val loop = loopIndex[loopId]!! - val irContinue = IrContinueImpl(start, end, type.ir, loop) - irContinue.label = label - - return irContinue - } - - private fun deserializeConst(proto: KonanIr.IrConst, start: Int, end: Int, type: KotlinType): IrExpression = - when(proto.valueCase) { - NULL - -> IrConstImpl.constNull(start, end, type.ir) - BOOLEAN - -> IrConstImpl.boolean(start, end, type.ir, proto.boolean) - BYTE - -> IrConstImpl.byte(start, end, type.ir, proto.byte.toByte()) - CHAR - -> IrConstImpl.char(start, end, type.ir, proto.char.toChar()) - SHORT - -> IrConstImpl.short(start, end, type.ir, proto.short.toShort()) - INT - -> IrConstImpl.int(start, end, type.ir, proto.int) - LONG - -> IrConstImpl.long(start, end, type.ir, proto.long) - STRING - -> IrConstImpl.string(start, end, type.ir, proto.string) - FLOAT - -> IrConstImpl.float(start, end, type.ir, proto.float) - DOUBLE - -> IrConstImpl.double(start, end, type.ir, proto.double) - else -> { - TODO("Not all const types have been implemented") - } - } - - private fun deserializeOperation(proto: KonanIr.IrOperation, start: Int, end: Int, type: KotlinType): IrExpression = - when (proto.operationCase) { - BLOCK - -> deserializeBlock(proto.block, start, end, type) - BREAK - -> deserializeBreak(proto.`break`, start, end, type) - CLASS_REFERENCE - -> deserializeClassReference(proto.classReference, start, end, type) - CALL - -> deserializeCall(proto.call, start, end, type) - CALLABLE_REFERENCE - -> deserializeCallableReference(proto.callableReference, start, end, type) - COMPOSITE - -> deserializeComposite(proto.composite, start, end, type) - CONST - -> deserializeConst(proto.const, start, end, type) - CONTINUE - -> deserializeContinue(proto.`continue`, start, end, type) - DELEGATING_CONSTRUCTOR_CALL - -> deserializeDelegatingConstructorCall(proto.delegatingConstructorCall, start, end) - DO_WHILE - -> deserializeDoWhile(proto.doWhile, start, end, type) - GET_ENUM_VALUE - -> deserializeGetEnumValue(proto.getEnumValue, start, end) - GET_CLASS - -> deserializeGetClass(proto.getClass, start, end, type) - GET_FIELD - -> deserializeGetField(proto.getField, start, end) - GET_OBJECT - -> deserializeGetObject(proto.getObject, start, end, type) - GET_VALUE - -> deserializeGetValue(proto.getValue, start, end) - INSTANCE_INITIALIZER_CALL - -> deserializeInstanceInitializerCall(proto.instanceInitializerCall, start, end) - RETURN - -> deserializeReturn(proto.`return`, start, end, type) - SET_FIELD - -> deserializeSetField(proto.setField, start, end) - SET_VARIABLE - -> deserializeSetVariable(proto.setVariable, start, end) - STRING_CONCAT - -> deserializeStringConcat(proto.stringConcat, start, end, type) - THROW - -> deserializeThrow(proto.`throw`, start, end, type) - TRY - -> deserializeTry(proto.`try`, start, end, type) - TYPE_OP - -> deserializeTypeOp(proto.typeOp, start, end, type) - VARARG - -> deserializeVararg(proto.vararg, start, end, type) - WHEN - -> deserializeWhen(proto.`when`, start, end, type) - WHILE - -> deserializeWhile(proto.`while`, start, end, type) - else -> { - TODO("Expression deserialization not implemented: ${proto.operationCase}") - } - } - - private fun deserializeExpression(proto: KonanIr.IrExpression): IrExpression { - val start = proto.coordinates.startOffset - val end = proto.coordinates.endOffset - val type = deserializeKotlinType(proto.type) - val operation = proto.operation - val expression = deserializeOperation(operation, start, end, type) - - context.log{"### Deserialized expression: ${ir2string(expression)}"} - return expression - } - - private fun deserializeIrClass(proto: KonanIr.IrClass, descriptor: ClassDescriptor, start: Int, end: Int, origin: IrDeclarationOrigin): IrClass { - val members = mutableListOf() - - proto.memberList.forEach { - members.add(deserializeDeclaration(it)) - } - - val clazz = IrClassImpl(start, end, origin, descriptor, members) - - val symbolTable = context.ir.symbols.symbolTable - clazz.createParameterDeclarations(symbolTable) - clazz.addFakeOverrides(symbolTable) - clazz.setSuperSymbols(symbolTable) - - return clazz - - } - - private fun deserializeIrFunction(proto: KonanIr.IrFunction, descriptor: FunctionDescriptor, - start: Int, end: Int, origin: IrDeclarationOrigin): IrFunction { - - val body = deserializeStatement(proto.body) - val function = IrFunctionImpl(start, end, origin, descriptor, descriptor.returnType!!.ir, body as IrBody) - - function.createParameterDeclarations(context.ir.symbols.symbolTable) - function.setOverrides(context.ir.symbols.symbolTable) - - proto.defaultArgumentList.forEach { - val expr = deserializeExpression(it.value) - - function.putDefault( - descriptor.valueParameters[it.position], - IrExpressionBodyImpl(start, end, expr)) - } - return function - } - - private fun deserializeIrVariable(proto: KonanIr.IrVar, descriptor: VariableDescriptor, - start: Int, end: Int, origin: IrDeclarationOrigin): IrVariable { - - val initializer = if (proto.hasInitializer()) { - deserializeExpression(proto.initializer) - } else null - - return IrVariableImpl(start, end, origin, descriptor, descriptor.type.ir, initializer) - } - - private fun deserializeIrEnumEntry(proto: KonanIr.IrEnumEntry, descriptor: ClassDescriptor, - start: Int, end: Int, origin: IrDeclarationOrigin): IrEnumEntry { - - val enumEntry = IrEnumEntryImpl(start, end, origin, descriptor) - if (proto.hasCorrespondingClass()) { - enumEntry.correspondingClass = deserializeDeclaration(proto.correspondingClass) as IrClass - } - enumEntry.initializerExpression = deserializeExpression(proto.initializer) - - return enumEntry - } - - private fun deserializeDeclaration(proto: KonanIr.IrDeclaration): IrDeclaration { - - val descriptor = deserializeDescriptor(proto.descriptor) - - if (descriptor !is VariableDescriptor && descriptor != rootFunction) - localDeserializer.pushContext(descriptor) - - val start = proto.coordinates.startOffset - val end = proto.coordinates.endOffset - val origin = DEFINED // TODO: retore the real origins - val declarator = proto.declarator - - val declaration: IrDeclaration = when { - declarator.hasIrClass() - -> deserializeIrClass(declarator.irClass, - descriptor as ClassDescriptor, start, end, origin) - declarator.hasFunction() - -> deserializeIrFunction(declarator.function, - descriptor as FunctionDescriptor, start, end, origin) - declarator.hasVariable() - -> deserializeIrVariable(declarator.variable, - descriptor as VariableDescriptor, start, end, origin) - declarator.hasIrEnumEntry() - -> deserializeIrEnumEntry(declarator.irEnumEntry, - descriptor as ClassDescriptor, start, end, origin) - else -> { - TODO("Declaration deserialization not implemented") - } - } - - val sourceFileName = proto.fileName - context.ir.originalModuleIndex.declarationToFile[declaration.descriptor.original] = sourceFileName - - if (!(descriptor is VariableDescriptor) && descriptor != rootFunction) - localDeserializer.popContext(descriptor) - context.log{"### Deserialized declaration: ${ir2string(declaration)}"} - return declaration - } - - // We run inline body deserializations after the public descriptor tree - // deserialization is long gone. So we don't have the needed chain of - // deserialization contexts available to take type parameters. - // So typeDeserializer introduces a brand new set of DeserializadTypeParameterDescriptors - // for the rootFunction. - // This function takes the type parameters from the rootFunction descriptor - // and substitutes them instead the deserialized ones. - // TODO: consider lazy inline body deserialization during the public descriptors deserialization. - // I tried to copy over TypeDeserializaer, MemberDeserializer, - // and the rest of what's needed, but it didn't work out. - private fun adaptDeserializedTypeParameters(declaration: IrDeclaration): IrDeclaration { - - val rootFunctionTypeParameters = - localDeserializer.typeDeserializer.ownTypeParameters - - val realTypeParameters = - rootFunction.deserializedPropertyIfAccessor.typeParameters - - val substitutionContext = rootFunctionTypeParameters.mapIndexed{ - index, param -> - Pair(param.typeConstructor, TypeProjectionImpl(realTypeParameters[index].defaultType)) - }.associate{ - (key,value) -> - key to value} - - return DeepCopyIrTreeWithDescriptors(rootFunction, rootFunction.parents.first(), context, - TypeSubstitutor.create(substitutionContext) - ).copy(declaration) as IrFunction - } - - private val extractInlineProto: KonanProtoBuf.InlineIrBody - get() = when (rootFunction) { - is DeserializedSimpleFunctionDescriptor -> { - rootFunction.proto.inlineIr - } - is DeserializedClassConstructorDescriptor -> { - rootFunction.proto.constructorIr - } - is PropertyGetterDescriptor -> { - (rootMember as DeserializedPropertyDescriptor).proto.getterIr - } - is PropertySetterDescriptor -> { - (rootMember as DeserializedPropertyDescriptor).proto.setterIr - } - else -> error("Unexpected descriptor: $rootFunction") - } - - fun decodeDeclaration(): IrDeclaration { - assert(rootFunction.isDeserializableCallable) - - val inlineProto = extractInlineProto - val base64 = inlineProto.encodedIr - val byteArray = base64Decode(base64) - val irProto = KonanIr.IrDeclaration.parseFrom(byteArray, KonanSerializerProtocol.extensionRegistry) - val declaration = deserializeDeclaration(irProto) - - return adaptDeserializedTypeParameters(declaration) - } -} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/UniqId.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/UniqId.kt new file mode 100644 index 00000000000..d40ebd6411a --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/UniqId.kt @@ -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 > M.tryGetExtension(extension: GeneratedMessageLite.GeneratedExtension) + = if (this.hasExtension(extension)) this.getExtension(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() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/UniqSymbolName.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/UniqSymbolName.kt new file mode 100644 index 00000000000..a9a262ebc18 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/UniqSymbolName.kt @@ -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 . +private val IrFunction.uniqFunctionName: String + get() { + val parent = this.parent + + val containingDeclarationPart = parent.fqNameUnique.let { + if (it.isRoot) "" else "$it." + } + + return "kfun:$containingDeclarationPart#$functionName" + } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt index f2e79eda583..661a781b90c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt @@ -7,6 +7,10 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.descriptors.* +import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.WrappedPropertyDescriptor +import org.jetbrains.kotlin.backend.common.descriptors.substitute import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.KonanCompilationException @@ -30,6 +34,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl @@ -40,6 +45,9 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid +import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver import org.jetbrains.kotlin.types.* @@ -619,7 +627,12 @@ fun createField( } fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { - assert(this.descriptor.type == newDescriptor.type) + // Aggressive use of WrappedDescriptors during deserialization + // makes these types different. + // Let's hope they not really used afterwards. + //assert(this.descriptor.type == newDescriptor.type) { + // "type1 = ${this.descriptor.type} != type2 = ${newDescriptor.type}" + //} return IrValueParameterImpl( startOffset, @@ -637,7 +650,7 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean get() = this is IrSimpleType && this.hasQuestionMark fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) = - if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType + if (hasQuestionMark) this.defaultType.makeNullable(false) else this.defaultType fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean = this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 45716906eef..4aa3631a569 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -3109,7 +3109,6 @@ task library_mismatch(type: RunStandaloneKonanTest) { doFirst { def konancScript = isWindows() ? "konanc.bat" : "konanc" def konanc = "$dist/bin/$konancScript" - "$konanc $lib -p library -o $dir/1.2/empty -target $currentTarget -lv 1.2".execute().waitFor() "$konanc $lib -p library -o $dir/3.4/empty -target $someOtherTarget".execute().waitFor() "$konanc $lib -p library -o $dir/5.6/empty -target $currentTarget -lv 5.6".execute().waitFor() diff --git a/build.gradle b/build.gradle index 4558012c848..6e301df5bdf 100644 --- a/build.gradle +++ b/build.gradle @@ -397,7 +397,10 @@ task bundle(type: (isWindows()) ? Zip : Tar) { } destinationDir = file('.') - if (!isWindows()) { + + if (isWindows()) { + zip64 true + } else { extension = 'tar.gz' compression = Compression.GZIP } diff --git a/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy b/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy index c07001d95a6..5126842091a 100644 --- a/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy +++ b/buildSrc/plugins/src/main/groovy/org/jetbrains/kotlin/KonanTest.groovy @@ -100,7 +100,7 @@ abstract class KonanTest extends JavaExec { classpath = project.fileTree("$dist.canonicalPath/konan/lib/") { include '*.jar' } - jvmArgs "-Dkonan.home=${dist.canonicalPath}", "-Xmx2G", + jvmArgs "-Dkonan.home=${dist.canonicalPath}", "-Xmx4G", "-Djava.library.path=${dist.canonicalPath}/konan/nativelib" enableAssertions = true def sources = File.createTempFile(name,".lst") diff --git a/extracted/konan.metadata/src/KonanProtoBuf.proto b/extracted/konan.metadata/src/KonanProtoBuf.proto index 7863aa9ee5e..98bcbebf982 100644 --- a/extracted/konan.metadata/src/KonanProtoBuf.proto +++ b/extracted/konan.metadata/src/KonanProtoBuf.proto @@ -16,23 +16,30 @@ option optimize_for = LITE_RUNTIME; // Konan extensions to the "descriptors" protobuf. +message DescriptorUniqId { + required int64 index = 1; +} + extend Package { optional int32 package_fq_name = 171; } extend Class { repeated Annotation class_annotation = 170; + optional DescriptorUniqId class_uniq_id = 171; } extend Constructor { repeated Annotation constructor_annotation = 170; optional InlineIrBody inline_constructor_ir_body = 171; + optional DescriptorUniqId constructor_uniq_id = 172; } extend Function { repeated Annotation function_annotation = 170; optional InlineIrBody inline_ir_body = 171; optional int32 function_file = 172; + optional DescriptorUniqId function_uniq_id = 173; } extend Property { @@ -45,15 +52,18 @@ extend Property { optional InlineIrBody inline_getter_ir_body = 174; optional InlineIrBody inline_setter_ir_body = 175; optional int32 property_file = 176; + optional DescriptorUniqId property_uniq_id = 179; } extend EnumEntry { repeated Annotation enum_entry_annotation = 170; optional int32 enum_entry_ordinal = 171; + optional DescriptorUniqId enum_entry_uniq_id = 172; } extend ValueParameter { repeated Annotation parameter_annotation = 170; + optional DescriptorUniqId value_param_uniq_id = 171; } extend Type { @@ -63,6 +73,7 @@ extend Type { extend TypeParameter { repeated Annotation type_parameter_annotation = 170; + optional DescriptorUniqId type_param_uniq_id = 171; } message InlineIrBody { diff --git a/extracted/konan.serializer/src/org/jetbrains/kotlin/konan/library/resolver/impl/KonanLibraryResolverImpl.kt b/extracted/konan.serializer/src/org/jetbrains/kotlin/konan/library/resolver/impl/KonanLibraryResolverImpl.kt index e337374bce3..39205f93a3e 100644 --- a/extracted/konan.serializer/src/org/jetbrains/kotlin/konan/library/resolver/impl/KonanLibraryResolverImpl.kt +++ b/extracted/konan.serializer/src/org/jetbrains/kotlin/konan/library/resolver/impl/KonanLibraryResolverImpl.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.jetbrains.kotlin.konan.library.resolver.impl import org.jetbrains.kotlin.konan.file.File diff --git a/extracted/konan.serializer/src/org/jetbrains/kotlin/serialization/konan/impl/KonanDeserializedModuleDescriptorFactoryImpl.kt b/extracted/konan.serializer/src/org/jetbrains/kotlin/serialization/konan/impl/KonanDeserializedModuleDescriptorFactoryImpl.kt index 35e1f209dee..76265f298c2 100644 --- a/extracted/konan.serializer/src/org/jetbrains/kotlin/serialization/konan/impl/KonanDeserializedModuleDescriptorFactoryImpl.kt +++ b/extracted/konan.serializer/src/org/jetbrains/kotlin/serialization/konan/impl/KonanDeserializedModuleDescriptorFactoryImpl.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.konan.library.KonanLibrary +import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration diff --git a/gradle.properties b/gradle.properties index 1dcf5c2cb11..36c38283031 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,3 +24,4 @@ testKotlinVersion=1.3.30-dev-964 konanVersion=1.2.0 org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.workers.max=4 +#kotlinProjectPath=/Users/jetbrains/kotlin-native/kotlin diff --git a/platformLibs/src/platform/ios/CoreAudioKit.def b/platformLibs/src/platform/ios/CoreAudioKit.def index 85d80c2aad4..a35b5a514b2 100644 --- a/platformLibs/src/platform/ios/CoreAudioKit.def +++ b/platformLibs/src/platform/ios/CoreAudioKit.def @@ -1,4 +1,4 @@ -depends = AudioToolbox CFNetwork CoreAudio CoreFoundation CoreGraphics CoreImage CoreText CoreVideo EAGL FileProvider Foundation IOSurface ImageIO Metal OpenGLESCommon QuartzCore Security UIKit darwin posix +depends = AudioToolbox CFNetwork CoreAudio CoreFoundation CoreGraphics CoreImage CoreMIDI CoreText CoreVideo EAGL FileProvider Foundation IOSurface ImageIO Metal OpenGLESCommon QuartzCore Security UIKit darwin posix language = Objective-C package = platform.CoreAudioKit headers = CoreAudioKit/CoreAudioKit.h diff --git a/runtime/src/main/kotlin/kotlin/Array.kt b/runtime/src/main/kotlin/kotlin/Array.kt index 73ac3775d69..bc59788a580 100644 --- a/runtime/src/main/kotlin/kotlin/Array.kt +++ b/runtime/src/main/kotlin/kotlin/Array.kt @@ -33,6 +33,7 @@ public final class Array { } } + @PublishedApi @ExportForCompiler internal constructor(@Suppress("UNUSED_PARAMETER") size: Int) {} diff --git a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt index 8f159552c25..79d383128ed 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt @@ -117,9 +117,11 @@ fun > valuesForEnum(values: Array): Array { return result as Array } +@PublishedApi @TypedIntrinsic(IntrinsicType.CREATE_UNINITIALIZED_INSTANCE) internal external fun createUninitializedInstance(): T +@PublishedApi @TypedIntrinsic(IntrinsicType.INIT_INSTANCE) internal external fun initInstance(thiz: Any, constructorCall: Any): Unit @@ -157,4 +159,4 @@ internal fun listOfInternal(vararg elements: T): List { for (i in 0 until elements.size) result.add(elements[i]) return result -} \ No newline at end of file +} diff --git a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibrary.kt b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibrary.kt index f519d170979..45eddb08bc3 100644 --- a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibrary.kt +++ b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibrary.kt @@ -42,6 +42,9 @@ interface KonanLibrary { val moduleHeaderData: ByteArray fun packageMetadataParts(fqName: String): Set fun packageMetadata(fqName: String, partName: String): ByteArray + + val irHeader: ByteArray + fun irDeclaration(index: Long, isLocal: Boolean): ByteArray } val KonanLibrary.uniqueName diff --git a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibraryLayout.kt b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibraryLayout.kt index ad8fb71f9e0..e89148167a7 100644 --- a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibraryLayout.kt +++ b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanLibraryLayout.kt @@ -44,4 +44,15 @@ interface KonanLibraryLayout { fun packageFragmentFile(packageFqName: String, partName: String) = File(packageFragmentsDir(packageFqName), "$partName$KLIB_METADATA_FILE_EXTENSION_WITH_DOT") + val irDir + get() = File(libDir, "ir") + fun hiddenDeclarationFile(declarationId: String) + = File(irDir, "hidden_$declarationId.knd") + fun visibleDeclarationFile(declarationId: String) + = File(irDir, "visible_$declarationId.knd") + val wholeIrFile + get() = File(irDir, "irHeaders.kni") + val irIndex: File + get() = File(irDir, "uniqIdTableDump.txt") + } diff --git a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanMetadataReader.kt b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanMetadataReader.kt index 57ae74f6e12..5d06e01cf4a 100644 --- a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanMetadataReader.kt +++ b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/KonanMetadataReader.kt @@ -3,4 +3,6 @@ package org.jetbrains.kotlin.konan.library interface MetadataReader { fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray + fun loadWholeIr(libraryLayout: KonanLibraryLayout): ByteArray + fun loadIrDeclaraton(libraryLayout: KonanLibraryLayout, index: Long, isLocal: Boolean): ByteArray } diff --git a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/DefaultMetadataReaderImpl.kt b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/DefaultMetadataReaderImpl.kt index f45a60f3272..65e56d4eef2 100644 --- a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/DefaultMetadataReaderImpl.kt +++ b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/DefaultMetadataReaderImpl.kt @@ -10,4 +10,16 @@ internal object DefaultMetadataReaderImpl : MetadataReader { override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray = libraryLayout.packageFragmentFile(fqName, partName).readBytes() + + override fun loadWholeIr(libraryLayout: KonanLibraryLayout): ByteArray = + libraryLayout.wholeIrFile.readBytes() + + override fun loadIrDeclaraton(libraryLayout: KonanLibraryLayout, index: Long, isLocal: Boolean): ByteArray { + val name = index.toULong().toString(16) + val file = if (isLocal) + libraryLayout.hiddenDeclarationFile(name) + else + libraryLayout.visibleDeclarationFile(name) + return file.readBytes() + } } diff --git a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/KonanLibraryImpl.kt b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/KonanLibraryImpl.kt index e50dc59d570..8c3b2095a6d 100644 --- a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/KonanLibraryImpl.kt +++ b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/impl/KonanLibraryImpl.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.jetbrains.kotlin.konan.library.impl import org.jetbrains.kotlin.konan.file.File @@ -9,7 +25,6 @@ import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions import org.jetbrains.kotlin.konan.util.substitute - class KonanLibraryImpl( override val libraryFile: File, internal val target: KonanTarget?, @@ -69,5 +84,9 @@ class KonanLibraryImpl( } } + override val irHeader: ByteArray by lazy { layout.inPlace { metadataReader.loadWholeIr(it) }} + + override fun irDeclaration(index: Long, isLocal: Boolean) = layout.inPlace { metadataReader.loadIrDeclaraton(it, index, isLocal) } + override fun toString() = "$libraryName[default=$isDefault]" -} \ No newline at end of file +} diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/Util.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/Util.kt index 4abc80480ff..d3f8d6bab50 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/Util.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/util/Util.kt @@ -20,11 +20,13 @@ import kotlin.system.measureTimeMillis import org.jetbrains.kotlin.konan.file.* // FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function: -fun printMillisec(message: String, body: () -> Unit) { +fun printMillisec(message: String, body: () -> T): T { + var result: T? = null val msec = measureTimeMillis{ - body() + result = body() } println("$message: $msec msec") + return result!! } // FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function: