From 98ad71fc1186175fcfc36b6f6ae3db09f3818ccd Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Fri, 20 Mar 2020 18:13:21 +0300 Subject: [PATCH] [KLIB] Make K/N work with new linker (cherry picked from commit 19a301ee517ad89e82e4b65347a6ff112042e781) --- ...BuiltInFictitiousFunctionIrClassFactory.kt | 225 ++++++++++++---- .../kotlin/backend/konan/ToplevelPhases.kt | 62 +++-- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 8 +- .../interop/DescriptorToIrTranslationUtils.kt | 14 +- .../IrProviderForCEnumAndCStructStubs.kt | 100 +++---- .../DescriptorByIdSignatureFinder.kt | 66 ----- .../konan/serialization/KonanIrlinker.kt | 244 +++++++++++------- 7 files changed, 404 insertions(+), 315 deletions(-) delete mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorByIdSignatureFinder.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt index 69294fba725..5a950e5f41d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt @@ -12,16 +12,24 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.* +import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol +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.IrPropertySymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.defaultType -import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl -import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.types.impl.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.OperatorNameConventions internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS") @@ -30,10 +38,12 @@ internal class BuiltInFictitiousFunctionIrClassFactory( var symbolTable: SymbolTable?, private val irBuiltIns: IrBuiltIns, private val reflectionTypes: KonanReflectionTypes -) : IrProvider { +) : IrAbstractFunctionFactory(), IrProvider { override fun getDeclaration(symbol: IrSymbol) = - (symbol.descriptor as? FunctionClassDescriptor)?.let { buildClass(it) } + (symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor -> + buildClass(descriptor) { declareClass(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, descriptor) } + } var module: IrModuleFragment? = null set(value) { @@ -43,7 +53,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory( error("Module has already been set") field = value value.files += filesMap.values - builtClasses.forEach { it.addFakeOverrides() } +// builtClasses.forEach { it.addFakeOverrides() } } class FunctionalInterface(val irClass: IrClass, val arity: Int) @@ -51,17 +61,36 @@ internal class BuiltInFictitiousFunctionIrClassFactory( fun buildAllClasses() { val maxArity = 255 // See [BuiltInFictitiousFunctionClassFactory]. (0 .. maxArity).forEach { arity -> - function(arity) - kFunction(arity) - suspendFunction(arity) - kSuspendFunction(arity) + functionN(arity) + kFunctionN(arity) + suspendFunctionN(arity) + kSuspendFunctionN(arity) } } - fun function(n: Int) = buildClass(irBuiltIns.builtIns.getFunction(n) as FunctionClassDescriptor) - fun kFunction(n: Int) = buildClass(reflectionTypes.getKFunction(n) as FunctionClassDescriptor) - fun suspendFunction(n: Int) = buildClass(irBuiltIns.builtIns.getSuspendFunction(n) as FunctionClassDescriptor) - fun kSuspendFunction(n: Int) = buildClass(reflectionTypes.getKSuspendFunction(n) as FunctionClassDescriptor) + override fun functionClassDescriptor(arity: Int): FunctionClassDescriptor = + irBuiltIns.builtIns.getFunction(arity) as FunctionClassDescriptor + + override fun kFunctionClassDescriptor(arity: Int): FunctionClassDescriptor = + reflectionTypes.getKFunction(arity) as FunctionClassDescriptor + + override fun suspendFunctionClassDescriptor(arity: Int): FunctionClassDescriptor = + irBuiltIns.builtIns.getSuspendFunction(arity) as FunctionClassDescriptor + + override fun kSuspendFunctionClassDescriptor(arity: Int): FunctionClassDescriptor = + reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor + + override fun functionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + buildClass(irBuiltIns.builtIns.getFunction(arity) as FunctionClassDescriptor, declarator) + + override fun kFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + buildClass(reflectionTypes.getKFunction(arity) as FunctionClassDescriptor, declarator) + + override fun suspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + buildClass(irBuiltIns.builtIns.getSuspendFunction(arity) as FunctionClassDescriptor, declarator) + + override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + buildClass(reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor, declarator) private val functionSymbol = symbolTable!!.referenceClass( irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies( @@ -112,19 +141,16 @@ internal class BuiltInFictitiousFunctionIrClassFactory( returnType ) - private fun createClass(descriptor: FunctionClassDescriptor) = - symbolTable?.declareClass( - SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, DECLARATION_ORIGIN_FUNCTION_CLASS, - descriptor - ) - ?: IrClassImpl( - SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, DECLARATION_ORIGIN_FUNCTION_CLASS, - IrClassSymbolImpl(descriptor) - ) + private val createClassLambda = + { s: IrClassSymbol -> IrClassImpl(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, s) } - private fun buildClass(descriptor: FunctionClassDescriptor): IrClass = + private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass { + return symbolTable?.declarator(createClassLambda) ?: createClassLambda(IrClassSymbolImpl(descriptor)) + } + + private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = builtClassesMap.getOrPut(descriptor) { - createClass(descriptor).apply { + createClass(descriptor, declarator).apply { val functionClass = this typeParameters += descriptor.declaredTypeParameters.map { typeParameterDescriptor -> createTypeParameter(typeParameterDescriptor).also { @@ -142,7 +168,9 @@ internal class BuiltInFictitiousFunctionIrClassFactory( makeTypeProjection(argumentClassifierSymbol.defaultType, argument.projectionKind) } val superTypeSymbol = when (val superTypeDescriptor = superType.constructor.declarationDescriptor) { - is FunctionClassDescriptor -> buildClass(superTypeDescriptor).symbol + is FunctionClassDescriptor -> buildClass(superTypeDescriptor) { + declareClass(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, superTypeDescriptor) + }.symbol functionSymbol.descriptor -> functionSymbol kFunctionSymbol.descriptor -> kFunctionSymbol else -> error("Unexpected super type: $superTypeDescriptor") @@ -155,40 +183,42 @@ internal class BuiltInFictitiousFunctionIrClassFactory( val invokeFunctionDescriptor = descriptor.unsubstitutedMemberScope.getContributedFunctions( OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).single() val isFakeOverride = invokeFunctionDescriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE - val invokeFunctionOrigin = - if (isFakeOverride) - IrDeclarationOrigin.FAKE_OVERRIDE - else - DECLARATION_ORIGIN_FUNCTION_CLASS - declarations += createSimpleFunction( - invokeFunctionDescriptor, invokeFunctionOrigin, - typeParameters.last().defaultType - ).apply { - parent = functionClass - valueParameters += invokeFunctionDescriptor.valueParameters.map { - IrValueParameterImpl( - SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, - invokeFunctionOrigin, - it, - functionClass.typeParameters[it.index].defaultType, - null - ).also { it.parent = this } - } - if (!isFakeOverride) - createDispatchReceiverParameter(invokeFunctionOrigin) - else { - val overriddenFunction = superTypes - .mapNotNull { it.classOrNull?.owner } - .single { it.descriptor is FunctionClassDescriptor } - .simpleFunctions() - .single { it.name == OperatorNameConventions.INVOKE } - overriddenSymbols += overriddenFunction.symbol - dispatchReceiverParameter = overriddenFunction.dispatchReceiverParameter?.copyTo(this) + if (!isFakeOverride) { + val invokeFunctionOrigin = + if (isFakeOverride) + IrDeclarationOrigin.FAKE_OVERRIDE + else + DECLARATION_ORIGIN_FUNCTION_CLASS + declarations += createSimpleFunction( + invokeFunctionDescriptor, invokeFunctionOrigin, + typeParameters.last().defaultType + ).apply { + parent = functionClass + valueParameters += invokeFunctionDescriptor.valueParameters.map { + IrValueParameterImpl( + SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, + invokeFunctionOrigin, + it, + functionClass.typeParameters[it.index].defaultType, + null + ).also { it.parent = this } + } + if (!isFakeOverride) + createDispatchReceiverParameter(invokeFunctionOrigin) + else { + val overriddenFunction = superTypes + .mapNotNull { it.classOrNull?.owner } + .single { it.descriptor is FunctionClassDescriptor } + .simpleFunctions() + .single { it.name == OperatorNameConventions.INVOKE } + overriddenSymbols += overriddenFunction.symbol + dispatchReceiverParameter = overriddenFunction.dispatchReceiverParameter?.copyTo(this) + } } } // Unfortunately, addFakeOverrides() uses some parents but they are only set after PsiToIr phase. // So we add all the fake overrides only when we're supplied with the module (this is done after PsiToIr). - if (this@BuiltInFictitiousFunctionIrClassFactory.module != null) +// if (this@BuiltInFictitiousFunctionIrClassFactory.module != null) addFakeOverrides() val packageFragmentDescriptor = descriptor.findPackage() @@ -201,4 +231,89 @@ internal class BuiltInFictitiousFunctionIrClassFactory( file.declarations += this } } + + private fun toIrType(wrapped: KotlinType): IrType { + val kotlinType = wrapped.unwrap() + return with(IrSimpleTypeBuilder()) { + classifier = + symbolTable?.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType")) + hasQuestionMark = kotlinType.isMarkedNullable + arguments = kotlinType.arguments.map { + if (it.isStarProjection) IrStarProjectionImpl + else makeTypeProjection(toIrType(it.type), it.projectionKind) + } + buildSimpleType() + } + } + + private fun IrFunction.createValueParameter(descriptor: ParameterDescriptor): IrValueParameter { + val symbol = IrValueParameterSymbolImpl(descriptor) + val varargType = if (descriptor is ValueParameterDescriptor) descriptor.varargElementType else null + return IrValueParameterImpl( + offset, + offset, + memberOrigin, + symbol, + toIrType(descriptor.type), + varargType?.let { toIrType(it) }).also { + it.parent = this + } + } + + private fun IrClass.addFakeOverrides() { + + val fakeOverrideDescriptors = descriptor.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.CALLABLES) + .filterIsInstance().filter { it.kind === CallableMemberDescriptor.Kind.FAKE_OVERRIDE } + + fun createFakeOverrideFunction(descriptor: FunctionDescriptor, property: IrPropertySymbol?): IrSimpleFunction { + val returnType = descriptor.returnType?.let { toIrType(it) } ?: error("No return type for $descriptor") + + + val functionDeclare = { s: IrSimpleFunctionSymbol -> + descriptor.run { + IrFunctionImpl( + offset, offset, memberOrigin, s, name, visibility, modality, returnType, + isInline, isExternal, isTailrec, isSuspend, isOperator, isExpect, true + ) + } + } + + val newFunction = symbolTable?.declareSimpleFunction(offset, offset, memberOrigin, descriptor, functionDeclare) + ?: functionDeclare(IrSimpleFunctionSymbolImpl(descriptor)) + + newFunction.parent = this + newFunction.overriddenSymbols = descriptor.overriddenDescriptors.mapNotNull { symbolTable?.referenceSimpleFunction(it.original) } + newFunction.dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.let { newFunction.createValueParameter(it) } + newFunction.extensionReceiverParameter = descriptor.extensionReceiverParameter?.let { newFunction.createValueParameter(it) } + newFunction.valueParameters = descriptor.valueParameters.map { newFunction.createValueParameter(it) } + newFunction.correspondingPropertySymbol = property + + return newFunction + } + + fun createFakeOverrideProperty(descriptor: PropertyDescriptor): IrProperty { + val propertyDeclare = { s: IrPropertySymbol -> + IrPropertyImpl(offset, offset, memberOrigin, s, descriptor.name) + } + val property = symbolTable?.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare) + ?: propertyDeclare(IrPropertySymbolImpl(descriptor)) + + property.parent = this + property.getter = descriptor.getter?.let { g -> createFakeOverrideFunction(g, property.symbol) } + property.setter = descriptor.setter?.let { s -> createFakeOverrideFunction(s, property.symbol) } + + return property + } + + + fun createFakeOverride(descriptor: CallableMemberDescriptor): IrDeclaration { + return when (descriptor) { + is FunctionDescriptor -> createFakeOverrideFunction(descriptor, null) + is PropertyDescriptor -> createFakeOverrideProperty(descriptor) + else -> error("Unexpected member $descriptor") + } + } + + declarations += fakeOverrideDescriptors.map { createFakeOverride(it) } + } } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index edc65c50c92..482af532187 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMo import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary -import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForInteropStubs import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs import org.jetbrains.kotlin.backend.konan.llvm.* @@ -21,6 +20,8 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin +import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment @@ -144,8 +145,9 @@ internal val psiToIrPhase = konanUnitPhase( Psi2IrConfiguration(false), KonanIdSignaturer(KonanManglerDesc)) val generatorContext = translator.createGeneratorContext(moduleDescriptor, bindingContext, symbolTable) + val pluginExtensions = IrGenerationExtension.getInstances(config.project) + translator.addPostprocessingStep { module -> - val extensions = IrGenerationExtension.getInstances(config.project) val pluginContext = IrPluginContext( generatorContext.moduleDescriptor, generatorContext.bindingContext, @@ -154,7 +156,7 @@ internal val psiToIrPhase = konanUnitPhase( generatorContext.typeTranslator, generatorContext.irBuiltIns ) - extensions.forEach { extension -> + pluginExtensions.forEach { extension -> extension.generate(module, pluginContext) } } @@ -167,12 +169,25 @@ internal val psiToIrPhase = konanUnitPhase( // Note: using [llvmModuleSpecification] since this phase produces IR for generating single LLVM module. val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct() + val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory( + symbolTable, generatorContext.irBuiltIns, reflectionTypes) + val stubGenerator = DeclarationStubGenerator( + moduleDescriptor, symbolTable, + config.configuration.languageVersionSettings + ) + val symbols = KonanSymbols(this, symbolTable, symbolTable.lazyWrapper, functionIrClassFactory) + + val irProviderForCEnumsAndCStructs = + IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, symbols) val deserializer = KonanIrLinker( moduleDescriptor, + functionIrClassFactory, this as LoggingContext, generatorContext.irBuiltIns, symbolTable, forwardDeclarationsModuleDescriptor, + stubGenerator, + irProviderForCEnumsAndCStructs, exportedDependencies ) @@ -190,40 +205,22 @@ internal val psiToIrPhase = konanUnitPhase( } for (dependency in sortDependencies(dependencies)) { - deserializer.deserializeIrModuleHeader(dependency) + val kotlinLibrary = dependency.getCapability(KlibModuleOrigin.CAPABILITY)?.let { + (it as? DeserializedKlibModuleOrigin)?.library + } + deserializer.deserializeIrModuleHeader(dependency, kotlinLibrary) } if (dependencies.size == dependenciesCount) break dependenciesCount = dependencies.size } - deserializer.initializeExpectActualLinker() - - val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory( - symbolTable, generatorContext.irBuiltIns, reflectionTypes) - val symbols = KonanSymbols(this, symbolTable, symbolTable.lazyWrapper, functionIrClassFactory) - val stubGenerator = DeclarationStubGenerator( - moduleDescriptor, symbolTable, - config.configuration.languageVersionSettings - ) - val irProviderForCEnumsAndCStructs = IrProviderForCEnumAndCStructStubs( - generatorContext, interopBuiltIns, symbols, llvmModuleSpecification::containsModule - ) // We need to run `buildAllEnumsAndStructsFrom` before `generateModuleFragment` because it adds references to symbolTable // that should be bound. modulesWithoutDCE .filter(ModuleDescriptor::isFromInteropLibrary) - .forEach(irProviderForCEnumsAndCStructs::buildAllEnumsAndStructsFrom) - val irProviderForInteropStubs = IrProviderForInteropStubs( - stubGenerator, - irProviderForCEnumsAndCStructs::canHandleSymbol - ) - val irProviders = listOf( - irProviderForCEnumsAndCStructs, - irProviderForInteropStubs, - functionIrClassFactory, - deserializer, - stubGenerator - ) + .forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom) + + val irProviders = listOf(deserializer) stubGenerator.setIrProviders(irProviders) expectDescriptorToSymbol = mutableMapOf() @@ -238,14 +235,16 @@ internal val psiToIrPhase = konanUnitPhase( if (expectActualLinker) expectDescriptorToSymbol else null ) - deserializer.finalizeExpectActualLinker() + deserializer.postProcess() if (this.stdlibModule in modulesWithoutDCE) { functionIrClassFactory.buildAllClasses() } - module.acceptVoid(ManglerChecker(KonanManglerIr, Ir2DescriptorManglerAdapter(KonanManglerDesc))) - module.files += irProviderForCEnumsAndCStructs.outputFiles + // Enable lazy IR genration for newly-created symbols inside BE + stubGenerator.unboundSymbolGeneration = true + + module.acceptVoid(ManglerChecker(KonanManglerIr, Ir2DescriptorManglerAdapter(KonanManglerDesc))) irModule = module irModules = deserializer.modules.filterValues { llvmModuleSpecification.containsModule(it) } @@ -263,7 +262,6 @@ internal val psiToIrPhase = konanUnitPhase( internal val destroySymbolTablePhase = konanUnitPhase( op = { this.symbolTable = null // TODO: invalidate symbolTable itself. - ir.symbols.functionIrClassFactory.symbolTable = null }, name = "DestroySymbolTable", description = "Destroy SymbolTable", 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 e7370b79d8e..84272493b85 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 @@ -514,13 +514,13 @@ internal class KonanSymbols( .getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND) as ClassDescriptor ) - override fun functionN(n: Int) = functionIrClassFactory.function(n).symbol + override fun functionN(n: Int) = functionIrClassFactory.functionN(n).symbol - override fun suspendFunctionN(n: Int) = functionIrClassFactory.suspendFunction(n).symbol + override fun suspendFunctionN(n: Int) = functionIrClassFactory.suspendFunctionN(n).symbol - fun kFunctionN(n: Int) = functionIrClassFactory.kFunction(n).symbol + fun kFunctionN(n: Int) = functionIrClassFactory.kFunctionN(n).symbol - fun kSuspendFunctionN(n: Int) = functionIrClassFactory.kSuspendFunction(n).symbol + fun kSuspendFunctionN(n: Int) = functionIrClassFactory.kSuspendFunctionN(n).symbol fun getKFunctionType(returnType: IrType, parameterTypes: List) = kFunctionN(parameterTypes.size).typeWith(parameterTypes + returnType) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt index ead36902614..1c7995944e7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/DescriptorToIrTranslationUtils.kt @@ -160,9 +160,10 @@ internal fun ClassDescriptor.inheritsFromCStructVar(interopBuiltIns: InteropBuil * CEnum inheritor. */ internal fun IrSymbol.findCEnumDescriptor(interopBuiltIns: InteropBuiltIns): ClassDescriptor? = - descriptor.parentsWithSelf - .filterIsInstance() - .firstOrNull { it.implementsCEnum(interopBuiltIns) } + descriptor.findCEnumDescriptor(interopBuiltIns) + +internal fun DeclarationDescriptor.findCEnumDescriptor(interopBuiltIns: InteropBuiltIns): ClassDescriptor? = + parentsWithSelf.filterIsInstance().firstOrNull { it.implementsCEnum(interopBuiltIns) } /** * All structs that come from interop library inherit from CStructVar class. @@ -170,6 +171,7 @@ internal fun IrSymbol.findCEnumDescriptor(interopBuiltIns: InteropBuiltIns): Cla * CStructVar inheritor. */ internal fun IrSymbol.findCStructDescriptor(interopBuiltIns: InteropBuiltIns): ClassDescriptor? = - descriptor.parentsWithSelf - .filterIsInstance() - .firstOrNull { it.inheritsFromCStructVar(interopBuiltIns) } \ No newline at end of file + descriptor.findCStructDescriptor(interopBuiltIns) + +internal fun DeclarationDescriptor.findCStructDescriptor(interopBuiltIns: InteropBuiltIns): ClassDescriptor? = + parentsWithSelf.filterIsInstance().firstOrNull { it.inheritsFromCStructVar(interopBuiltIns) } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt index 87fef4e423e..3b24ca60afc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/interop/IrProviderForCEnumAndCStructStubs.kt @@ -4,28 +4,20 @@ */ package org.jetbrains.kotlin.backend.konan.ir.interop +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData import org.jetbrains.kotlin.backend.konan.InteropBuiltIns -import org.jetbrains.kotlin.backend.konan.descriptors.findPackage import org.jetbrains.kotlin.backend.konan.descriptors.getPackageFragments -import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumByValueFunctionGenerator import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumClassGenerator import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumCompanionGenerator import org.jetbrains.kotlin.backend.konan.ir.interop.cenum.CEnumVarClassGenerator import org.jetbrains.kotlin.backend.konan.ir.interop.cstruct.CStructVarClassGenerator -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext -import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter /** @@ -38,23 +30,18 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter * compiler phases. * 2. It is an easier and more obvious approach. Since implementation of metadata-based * libraries generation already took too much time we take an easier approach here. - * - * [moduleFilter] -- We want to select modules that should be part of compiler's output. - * - * For example, when we generate compiler cache, - * declarations from dependencies should not be added to the current module. */ internal class IrProviderForCEnumAndCStructStubs( context: GeneratorContext, private val interopBuiltIns: InteropBuiltIns, - symbols: KonanSymbols, - private val moduleFilter: (ModuleDescriptor) -> Boolean -) : IrProvider { + symbols: KonanSymbols +) { + /** + * TODO: integrate this provider into [KonanIrLinker.KonanInteropModuleDeserializer] + */ private val symbolTable: SymbolTable = context.symbolTable - private val filesMap = mutableMapOf() - private val cEnumByValueFunctionGenerator = CEnumByValueFunctionGenerator(context, symbols) private val cEnumCompanionGenerator = @@ -66,60 +53,47 @@ internal class IrProviderForCEnumAndCStructStubs( private val cStructClassGenerator = CStructVarClassGenerator(context, interopBuiltIns) - /** - * The final output of this provider is a list of files which contain IR declarations - * of enums and structs that should be generated. - */ - val outputFiles: List - get() = filesMap.filterKeys { moduleFilter(it.module) }.values.toList() + fun isCEnumOrCStruct(declarationDescriptor: DeclarationDescriptor): Boolean = + declarationDescriptor.run { findCEnumDescriptor(interopBuiltIns) ?: findCStructDescriptor(interopBuiltIns) } != null - fun canHandleSymbol(symbol: IrSymbol): Boolean { - if (!symbol.isPublicApi) return false - if (symbol.signature.run { !IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() }) return false - return symbol.findCEnumDescriptor(interopBuiltIns) != null - || symbol.findCStructDescriptor(interopBuiltIns) != null - } - - fun buildAllEnumsAndStructsFrom(interopModule: ModuleDescriptor) = interopModule.getPackageFragments() + fun referenceAllEnumsAndStructsFrom(interopModule: ModuleDescriptor) = interopModule.getPackageFragments() .flatMap { it.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) } .filterIsInstance() - .forEach { - when { - it.implementsCEnum(interopBuiltIns) -> - cEnumClassGenerator.findOrGenerateCEnum(it, irParentFor(it)) - it.inheritsFromCStructVar(interopBuiltIns) -> - cStructClassGenerator.findOrGenerateCStruct(it, irParentFor(it)) - } - } + .filter { it.implementsCEnum(interopBuiltIns) || it.inheritsFromCStructVar(interopBuiltIns) } + .forEach { symbolTable.referenceClass(it) } - private fun generateIrIfNeeded(symbol: IrSymbol) { + private fun generateIrIfNeeded(symbol: IrSymbol, file: IrFile) { // TODO: These `findOrGenerate` calls generate a whole subtree. // This a simple but clearly suboptimal solution. symbol.findCEnumDescriptor(interopBuiltIns)?.let { enumDescriptor -> - cEnumClassGenerator.findOrGenerateCEnum(enumDescriptor, irParentFor(enumDescriptor)) + cEnumClassGenerator.findOrGenerateCEnum(enumDescriptor, file) } symbol.findCStructDescriptor(interopBuiltIns)?.let { structDescriptor -> - cStructClassGenerator.findOrGenerateCStruct(structDescriptor, irParentFor(structDescriptor)) + cStructClassGenerator.findOrGenerateCStruct(structDescriptor, file) } } - override fun getDeclaration(symbol: IrSymbol): IrDeclaration? { - if (symbol.isBound) return symbol.owner as IrDeclaration - if (!canHandleSymbol(symbol)) return null - generateIrIfNeeded(symbol) - return when (symbol) { - is IrClassSymbol -> symbolTable.referenceClass(symbol.descriptor).owner - is IrEnumEntrySymbol -> symbolTable.referenceEnumEntry(symbol.descriptor).owner - is IrFunctionSymbol -> symbolTable.referenceFunction(symbol.descriptor).owner - is IrPropertySymbol -> symbolTable.referenceProperty(symbol.descriptor).owner - else -> error(symbol) - } - } - - private fun irParentFor(descriptor: ClassDescriptor): IrDeclarationContainer { - val packageFragmentDescriptor = descriptor.findPackage() - return filesMap.getOrPut(packageFragmentDescriptor) { - IrFileImpl(NaiveSourceBasedFileEntryImpl(cTypeDefinitionsFileName), packageFragmentDescriptor) + fun getDeclaration(descriptor: DeclarationDescriptor, idSignature: IdSignature, file: IrFile, symbolKind: BinarySymbolData.SymbolKind): IrSymbolOwner { + return symbolTable.run { + when (symbolKind) { + BinarySymbolData.SymbolKind.CLASS_SYMBOL -> declareClassFromLinker(descriptor as ClassDescriptor, idSignature) { s -> + generateIrIfNeeded(s, file) + s.owner + } + BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> declareEnumEntryFromLinker(descriptor as ClassDescriptor, idSignature) { s -> + generateIrIfNeeded(s, file) + s.owner + } + BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> declareSimpleFunctionFromLinker(descriptor as FunctionDescriptor, idSignature) { s -> + generateIrIfNeeded(s, file) + s.owner + } + BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> declarePropertyFromLinker(descriptor as PropertyDescriptor, idSignature) { s -> + generateIrIfNeeded(s, file) + s.owner + } + else -> error("Unexpected symbol kind $symbolKind for sig $idSignature") + } } } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorByIdSignatureFinder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorByIdSignatureFinder.kt deleted file mode 100644 index fa164b488ca..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/DescriptorByIdSignatureFinder.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2010-2020 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.ir.util.IdSignature - -// The code here is intentionally copy-pasted from DeclarationStubGenerator with -// minor changes. -// "Find descriptor by IdSignature" task appears to be common and should be unified later. -class DescriptorByIdSignatureFinder( - private val moduleDescriptor: ModuleDescriptor -) { - fun findDescriptorBySignature(signature: IdSignature): DeclarationDescriptor? = when (signature) { - is IdSignature.AccessorSignature -> findDescriptorForAccessorSignature(signature) - is IdSignature.PublicSignature -> findDescriptorForPublicSignature(signature) - else -> error("only PublicSignature or AccessorSignature should reach this point, got $signature") - } - - private fun findDescriptorForAccessorSignature(signature: IdSignature.AccessorSignature): DeclarationDescriptor? { - val propertyDescriptor = findDescriptorBySignature(signature.propertySignature) as? PropertyDescriptor - ?: return null - return propertyDescriptor.accessors.singleOrNull { - it.name == signature.accessorSignature.declarationFqn.shortName() - } - } - - private fun findDescriptorForPublicSignature(signature: IdSignature.PublicSignature): DeclarationDescriptor? { - val packageDescriptor = moduleDescriptor.getPackage(signature.packageFqName()) - val pathSegments = signature.declarationFqn.pathSegments() - val toplevelDescriptors = packageDescriptor.memberScope.getContributedDescriptors { name -> name == pathSegments.first() } - .filter { it.name == pathSegments.first() } - val candidates = pathSegments.drop(1).fold(toplevelDescriptors) { acc, current -> - acc.flatMap { container -> - val classDescriptor = container as? ClassDescriptor - ?: return@flatMap emptyList() - val nextStepCandidates = classDescriptor.constructors + - classDescriptor.unsubstitutedMemberScope.getContributedDescriptors { name -> name == current } + - // Static scope is required only for Enum.values() and Enum.valueOf(). - classDescriptor.staticScope.getContributedDescriptors { name -> name == current } - nextStepCandidates.filter { it.name == current } - } - } - - return when (candidates.size) { - 1 -> candidates.first() - else -> { - findDescriptorByHash(candidates, signature.id) - ?: error("No descriptor found for $signature") - } - } - } - - private fun findDescriptorByHash(candidates: List, id: Long?): DeclarationDescriptor? = - candidates.firstOrNull { candidate -> - if (id == null) { - // We don't compute id for typealiases and classes. - candidate is ClassDescriptor || candidate is TypeAliasDescriptor - } else { - val candidateHash = with(KonanManglerDesc) { candidate.signatureMangle } - candidateHash == id - } - } -} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt index 091a43fa573..7e709e144db 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt @@ -18,123 +18,189 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.common.LoggingContext import org.jetbrains.kotlin.backend.common.serialization.* -import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData +import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib +import org.jetbrains.kotlin.descriptors.konan.kotlinLibrary +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl +import org.jetbrains.kotlin.ir.descriptors.IrAbstractFunctionFactory import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns -import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl -import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl -import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.library.IrLibrary +import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.module -class KonanIrLinker( - private val currentModule: ModuleDescriptor, - logger: LoggingContext, - builtIns: IrBuiltIns, - symbolTable: SymbolTable, - private val forwardModuleDescriptor: ModuleDescriptor?, - exportedDependencies: List -) : KotlinIrLinker(logger, builtIns, symbolTable, exportedDependencies, forwardModuleDescriptor) { - - private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder(currentModule) - - override fun reader(moduleDescriptor: ModuleDescriptor, fileIndex: Int, idSigIndex: Int) = - moduleDescriptor.konanLibrary!!.irDeclaration(idSigIndex, fileIndex) - - override fun readType(moduleDescriptor: ModuleDescriptor, fileIndex: Int, typeIndex: Int) = - moduleDescriptor.konanLibrary!!.type(typeIndex, fileIndex) - - override fun readSignature(moduleDescriptor: ModuleDescriptor, fileIndex: Int, signatureIndex: Int) = - moduleDescriptor.konanLibrary!!.signature(signatureIndex, fileIndex) - - override fun readString(moduleDescriptor: ModuleDescriptor, fileIndex: Int, stringIndex: Int) = - moduleDescriptor.konanLibrary!!.string(stringIndex, fileIndex) - - override fun readBody(moduleDescriptor: ModuleDescriptor, fileIndex: Int, bodyIndex: Int) = - moduleDescriptor.konanLibrary!!.body(bodyIndex, fileIndex) - - override fun readFile(moduleDescriptor: ModuleDescriptor, fileIndex: Int) = - moduleDescriptor.konanLibrary!!.file(fileIndex) - - override fun readFileCount(moduleDescriptor: ModuleDescriptor) = - moduleDescriptor.run { if (this === forwardModuleDescriptor || moduleDescriptor.isFromInteropLibrary()) 0 else konanLibrary!!.fileCount() } - - override fun handleNoModuleDeserializerFound(idSignature: IdSignature): DeserializationState<*> { - return globalDeserializationState - } +internal class KonanIrLinker( + private val currentModule: ModuleDescriptor, + override val functionalInteraceFactory: IrAbstractFunctionFactory, + logger: LoggingContext, + builtIns: IrBuiltIns, + symbolTable: SymbolTable, + private val forwardModuleDescriptor: ModuleDescriptor?, + private val stubGenerator: DeclarationStubGenerator, + private val cenumsProvider: IrProviderForCEnumAndCStructStubs, + exportedDependencies: List +) : KotlinIrLinker(currentModule, logger, builtIns, symbolTable, exportedDependencies) { companion object { private val C_NAMES_NAME = Name.identifier("cnames") private val OBJC_NAMES_NAME = Name.identifier("objcnames") + + val FORWARD_DECLARATION_ORIGIN = object : IrDeclarationOriginImpl("FORWARD_DECLARATION_ORIGIN") {} + + const val offset = SYNTHETIC_OFFSET } - override fun isSpecialPlatformSignature(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature() + override fun isBuiltInModule(moduleDescriptor: ModuleDescriptor): Boolean = moduleDescriptor.isNativeStdlib() - override fun postProcessPlatformSpecificDeclaration(idSig: IdSignature, descriptor: DeclarationDescriptor?, block: (IdSignature) -> Unit) { - if (descriptor == null) return + private val forwardDeclarationDeserializer = forwardModuleDescriptor?.let { KonanForwardDeclarationModuleDeserialier(it) } - if (!idSig.isForwardDeclarationSignature()) return - - val fqn = descriptor.fqNameSafe - if (!fqn.startsWith(C_NAMES_NAME) && !fqn.startsWith(OBJC_NAMES_NAME)) { - val signature = IdSignature.PublicSignature(fqn.parent(), FqName(fqn.shortName().asString()), null, 0) - block(signature) + override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary?, strategy: DeserializationStrategy): IrModuleDeserializer { + if (moduleDescriptor === forwardModuleDescriptor) { + return forwardDeclarationDeserializer ?: error("forward declaration deserializer expected") } + + if (klib is KotlinLibrary && klib.isInteropLibrary()) { + return KonanInteropModuleDeserializer(moduleDescriptor) + } + + return KonanModuleDeserializer(moduleDescriptor, klib ?: error("Expecting kotlin library"), strategy) } - override fun resolvePlatformDescriptor(idSig: IdSignature): DeclarationDescriptor? { - if (idSig.isInteropSignature()) { - return descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) + private inner class KonanModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary, strategy: DeserializationStrategy): + KotlinIrLinker.BasicIrModuleDeserializer(moduleDescriptor, klib, strategy) + + private inner class KonanInteropModuleDeserializer(moduleDescriptor: ModuleDescriptor) : IrModuleDeserializer(moduleDescriptor) { + init { + assert(moduleDescriptor.kotlinLibrary.isInteropLibrary()) } - if (!idSig.isForwardDeclarationSignature()) return null - val fwdModule = forwardModuleDescriptor ?: error("Forward declaration module should not be null") + private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder(moduleDescriptor, KonanManglerDesc) + private fun IdSignature.isInteropSignature(): Boolean = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() - return with(idSig as IdSignature.PublicSignature) { - val classId = ClassId(packageFqn, declarationFqn, false) - fwdModule.findClassAcrossModuleDependencies(classId) + override fun contains(idSig: IdSignature): Boolean { + + if (idSig.isPublic) { + if (idSig.isInteropSignature()) { + // TODO: add descriptor cache?? + return descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null + } + } + + return false } - } - private fun IdSignature.isInteropSignature(): Boolean = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() + private fun DeclarationDescriptor.isCEnumsOrCStruct(): Boolean = cenumsProvider.isCEnumOrCStruct(this) - private fun IdSignature.isForwardDeclarationSignature(): Boolean { - if (isPublic) { - return packageFqName().run { - startsWith(C_NAMES_NAME) || startsWith(OBJC_NAMES_NAME) + private val fileMap = mutableMapOf() + + private fun getIrFile(packageFragment: PackageFragmentDescriptor): IrFile = fileMap.getOrPut(packageFragment) { + IrFileImpl(NaiveSourceBasedFileEntryImpl(IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileName), packageFragment).also { + moduleFragment.files.add(it) } } - return false - } - - override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, strategy: DeserializationStrategy): IrModuleDeserializer { - return KonanModuleDeserializer(moduleDescriptor, strategy) - } - - private inner class KonanModuleDeserializer(moduleDescriptor: ModuleDescriptor, strategy: DeserializationStrategy): - IrModuleDeserializer(moduleDescriptor, strategy) - - /** - * If declaration is from interop library then IR for it is generated by IrProviderForInteropStubs. - */ - override fun IdSignature.shouldBeDeserialized(): Boolean = !isInteropSignature() && !isForwardDeclarationSignature() - - val modules: Map get() = mutableMapOf().apply { - deserializersForModules.filter { !it.key.isForwardDeclarationModule }.forEach { - this.put(it.key.konanLibrary!!.libraryName, it.value.module) + private fun resolveCEnumsOrStruct(descriptor: DeclarationDescriptor, idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + val file = getIrFile(descriptor.findPackage()) + return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol } + + override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) ?: error("Expecting descriptor for $idSig") + + if (descriptor.isCEnumsOrCStruct()) return resolveCEnumsOrStruct(descriptor, idSig, symbolKind) + + val symbolOwner = stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner + + return symbolOwner.symbol + } + + override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns) + override val moduleDependencies: Collection = listOfNotNull(forwardDeclarationDeserializer) } -} + + private inner class KonanForwardDeclarationModuleDeserialier(moduleDescriptor: ModuleDescriptor) : IrModuleDeserializer(moduleDescriptor) { + init { + assert(moduleDescriptor.isForwardDeclarationModule) + } + + private val declaredDeclaration = mutableMapOf() + private val packageToFileMap = mutableMapOf() + + private fun IdSignature.isForwardDeclarationSignature(): Boolean { + if (isPublic) { + return packageFqName().run { + startsWith(C_NAMES_NAME) || startsWith(OBJC_NAMES_NAME) + } + } + + return false + } + + override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature() + + private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor = + with(idSig as IdSignature.PublicSignature) { + val classId = ClassId(packageFqn, declarationFqn, false) + moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig") + } + + private fun getIrFile(packageFragment: PackageFragmentDescriptor): IrFile { + val fqn = packageFragment.fqName + return packageToFileMap.getOrPut(packageFragment.fqName) { + val fileSymbol = IrFileSymbolImpl(packageFragment) + IrFileImpl(NaiveSourceBasedFileEntryImpl("forward declarations for $fqn"), fileSymbol).also { + moduleFragment.files.add(it) + } + } + } + + private fun buildForwardDeclarationStub(idSig: IdSignature, descriptor: ClassDescriptor): IrClass { + val packageDescriptor = descriptor.containingDeclaration as PackageFragmentDescriptor + val irFile = getIrFile(packageDescriptor) + + val klass = symbolTable.declareClassFromLinker(descriptor, idSig) { s -> + IrClassImpl(offset, offset, FORWARD_DECLARATION_ORIGIN, s) + } + + klass.parent = irFile + irFile.declarations.add(klass) + + return klass + } + + override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + assert(symbolKind == BinarySymbolData.SymbolKind.CLASS_SYMBOL) { "Only class could be a Forward declaration $idSig (kind $symbolKind)" } + val descriptor = resolveDescriptor(idSig) + val actualModule = descriptor.module + if (actualModule !== moduleDescriptor) { + val moduleDeserializer = deserializersForModules[actualModule] ?: error("No module deserializer for $actualModule") + moduleDeserializer.addModuleReachableTopLevel(idSig) + return symbolTable.referenceClassFromLinker(descriptor, idSig) + } + + return declaredDeclaration.getOrPut(idSig) { buildForwardDeclarationStub(idSig, descriptor) }.symbol + } + + override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns) + override val moduleDependencies: Collection = emptyList() + } + + val modules: Map + get() = mutableMapOf().apply { + deserializersForModules + .filter { !it.key.isForwardDeclarationModule && it.value.moduleDescriptor !== currentModule } + .forEach { this.put(it.key.konanLibrary!!.libraryName, it.value.moduleFragment) } + } +} \ No newline at end of file