diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt index d4a938bb068..213d29e48fe 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/inline/FunctionInlining.kt @@ -182,7 +182,7 @@ class FunctionInlining( val statements = (copiedCallee.body as IrBlockBody).statements val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl() - val endOffset = callee.endOffset + val endOffset = statements.lastOrNull()?.endOffset ?: callee.endOffset /* creates irBuilder appending to the end of the given returnable block: thus why we initialize * irBuilder with (..., endOffset, endOffset). */ diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyClass.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyClass.kt index 902e7429782..a87968c7516 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyClass.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyClass.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.DeserializableClass import org.jetbrains.kotlin.ir.util.TypeTranslator +import org.jetbrains.kotlin.ir.util.isObject import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.NameResolver @@ -79,7 +80,8 @@ class IrLazyClass( private fun shouldBuildStub(descriptor: DeclarationDescriptor): Boolean = descriptor !is DeclarationDescriptorWithVisibility || - !DescriptorVisibilities.isPrivate(descriptor.visibility) + !DescriptorVisibilities.isPrivate(descriptor.visibility) || + isObject && descriptor is ClassConstructorDescriptor override var typeParameters: List by lazyVar(stubGenerator.lock) { descriptor.declaredTypeParameters.mapTo(arrayListOf()) { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyConstructor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyConstructor.kt index 1a833efa03d..f1c748d24a3 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyConstructor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyConstructor.kt @@ -7,11 +7,15 @@ package org.jetbrains.kotlin.ir.declarations.lazy import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.DescriptorVisibility +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.TypeTranslator @@ -20,6 +24,35 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource +@OptIn(ObsoleteDescriptorBasedAPI::class) +class IrLazyValueParameter( + override val startOffset: Int, + override val endOffset: Int, + override var origin: IrDeclarationOrigin, + override val symbol: IrValueParameterSymbol, + override val descriptor: ValueParameterDescriptor, + override val name: Name, + override val index: Int, + override var type: IrType, + override var varargElementType: IrType?, + override val isCrossinline: Boolean, + override val isNoinline: Boolean, + override val isHidden: Boolean, + override val isAssignable: Boolean, + override val stubGenerator: DeclarationStubGenerator, + override val typeTranslator: TypeTranslator, +) : IrValueParameter(), IrLazyDeclarationBase { + override lateinit var parent: IrDeclarationParent + + override var defaultValue: IrExpressionBody? = null + + override var annotations: List by createLazyAnnotations() + + init { + symbol.bind(this) + } +} + @OptIn(ObsoleteDescriptorBasedAPI::class) class IrLazyConstructor( override val startOffset: Int, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazySymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazySymbolTable.kt index 82e4343d6bc..cdfd9189632 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazySymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazySymbolTable.kt @@ -5,10 +5,7 @@ package org.jetbrains.kotlin.ir.declarations.lazy -import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrLock import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator @@ -32,6 +29,16 @@ class IrLazySymbolTable(private val originalTable: SymbolTable) : ReferenceSymbo } } + override fun referenceTypeAlias(descriptor: TypeAliasDescriptor): IrTypeAliasSymbol { + synchronized(lock) { + return originalTable.referenceTypeAlias(descriptor).also { + if (!it.isBound) { + stubGenerator?.generateTypeAliasStub(descriptor) + } + } + } + } + override fun referenceConstructor(descriptor: ClassConstructorDescriptor): IrConstructorSymbol { synchronized(lock) { return originalTable.referenceConstructor(descriptor).also { @@ -62,6 +69,16 @@ class IrLazySymbolTable(private val originalTable: SymbolTable) : ReferenceSymbo } } + override fun referenceProperty(descriptor: PropertyDescriptor): IrPropertySymbol { + synchronized(lock) { + return originalTable.referenceProperty(descriptor).also { + if (!it.isBound) { + stubGenerator?.generatePropertyStub(descriptor) + } + } + } + } + override fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol { synchronized(lock) { return originalTable.referenceTypeParameter(classifier).also { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt index 0eba2a78492..f4fd9b9820e 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner import org.jetbrains.kotlin.ir.symbols.IrFileSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol -import org.jetbrains.kotlin.ir.util.file +import org.jetbrains.kotlin.ir.util.fileOrNull import org.jetbrains.kotlin.ir.util.transformInPlace import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -58,6 +58,5 @@ abstract class IrReturnableBlock : IrBlock(), IrSymbolOwner, IrReturnTarget { abstract val inlineFunctionSymbol: IrFunctionSymbol? } -@Suppress("unused") // Used in kotlin-native val IrReturnableBlock.sourceFileSymbol: IrFileSymbol? - get() = inlineFunctionSymbol?.owner?.file?.symbol + get() = inlineFunctionSymbol?.owner?.fileOrNull?.symbol diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt index c69c335a896..6359178b114 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/overrides/IrOverridingUtil.kt @@ -66,7 +66,7 @@ fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, claz val typeParameters = extractTypeParameters(classifier.owner) val superArguments = superType.arguments - assert(typeParameters.size == superArguments.size) { + require(typeParameters.size == superArguments.size) { "typeParameters = $typeParameters size != typeArguments = $superArguments size " } @@ -76,7 +76,7 @@ fun buildFakeOverrideMember(superType: IrType, member: IrOverridableMember, claz val tp = typeParameters[i] val ta = superArguments[i] require(ta is IrTypeProjection) { "Unexpected super type argument: ${ta.render()} @ $i" } - assert(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" } + require(ta.variance == Variance.INVARIANT) { "Unexpected variance in super type argument: ${ta.variance} @$i" } substitutionMap[tp.symbol] = ta.type } @@ -414,7 +414,7 @@ class IrOverridingUtil( fakeOverride.overriddenSymbols = effectiveOverridden.map { it.original.symbol } - assert( + require( fakeOverride.overriddenSymbols.isNotEmpty() ) { "Overridden symbols should be set for " + CallableMemberDescriptor.Kind.FAKE_OVERRIDE } @@ -465,26 +465,24 @@ class IrOverridingUtil( val bReturnType = b.returnType if (!isVisibilityMoreSpecific(a, b)) return false if (a is IrSimpleFunction) { - assert(b is IrSimpleFunction) { "b is " + b.javaClass } + require(b is IrSimpleFunction) { "b is " + b.javaClass } return isReturnTypeMoreSpecific(a, aReturnType, b, bReturnType) } if (a is IrProperty) { - assert(b is IrProperty) { "b is " + b.javaClass } - val pa = a - val pb = b as IrProperty + require(b is IrProperty) { "b is " + b.javaClass } if (!isAccessorMoreSpecific( - pa.setter, - pb.setter + a.setter, + b.setter ) ) return false - return if (pa.isVar && pb.isVar) { + return if (a.isVar && b.isVar) { createTypeCheckerState( a.getter!!.typeParameters, b.getter!!.typeParameters ).equalTypes(aReturnType, bReturnType) } else { // both vals or var vs val: val can't be more specific then var - !(!pa.isVar && pb.isVar) && isReturnTypeMoreSpecific( + !(!a.isVar && b.isVar) && isReturnTypeMoreSpecific( a, aReturnType, b, bReturnType ) @@ -510,7 +508,7 @@ class IrOverridingUtil( private fun selectMostSpecificMember( overridables: Collection ): IrOverridableMember { - assert(!overridables.isEmpty()) { "Should have at least one overridable descriptor" } + require(!overridables.isEmpty()) { "Should have at least one overridable descriptor" } if (overridables.size == 1) { return overridables.first() } @@ -693,7 +691,7 @@ class IrOverridingUtil( } */ - assert(superValueParameters.size == subValueParameters.size) + require(superValueParameters.size == subValueParameters.size) superValueParameters.forEachIndexed { index, parameter -> if (!AbstractTypeChecker.equalTypes( diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt index 2e999c96029..e284d07275b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt @@ -235,10 +235,9 @@ abstract class DeclarationStubGenerator( private fun KotlinType.toIrType() = typeTranslator.translateType(this) internal fun generateValueParameterStub(descriptor: ValueParameterDescriptor): IrValueParameter = with(descriptor) { - symbolTable.irFactory.createValueParameter( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), name, index, type.toIrType(), - varargElementType?.toIrType(), isCrossinline, isNoinline, isHidden = false, isAssignable = false - ).also { irValueParameter -> + IrLazyValueParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, computeOrigin(this), IrValueParameterSymbolImpl(this), this, name, index, + type.toIrType(), varargElementType?.toIrType(), isCrossinline, isNoinline, isHidden = false, isAssignable = false, this@DeclarationStubGenerator, typeTranslator) + .also { irValueParameter -> if (descriptor.declaresDefaultValue()) { irValueParameter.defaultValue = irValueParameter.createStubDefaultValue() } @@ -304,7 +303,7 @@ abstract class DeclarationStubGenerator( } internal fun generateOrGetScopedTypeParameterStub(descriptor: TypeParameterDescriptor): IrTypeParameter { - val referenced = symbolTable.referenceTypeParameter(descriptor) + val referenced = symbolTable.referenceScopedTypeParameter(descriptor) if (referenced.isBound) { return referenced.owner } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index e3983043389..50806ac05e8 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -40,6 +40,7 @@ interface ReferenceSymbolTable { fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol fun referenceTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol + fun referenceScopedTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol fun referenceVariable(descriptor: VariableDescriptor): IrVariableSymbol fun referenceTypeAlias(descriptor: TypeAliasDescriptor): IrTypeAliasSymbol @@ -1030,6 +1031,11 @@ open class SymbolTable( createTypeParameterSymbol(classifier) } + override fun referenceScopedTypeParameter(classifier: TypeParameterDescriptor): IrTypeParameterSymbol = + scopedTypeParameterSymbolTable.referenced(classifier) { + createTypeParameterSymbol(classifier) + } + override fun referenceGlobalTypeParameterFromLinker(sig: IdSignature): IrTypeParameterSymbol { return globalTypeParameterSymbolTable.referenced(sig, false) { if (sig.isPubliclyVisible) IrTypeParameterPublicSymbolImpl(sig) else IrTypeParameterSymbolImpl() diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt index 18ab4ea3d14..f59ad2f01f3 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/BasicIrModuleDeserializer.kt @@ -35,7 +35,7 @@ abstract class BasicIrModuleDeserializer( private val moduleDeserializationState = ModuleDeserializationState(linker, this) - internal val moduleReversedFileIndex = mutableMapOf() + val moduleReversedFileIndex = mutableMapOf() override val moduleDependencies by lazy { moduleDescriptor.allDependencyModules.filter { it != moduleDescriptor }.map { linker.resolveModuleDeserializer(it, null) } @@ -110,6 +110,7 @@ abstract class BasicIrModuleDeserializer( val fileDeserializationState = FileDeserializationState( linker, + fileIndex, file, fileReader, fileProto, diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt index a602ba23966..8370b7f4242 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrFileDeserializer.kt @@ -57,8 +57,9 @@ class IrFileDeserializer( class FileDeserializationState( val linker: KotlinIrLinker, + val fileIndex: Int, file: IrFile, - fileReader: IrLibraryFileFromBytes, + val fileReader: IrLibraryFileFromBytes, fileProto: ProtoFile, deserializeBodies: Boolean, allowErrorNodes: Boolean, diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt index 9fadf090693..d5bc72e2561 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt @@ -22,6 +22,7 @@ internal fun IrSymbol.kind(): BinarySymbolData.SymbolKind { is IrPropertySymbol -> BinarySymbolData.SymbolKind.PROPERTY_SYMBOL is IrEnumEntrySymbol -> BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL is IrTypeAliasSymbol -> BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL + is IrTypeParameterSymbol -> BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL else -> error("Unexpected symbol kind $this") } } diff --git a/compiler/testData/ir/irText/stubs/constFromBuiltins__kotlin.Int.txt b/compiler/testData/ir/irText/stubs/constFromBuiltins__kotlin.Int.txt index 8c0cab20869..a58479d46f2 100644 --- a/compiler/testData/ir/irText/stubs/constFromBuiltins__kotlin.Int.txt +++ b/compiler/testData/ir/irText/stubs/constFromBuiltins__kotlin.Int.txt @@ -208,6 +208,7 @@ CLASS IR_EXTERNAL_DECLARATION_STUB CLASS name:Int modality:FINAL visibility:publ VALUE_PARAMETER IR_EXTERNAL_DECLARATION_STUB name:other index:0 type:kotlin.Int CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Companion modality:FINAL visibility:public [companion] superTypes:[] $this: VALUE_PARAMETER IR_EXTERNAL_DECLARATION_STUB name: type:kotlin.Int.Companion + CONSTRUCTOR IR_EXTERNAL_DECLARATION_STUB visibility:private <> () returnType:kotlin.Int.Companion [primary] PROPERTY IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE visibility:public modality:FINAL [const,val] FIELD IR_EXTERNAL_DECLARATION_STUB name:MAX_VALUE type:kotlin.Int visibility:public [final] EXPRESSION_BODY diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index f821ba49521..71f734d4f07 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -364,6 +364,15 @@ class K2Native : CLICompiler() { WorkerExceptionHandling.LEGACY } }) + put(LAZY_IR_FOR_CACHES, when (arguments.lazyIrForCaches) { + null -> true + "enable" -> true + "disable" -> false + else -> { + configuration.report(ERROR, "Expected 'enable' or 'disable' for lazy IR usage for cached libraries") + false + } + }) arguments.externalDependencies?.let { put(EXTERNAL_DEPENDENCIES, it) } putIfNotNull(LLVM_VARIANT, when (val variant = arguments.llvmVariant) { diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index 08bc03c41f7..bd563f79040 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -361,6 +361,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @Argument(value = "-Xruntime-logs", valueDescription = "", description = "Enable logging for runtime with tags.") var runtimeLogs: String? = null + @Argument(value = "-Xlazy-ir-for-caches", valueDescription = "{disable|enable}", description = "Use lazy IR for cached libraries") + var lazyIrForCaches: String? = null + override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap, Any> = super.configureAnalysisFlags(collector, languageVersion).also { val optInList = it[AnalysisFlags.optIn] as List<*> diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt index f86db1d82b7..5d3d0efddf0 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt @@ -53,7 +53,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la classes.add(parent) parent = parent.parent } - require(parent is IrFile) { "Local inline classes are not supported" } + require(parent is IrFile || parent is IrExternalPackageFragment) { "Local inline classes are not supported" } val symbols = ir.symbols @@ -100,7 +100,7 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la ).also { it.parent = function }) - function.parent = inlinedClass.getContainingFile()!! + function.parent = parent } } @@ -112,7 +112,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context. classes.add(parent) parent = parent.parent } - require(parent is IrFile) { "Local inline classes are not supported" } + require(parent is IrFile || parent is IrExternalPackageFragment) { "Local inline classes are not supported" } val symbols = ir.symbols @@ -159,7 +159,7 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context. ).also { it.parent = function }) - function.parent = inlinedClass.getContainingFile()!! + function.parent = parent } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt index 031e81aa8d6..c15774ab1d3 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BuiltInFictitiousFunctionIrClassFactory.kt @@ -36,11 +36,65 @@ import org.jetbrains.kotlin.util.OperatorNameConventions internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS") -internal class BuiltInFictitiousFunctionIrClassFactory( - var symbolTable: SymbolTable?, +abstract class KonanIrAbstractDescriptorBasedFunctionFactory : IrProvider, IrAbstractDescriptorBasedFunctionFactory() + +internal class LazyIrFunctionFactory( + private val symbolTable: SymbolTable, + private val stubGenerator: DeclarationStubGenerator, private val irBuiltIns: IrBuiltInsOverDescriptors, private val reflectionTypes: KonanReflectionTypes -) : IrProvider, IrAbstractDescriptorBasedFunctionFactory() { +) : KonanIrAbstractDescriptorBasedFunctionFactory() { + + override fun getDeclaration(symbol: IrSymbol) = + (symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor -> + buildClass(descriptor) { + declareClass(descriptor) { + createIrClass(descriptor) + } + } + } + + 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 builtClassesMap = mutableMapOf() + + private fun createIrClass(descriptor: ClassDescriptor): IrClass = + stubGenerator.generateClassStub(descriptor) + + private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + symbolTable.declarator { createIrClass(descriptor) } + + private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = + builtClassesMap.getOrPut(descriptor) { createClass(descriptor, declarator) } +} + +internal class BuiltInFictitiousFunctionIrClassFactory( + private val symbolTable: SymbolTable, + private val irBuiltIns: IrBuiltInsOverDescriptors, + private val reflectionTypes: KonanReflectionTypes +) : KonanIrAbstractDescriptorBasedFunctionFactory() { override fun getDeclaration(symbol: IrSymbol) = (symbol.descriptor as? FunctionClassDescriptor)?.let { descriptor -> @@ -98,11 +152,11 @@ internal class BuiltInFictitiousFunctionIrClassFactory( override fun kSuspendFunctionN(arity: Int, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = buildClass(reflectionTypes.getKSuspendFunction(arity) as FunctionClassDescriptor, declarator) - private val functionSymbol = symbolTable!!.referenceClass( + private val functionSymbol = symbolTable.referenceClass( irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies( ClassId.topLevel(KonanFqNames.function))!!) - private val kFunctionSymbol = symbolTable!!.referenceClass( + private val kFunctionSymbol = symbolTable.referenceClass( irBuiltIns.builtIns.builtInsModule.findClassAcrossModuleDependencies( ClassId.topLevel(KonanFqNames.kFunction))!!) @@ -121,20 +175,10 @@ internal class BuiltInFictitiousFunctionIrClassFactory( } private fun createTypeParameter(descriptor: TypeParameterDescriptor): IrTypeParameter = - symbolTable?.declareGlobalTypeParameter( + symbolTable.declareGlobalTypeParameter( SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, DECLARATION_ORIGIN_FUNCTION_CLASS, descriptor ) - ?: IrTypeParameterImpl( - SYNTHETIC_OFFSET, - SYNTHETIC_OFFSET, - DECLARATION_ORIGIN_FUNCTION_CLASS, - IrTypeParameterSymbolImpl(descriptor), - descriptor.name, - descriptor.index, - descriptor.isReified, - descriptor.variance - ) private fun createSimpleFunction( descriptor: FunctionDescriptor, @@ -150,16 +194,14 @@ internal class BuiltInFictitiousFunctionIrClassFactory( ) } } - return symbolTable?.declareSimpleFunction(descriptor, functionFactory) - ?: functionFactory(IrSimpleFunctionSymbolImpl(descriptor)) + return symbolTable.declareSimpleFunction(descriptor, functionFactory) } private fun createIrClass(symbol: IrClassSymbol, descriptor: ClassDescriptor): IrClass = IrFactoryImpl.createIrClassFromDescriptor(offset, offset, DECLARATION_ORIGIN_FUNCTION_CLASS, symbol, descriptor) private fun createClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = - symbolTable?.declarator { createIrClass(it, descriptor) } - ?: createIrClass(IrClassSymbolImpl(descriptor), descriptor) + symbolTable.declarator { createIrClass(it, descriptor) } private fun buildClass(descriptor: FunctionClassDescriptor, declarator: SymbolTable.((IrClassSymbol) -> IrClass) -> IrClass): IrClass = builtClassesMap.getOrPut(descriptor) { @@ -246,8 +288,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory( 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")) + classifier = symbolTable.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType")) hasQuestionMark = kotlinType.isMarkedNullable arguments = kotlinType.arguments.map { if (it.isStarProjection) IrStarProjectionImpl @@ -296,11 +337,10 @@ internal class BuiltInFictitiousFunctionIrClassFactory( } } - val newFunction = symbolTable?.declareSimpleFunction(descriptor, functionDeclare) - ?: functionDeclare(IrSimpleFunctionSymbolImpl(descriptor)) + val newFunction = symbolTable.declareSimpleFunction(descriptor, functionDeclare) newFunction.parent = this - newFunction.overriddenSymbols = descriptor.overriddenDescriptors.mapNotNull { symbolTable?.referenceSimpleFunction(it.original) } + 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) } @@ -327,8 +367,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory( isExpect = descriptor.isExpect, isFakeOverride = true) } - val property = symbolTable?.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare) - ?: propertyDeclare(IrPropertySymbolImpl(descriptor)) + val property = symbolTable.declareProperty(offset, offset, memberOrigin, descriptor, propertyFactory = propertyDeclare) property.parent = this property.getter = descriptor.getter?.let { g -> createFakeOverrideFunction(g, property.symbol) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt index 1f208e9e82b..4411ef3af78 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer +import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.KonanTarget @@ -25,6 +27,18 @@ class CachedLibraries( val directory = File(path).absoluteFile.parent File(directory, BITCODE_DEPENDENCIES_FILE_NAME).readStrings() } + + val serializedInlineFunctionBodies by lazy { + val directory = File(path).absoluteFile.parent + val data = File(directory, INLINE_FUNCTION_BODIES_FILE_NAME).readBytes() + InlineFunctionBodyReferenceSerializer.deserialize(data) + } + + val serializedClassFields by lazy { + val directory = File(path).absoluteFile.parent + val data = File(directory, CLASS_FIELDS_FILE_NAME).readBytes() + ClassFieldsSerializer.deserialize(data) + } } private val cacheDirsContents = mutableMapOf>() @@ -90,6 +104,9 @@ class CachedLibraries( companion object { fun getCachedLibraryName(library: KotlinLibrary): String = getCachedLibraryName(library.uniqueName) fun getCachedLibraryName(libraryName: String): String = "$libraryName-cache" + const val BITCODE_DEPENDENCIES_FILE_NAME = "bitcode_deps" + const val INLINE_FUNCTION_BODIES_FILE_NAME = "inline_bodies" + const val CLASS_FIELDS_FILE_NAME = "class_fields" } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 07bfed09557..0d3931e7090 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -42,6 +42,9 @@ import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.copyToWithoutSuperTypes import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager +import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker +import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields +import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl @@ -51,6 +54,8 @@ import org.jetbrains.kotlin.konan.util.disposeNativeMemoryAllocator import org.jetbrains.kotlin.library.SerializedIrModule import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal +internal class InlineFunctionOriginInfo(val irFile: IrFile, val startOffset: Int, val endOffset: Int) + /** * Offset for synthetic elements created by lowerings and not attributable to other places in the source code. */ @@ -65,7 +70,7 @@ internal class SpecialDeclarationsFactory(val context: Context) { private val bridges = mutableMapOf() - val loweredInlineFunctions = mutableSetOf() + val loweredInlineFunctions = mutableMapOf() object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS : IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") @@ -494,6 +499,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { * Manages internal ABI references and declarations. */ val internalAbi = InternalAbi(this) + + lateinit var irLinker: KonanIrLinker + + val inlineFunctionBodies = mutableListOf() + + val classFields = mutableListOf() } private fun MemberScope.getContributedClassifier(name: String) = diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt index 723d5cb78ab..079c40bad20 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/EntryPoint.kt @@ -19,14 +19,24 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.types.typeWith +import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET import org.jetbrains.kotlin.ir.util.irCatch import org.jetbrains.kotlin.name.Name internal fun makeEntryPoint(context: Context): IrFunction { val actualMain = context.ir.symbols.entryPoint!!.owner + // TODO: Do we need to do something with the offsets if
is in a cached library? + val startOffset = if (context.llvmModuleSpecification.containsDeclaration(actualMain)) + actualMain.startOffset + else + SYNTHETIC_OFFSET + val endOffset = if (context.llvmModuleSpecification.containsDeclaration(actualMain)) + actualMain.endOffset + else + SYNTHETIC_OFFSET val entryPoint = IrFunctionImpl( - actualMain.startOffset, - actualMain.startOffset, + startOffset, + endOffset, IrDeclarationOrigin.DEFINED, IrSimpleFunctionSymbolImpl(), Name.identifier("Konan_start"), @@ -44,7 +54,7 @@ internal fun makeEntryPoint(context: Context): IrFunction { ).also { function -> function.valueParameters = listOf( IrValueParameterImpl( - actualMain.startOffset, actualMain.startOffset, + startOffset, endOffset, IrDeclarationOrigin.DEFINED, IrValueParameterSymbolImpl(), Name.identifier("args"), @@ -60,16 +70,12 @@ internal fun makeEntryPoint(context: Context): IrFunction { }) } entryPoint.annotations += buildSimpleAnnotation(context.irBuiltIns, - actualMain.startOffset, actualMain.startOffset, + startOffset, endOffset, context.ir.symbols.exportForCppRuntime.owner, "Konan_start") val builder = context.createIrBuilder(entryPoint.symbol) entryPoint.body = builder.irBlockBody(entryPoint) { - +IrTryImpl( - startOffset = actualMain.startOffset, - endOffset = actualMain.startOffset, - type = context.irBuiltIns.nothingType - ).apply { + +IrTryImpl(startOffset, endOffset, context.irBuiltIns.nothingType).apply { tryResult = irBlock { +irCall(actualMain).apply { if (actualMain.valueParameters.size != 0) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 01d5588da11..a23569e9238 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -273,6 +273,8 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val isInteropStubs: Boolean get() = manifestProperties?.getProperty("interop") == "true" internal val propertyLazyInitialization: Boolean get() = configuration.get(KonanConfigKeys.PROPERTY_LAZY_INITIALIZATION)!! + + internal val lazyIrForCaches: Boolean get() = configuration.get(KonanConfigKeys.LAZY_IR_FOR_CACHES)!! } fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 3704d6f842c..b3647358c38 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -170,6 +170,7 @@ class KonanConfigKeys { CompilerConfigurationKey.create("use external dependencies to enhance IR linker error messages") val LLVM_VARIANT: CompilerConfigurationKey = CompilerConfigurationKey.create("llvm variant") val RUNTIME_LOGS: CompilerConfigurationKey = CompilerConfigurationKey.create("enable runtime logging") + val LAZY_IR_FOR_CACHES: CompilerConfigurationKey = CompilerConfigurationKey.create("use lazy IR for cached libraries") } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt index d719daf5f0f..a6b2a8c1b55 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt @@ -1,5 +1,7 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer +import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer import org.jetbrains.kotlin.konan.KonanExternalToolFailure import org.jetbrains.kotlin.konan.exec.Command import org.jetbrains.kotlin.konan.file.File @@ -58,6 +60,8 @@ internal class Linker(val context: Context) { private fun saveAdditionalInfoForCache() { saveCacheBitcodeDependencies() + saveInlineFunctionBodies() + saveClassFields() } private fun saveCacheBitcodeDependencies() { @@ -73,6 +77,18 @@ internal class Linker(val context: Context) { bitcodeDependenciesFile.writeLines(bitcodeDependencies.map { it.uniqueName }) } + private fun saveInlineFunctionBodies() { + val outputFiles = context.config.outputFiles + val inlineFunctionBodiesFile = File(outputFiles.inlineFunctionBodiesFile!!) + inlineFunctionBodiesFile.writeBytes(InlineFunctionBodyReferenceSerializer.serialize(context.inlineFunctionBodies)) + } + + private fun saveClassFields() { + val outputFiles = context.config.outputFiles + val classFieldsFile = File(outputFiles.classFieldsFile!!) + classFieldsFile.writeBytes(ClassFieldsSerializer.serialize(context.classFields)) + } + private fun renameOutput() { if (context.config.produce.isCache) { val outputFiles = context.config.outputFiles diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt index 14ba4aa8c31..dbd04f60484 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt @@ -63,6 +63,16 @@ class OutputFiles(outputPath: String?, target: KonanTarget, val produce: Compile tempCacheDirectory!!.child(CachedLibraries.BITCODE_DEPENDENCIES_FILE_NAME).absolutePath else null + val inlineFunctionBodiesFile = + if (produce.isCache) + tempCacheDirectory!!.child(CachedLibraries.INLINE_FUNCTION_BODIES_FILE_NAME).absolutePath + else null + + val classFieldsFile = + if (produce.isCache) + tempCacheDirectory!!.child(CachedLibraries.CLASS_FIELDS_FILE_NAME).absolutePath + else null + private fun String.fullOutputName() = prefixBaseNameIfNeeded(prefix).suffixIfNeeded(suffix) private fun String.prefixBaseNameIfNeeded(prefix: String) = diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt index 089cd055036..c69e4f4866d 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/PsiToIr.kt @@ -53,15 +53,17 @@ internal fun Context.psiToIr( // Note: using [llvmModuleSpecification] since this phase produces IR for generating single LLVM module. - val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct() - val irBuiltInsOverDescriptors = generatorContext.irBuiltIns as IrBuiltInsOverDescriptors - val functionIrClassFactory = BuiltInFictitiousFunctionIrClassFactory( - symbolTable, irBuiltInsOverDescriptors, reflectionTypes) - irBuiltInsOverDescriptors.functionFactory = functionIrClassFactory val stubGenerator = DeclarationStubGeneratorImpl( moduleDescriptor, symbolTable, generatorContext.irBuiltIns ) + val irBuiltInsOverDescriptors = generatorContext.irBuiltIns as IrBuiltInsOverDescriptors + val functionIrClassFactory: KonanIrAbstractDescriptorBasedFunctionFactory = + if (config.lazyIrForCaches && !llvmModuleSpecification.containsModule(this.stdlibModule)) + LazyIrFunctionFactory(symbolTable, stubGenerator, irBuiltInsOverDescriptors, reflectionTypes) + else + BuiltInFictitiousFunctionIrClassFactory(symbolTable, irBuiltInsOverDescriptors, reflectionTypes) + irBuiltInsOverDescriptors.functionFactory = functionIrClassFactory val symbols = KonanSymbols(this, generatorContext.irBuiltIns, symbolTable, symbolTable.lazyWrapper) val irDeserializer = if (isProducingLibrary && !useLinkerWhenProducingLibrary) { @@ -77,6 +79,7 @@ internal fun Context.psiToIr( } } } else { + val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct() val irProviderForCEnumsAndCStructs = IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, symbols) @@ -102,6 +105,7 @@ internal fun Context.psiToIr( irProviderForCEnumsAndCStructs, exportedDependencies, config.cachedLibraries, + config.lazyIrForCaches, config.userVisibleIrModulesSupport ).also { linker -> @@ -120,15 +124,14 @@ internal fun Context.psiToIr( } for (dependency in sortDependencies(dependencies).filter { it != moduleDescriptor }) { - val kotlinLibrary = dependency.getCapability(KlibModuleOrigin.CAPABILITY)?.let { - (it as? DeserializedKlibModuleOrigin)?.library - } - when { - isProducingLibrary -> linker.deserializeOnlyHeaderModule(dependency, kotlinLibrary) - kotlinLibrary != null && config.cachedLibraries.isLibraryCached(kotlinLibrary) -> - linker.deserializeHeadersWithInlineBodies(dependency, kotlinLibrary) - else -> linker.deserializeIrModuleHeader(dependency, kotlinLibrary, dependency.name.asString()) - } + val kotlinLibrary = (dependency.getCapability(KlibModuleOrigin.CAPABILITY) as? DeserializedKlibModuleOrigin)?.library + val isCachedLibrary = kotlinLibrary != null && config.cachedLibraries.isLibraryCached(kotlinLibrary) + if (isProducingLibrary || (config.lazyIrForCaches && isCachedLibrary)) + linker.deserializeOnlyHeaderModule(dependency, kotlinLibrary) + else if (isCachedLibrary) + linker.deserializeHeadersWithInlineBodies(dependency, kotlinLibrary!!) + else + linker.deserializeIrModuleHeader(dependency, kotlinLibrary, dependency.name.asString()) } if (dependencies.size == dependenciesCount) break dependenciesCount = dependencies.size @@ -140,7 +143,6 @@ internal fun Context.psiToIr( .filter(ModuleDescriptor::isFromInteropLibrary) .forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom) - translator.addPostprocessingStep { irProviderForCEnumsAndCStructs.generateBodies() } @@ -197,14 +199,19 @@ internal fun Context.psiToIr( // Note: coupled with [shouldLower] below. irModules = modules.filterValues { llvmModuleSpecification.containsModule(it) } + if (!isProducingLibrary) + irLinker = irDeserializer as KonanIrLinker + ir.symbols = symbols if (!isProducingLibrary) { // TODO: find out what should be done in the new builtins/symbols about it - if (this.stdlibModule in modulesWithoutDCE) - functionIrClassFactory.buildAllClasses() + if (this.stdlibModule in modulesWithoutDCE) { + (functionIrClassFactory as BuiltInFictitiousFunctionIrClassFactory).buildAllClasses() + } internalAbi.init(irModules.values + irModule!!) - functionIrClassFactory.module = (modules.values + irModule!!).single { it.descriptor.isNativeStdlib() } + (functionIrClassFactory as? BuiltInFictitiousFunctionIrClassFactory)?.module = + (modules.values + irModule!!).single { it.descriptor.isNativeStdlib() } } mainModule.files.forEach { it.metadata = KonanFileMetadataSource(mainModule) } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt index b07e09ce366..dde62f9f145 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ToplevelPhases.kt @@ -7,13 +7,12 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer +import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport -import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer -import org.jetbrains.kotlin.backend.konan.serialization.KonanIrModuleSerializer -import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerDesc +import org.jetbrains.kotlin.backend.konan.serialization.* import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.ir.IrElement @@ -32,6 +31,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.konan.target.CompilerOutputKind +import org.jetbrains.kotlin.name.FqName internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) { if (!context.config.needVerifyIr) return @@ -124,6 +124,47 @@ internal val psiToIrPhase = konanUnitPhase( prerequisite = setOf(createSymbolTablePhase) ) +internal val buildAdditionalCacheInfoPhase = konanUnitPhase( + op = { + irModules.values.single().let { module -> + val moduleDeserializer = irLinker.nonCachedLibraryModuleDeserializers[module.descriptor] + if (moduleDeserializer == null) { + require(module.descriptor.isFromInteropLibrary()) { "No module deserializer for ${module.descriptor}" } + } else { + val compatibleMode = CompatibilityMode(moduleDeserializer.libraryAbiVersion).oldSignatures + module.acceptChildrenVoid(object : IrElementVisitorVoid { + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + + override fun visitClass(declaration: IrClass) { + declaration.acceptChildrenVoid(this) + + if (declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS) + classFields.add(moduleDeserializer.buildClassFields(declaration, getLayoutBuilder(declaration).getDeclaredFields())) + } + + override fun visitFunction(declaration: IrFunction) { + declaration.acceptChildrenVoid(this) + + if (declaration.isFakeOverride || !declaration.isExportedInlineFunction) return + inlineFunctionBodies.add(moduleDeserializer.buildInlineFunctionReference(declaration)) + } + + private val IrClass.isExported + get() = with(KonanManglerIr) { isExported(compatibleMode) } + + private val IrFunction.isExportedInlineFunction + get() = isInline && with(KonanManglerIr) { isExported(compatibleMode) } + }) + } + } + }, + name = "BuildAdditionalCacheInfo", + description = "Build additional cache info (inline functions bodies and fields of classes)", + prerequisite = setOf(psiToIrPhase) +) + // Coupled with [psiToIrPhase] logic above. internal fun shouldLower(context: Context, declaration: IrDeclaration): Boolean { return context.llvmModuleSpecification.containsDeclaration(declaration) @@ -305,21 +346,17 @@ internal val entryPointPhase = makeCustomPhase( description = "Add entry point for program", prerequisite = emptySet(), op = { context, _ -> - assert(context.config.produce == CompilerOutputKind.PROGRAM) + require(context.config.produce == CompilerOutputKind.PROGRAM) - val originalFile = context.ir.symbols.entryPoint!!.owner.file - val originalModule = originalFile.packageFragmentDescriptor.containingDeclaration - val file = if (context.llvmModuleSpecification.containsModule(originalModule)) { - originalFile + val entryPoint = context.ir.symbols.entryPoint!!.owner + val file = if (context.llvmModuleSpecification.containsDeclaration(entryPoint)) { + entryPoint.file } else { // `main` function is compiled to other LLVM module. // For example, test running support uses `main` defined in stdlib. - context.irModule!!.addFile(originalFile.fileEntry, originalFile.fqName) + context.irModule!!.addFile(NaiveSourceBasedFileEntryImpl("entryPointOwner"), FqName("kotlin.native.caches.abi")) } - require(context.llvmModuleSpecification.containsModule( - file.packageFragmentDescriptor.containingDeclaration)) - file.addChild(makeEntryPoint(context)) } ) @@ -444,6 +481,7 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase( objCExportPhase then buildCExportsPhase then psiToIrPhase then + buildAdditionalCacheInfoPhase then destroySymbolTablePhase then copyDefaultValuesToActualPhase then checkSamSuperTypesPhase then @@ -478,6 +516,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) { // Don't serialize anything to a final executable. disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY) disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM) + disableUnless(buildAdditionalCacheInfoPhase, config.produce.isCache) disableUnless(exportInternalAbiPhase, config.produce.isCache) disableIf(backendCodegen, config.produce == CompilerOutputKind.LIBRARY) disableUnless(bitcodeOptimizationPhase, config.produce.involvesLinkStage) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt index f7657f82d03..10d402adcb2 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/ClassLayoutBuilder.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.util.* 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.library.isInterop internal class OverriddenFunctionInfo( val function: IrSimpleFunction, @@ -466,6 +467,19 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va * Fields declared in the class. */ fun getDeclaredFields(): List { + if (context.config.lazyIrForCaches && !context.llvmModuleSpecification.containsDeclaration(irClass)) { + val packageFragment = irClass.findPackage() + val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration + if (moduleDescriptor.isFromInteropLibrary()) + return emptyList() + val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor] + ?: error("No module deserializer for ${irClass.render()}") + val fields = moduleDeserializer.deserializeClassFields(irClass).toMutableList() + if (irClass.isInner) + fields.add(InnerClassLowering.addOuterThisField(mutableListOf(), irClass, context).toFieldInfo()) + return fields + } + val declarations: List = if (irClass.isInner && !isLowered) { // Note: copying to avoid mutation of the original class. irClass.declarations.toMutableList() diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FakeIrUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FakeIrUtils.kt index 5dd514db789..819c37ab551 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FakeIrUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/FakeIrUtils.kt @@ -6,20 +6,16 @@ package org.jetbrains.kotlin.backend.konan.ir import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.descriptors.findPackage import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyDeclarationBase import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.toKotlinType -import org.jetbrains.kotlin.ir.util.file // This file contains some IR utilities which actually use descriptors. // TODO: port this code to IR. -internal val IrDeclaration.llvmSymbolOrigin get() = when (this) { - is IrLazyDeclarationBase -> descriptor.llvmSymbolOrigin - else -> file.packageFragmentDescriptor.llvmSymbolOrigin -} +internal val IrDeclaration.llvmSymbolOrigin get() = findPackage().packageFragmentDescriptor.llvmSymbolOrigin internal fun IrType.isObjCObjectType() = this.toKotlinType().isObjCObjectType() diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 8d0b66b91d5..404e3c0692f 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1824,15 +1824,23 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map { override fun visitDeclaration(declaration: IrDeclarationBase, data: IrBuilderWithScope) = super.visitDeclaration(declaration, @@ -53,7 +56,7 @@ internal class PreInlineLowering(val context: Context) : BodyLoweringPass { IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type) } Symbols.isTypeOfIntrinsic(expression.symbol) -> { - with (KTypeGenerator(context, container.file, expression, needExactTypeParameters = true)) { + with (KTypeGenerator(context, irFile, expression, needExactTypeParameters = true)) { data.at(expression).irKType(expression.getTypeArgument(0)!!, leaveReifiedForLater = true) } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt index f8663482540..63a25990d2f 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIrlinker.kt @@ -16,12 +16,20 @@ package org.jetbrains.kotlin.backend.konan.serialization +import org.jetbrains.kotlin.backend.common.lower.parents import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideClassFilter +import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker import org.jetbrains.kotlin.backend.common.serialization.* +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAndType import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData import org.jetbrains.kotlin.backend.common.serialization.linkerissues.UserVisibleIrModulesSupport import org.jetbrains.kotlin.backend.konan.CachedLibraries +import org.jetbrains.kotlin.backend.common.serialization.encodings.FunctionFlags +import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.InlineFunctionOriginInfo +import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder +import org.jetbrains.kotlin.backend.konan.descriptors.findPackage import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs import org.jetbrains.kotlin.descriptors.* @@ -31,11 +39,17 @@ import org.jetbrains.kotlin.descriptors.konan.klibModuleOrigin import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.builders.TranslationPluginContext import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl -import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass +import org.jetbrains.kotlin.ir.expressions.IrBody +import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.types.classifierOrNull +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.types.getPublicSignature import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -44,7 +58,237 @@ 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.protobuf.ExtensionRegistryLite import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile as ProtoFile +import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration +import org.jetbrains.kotlin.backend.common.serialization.proto.IrClass as ProtoClass +import org.jetbrains.kotlin.backend.common.serialization.proto.IrFunction as ProtoFunction +import org.jetbrains.kotlin.backend.common.serialization.proto.IrProperty as ProtoProperty +import org.jetbrains.kotlin.backend.common.serialization.proto.IrField as ProtoField +import sun.misc.Unsafe + +private val unsafe = with(Unsafe::class.java.getDeclaredField("theUnsafe")) { + isAccessible = true + return@with this.get(null) as Unsafe +} + +private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong() + +internal class ByteArrayStream(val buf: ByteArray) { + private var offset = 0 + + fun hasData() = offset < buf.size + + fun readInt(): Int { + checkSize(offset + Int.SIZE_BYTES) { "Can't read an int at $offset, size = ${buf.size}" } + return unsafe.getInt(buf, byteArrayBaseOffset + offset).also { offset += Int.SIZE_BYTES } + } + + fun writeInt(value: Int) { + checkSize(offset + Int.SIZE_BYTES) { "Can't write an int at $offset, size = ${buf.size}" } + unsafe.putInt(buf, byteArrayBaseOffset + offset, value).also { offset += Int.SIZE_BYTES } + } + + private fun checkSize(at: Int, messageBuilder: () -> String) { + if (at > buf.size) error(messageBuilder()) + } +} + +class SerializedInlineFunctionReference(val file: Int, val functionSignature: Int, val body: Int, + val startOffset: Int, val endOffset: Int, + val extensionReceiverSig: Int, val dispatchReceiverSig: Int, + val valueParameterSigs: IntArray, val typeParameterSigs: IntArray, + val defaultValues: IntArray) + +internal object InlineFunctionBodyReferenceSerializer { + fun serialize(bodies: List): ByteArray { + val size = bodies.sumOf { + Int.SIZE_BYTES * (10 + it.valueParameterSigs.size + it.typeParameterSigs.size + it.defaultValues.size) + } + val stream = ByteArrayStream(ByteArray(size)) + bodies.forEach { + stream.writeInt(it.file) + stream.writeInt(it.functionSignature) + stream.writeInt(it.body) + stream.writeInt(it.startOffset) + stream.writeInt(it.endOffset) + stream.writeInt(it.extensionReceiverSig) + stream.writeInt(it.dispatchReceiverSig) + stream.writeInt(it.valueParameterSigs.size) + it.valueParameterSigs.forEach { sig -> stream.writeInt(sig) } + stream.writeInt(it.typeParameterSigs.size) + it.typeParameterSigs.forEach { sig -> stream.writeInt(sig) } + stream.writeInt(it.defaultValues.size) + it.defaultValues.forEach { stream.writeInt(it) } + } + return stream.buf + } + + fun deserialize(data: ByteArray): List { + val result = mutableListOf() + val stream = ByteArrayStream(data) + while (stream.hasData()) { + val file = stream.readInt() + val functionSignature = stream.readInt() + val body = stream.readInt() + val startOffset = stream.readInt() + val endOffset = stream.readInt() + val extensionReceiverSig = stream.readInt() + val dispatchReceiverSig = stream.readInt() + val valueParameterSigsCount = stream.readInt() + val valueParameterSigs = IntArray(valueParameterSigsCount) { stream.readInt() } + val typeParameterSigsCount = stream.readInt() + val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() } + val defaultValuesCount = stream.readInt() + val defaultValues = IntArray(defaultValuesCount) { stream.readInt() } + result.add(SerializedInlineFunctionReference(file, functionSignature, body, startOffset, endOffset, + extensionReceiverSig, dispatchReceiverSig, valueParameterSigs, typeParameterSigs, defaultValues)) + } + return result + } +} + +// [binaryType] is needed in case a field is of a private inline class type (which can't be deserialized). +// But it is safe to just set the field's type to the primitive type the inline class will be erased to. +class SerializedClassFieldInfo(val name: Int, val binaryType: Int, val type: Int, val flags: Int) { + companion object { + const val FLAG_IS_CONST = 1 + const val FLAG_CONST_INITIALIZER = 2 + } +} + +class SerializedClassFields(val file: Int, val classSignature: Int, + val typeParameterSigs: IntArray, val fields: Array) + +internal object ClassFieldsSerializer { + fun serialize(classFields: List): ByteArray { + val size = classFields.sumOf { Int.SIZE_BYTES * (4 + it.typeParameterSigs.size + it.fields.size * 4) } + val stream = ByteArrayStream(ByteArray(size)) + classFields.forEach { + stream.writeInt(it.file) + stream.writeInt(it.classSignature) + stream.writeInt(it.typeParameterSigs.size) + it.typeParameterSigs.forEach { stream.writeInt(it) } + stream.writeInt(it.fields.size) + it.fields.forEach { field -> + stream.writeInt(field.name) + stream.writeInt(field.binaryType) + stream.writeInt(field.type) + stream.writeInt(field.flags) + } + } + return stream.buf + } + + fun deserialize(data: ByteArray): List { + val result = mutableListOf() + val stream = ByteArrayStream(data) + while (stream.hasData()) { + val file = stream.readInt() + val classSignature = stream.readInt() + val typeParameterSigsCount = stream.readInt() + val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() } + val fieldsCount = stream.readInt() + val fields = Array(fieldsCount) { + val name = stream.readInt() + val binaryType = stream.readInt() + val type = stream.readInt() + val flags = stream.readInt() + SerializedClassFieldInfo(name, binaryType, type, flags) + } + result.add(SerializedClassFields(file, classSignature, typeParameterSigs, fields)) + } + return result + } +} + +internal fun ProtoClass.findClass(irClass: IrClass, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoClass { + val signature = irClass.symbol.signature ?: error("No signature for ${irClass.render()}") + var result: ProtoClass? = null + + for (i in 0 until this.declarationCount) { + val child = this.getDeclaration(i) + if (child.declaratorCase != ProtoDeclaration.DeclaratorCase.IR_CLASS) continue + val childClass = child.irClass + + val name = fileReader.string(child.irClass.name) + if (name == irClass.name.asString()) { + if (result == null) + result = childClass + else { + val resultIdSignature = symbolDeserializer.deserializeIdSignature(BinarySymbolData.decode(result.base.symbol).signatureId) + if (resultIdSignature == signature) + return result + result = childClass + } + } + } + return result ?: error("Class ${irClass.render()} is not found") +} + +internal fun ProtoClass.findProperty(irProperty: IrProperty, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoProperty { + val signature = irProperty.symbol.signature ?: error("No signature for ${irProperty.render()}") + var result: ProtoProperty? = null + + for (i in 0 until this.declarationCount) { + val child = this.getDeclaration(i) + if (child.declaratorCase != ProtoDeclaration.DeclaratorCase.IR_PROPERTY) continue + val childProperty = child.irProperty + + val name = fileReader.string(child.irProperty.name) + if (name == irProperty.name.asString()) { + if (result == null) + result = childProperty + else { + val resultIdSignature = symbolDeserializer.deserializeIdSignature(BinarySymbolData.decode(result.base.symbol).signatureId) + if (resultIdSignature == signature) + return result + result = childProperty + } + } + } + return result ?: error("Property ${irProperty.render()} is not found") +} + +internal fun ProtoProperty.findAccessor(irProperty: IrProperty, irFunction: IrSimpleFunction): ProtoFunction { + if (irFunction == irProperty.getter) + return getter + require(irFunction == irProperty.setter) { "Accessor should be either a getter or a setter. ${irFunction.render()}" } + return setter +} + +internal fun ProtoClass.findInlineFunction(irFunction: IrFunction, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoFunction { + (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.let { irProperty -> + return findProperty(irProperty, fileReader, symbolDeserializer).findAccessor(irProperty, irFunction) + } + + val signature = irFunction.symbol.signature ?: error("No signature for ${irFunction.render()}") + var result: ProtoFunction? = null + for (i in 0 until this.declarationCount) { + val child = this.getDeclaration(i) + if (child.declaratorCase != ProtoDeclaration.DeclaratorCase.IR_FUNCTION) continue + val childFunction = child.irFunction + if (childFunction.base.valueParameterCount != irFunction.valueParameters.size) continue + if (childFunction.base.hasExtensionReceiver() xor (irFunction.extensionReceiverParameter != null)) continue + if (childFunction.base.hasDispatchReceiver() xor (irFunction.dispatchReceiverParameter != null)) continue + if (!FunctionFlags.decode(childFunction.base.base.flags).isInline) continue + + val nameAndType = BinaryNameAndType.decode(childFunction.base.nameType) + val name = fileReader.string(nameAndType.nameIndex) + if (name == irFunction.name.asString()) { + if (result == null) + result = childFunction + else { + val resultIdSignature = symbolDeserializer.deserializeIdSignature(BinarySymbolData.decode(result.base.base.symbol).signatureId) + if (resultIdSignature == signature) + return result + result = childFunction + } + } + } + return result ?: error("Function ${irFunction.render()} is not found") +} object KonanFakeOverrideClassFilter : FakeOverrideClassFilter { private fun IdSignature.isInteropSignature(): Boolean = with(this) { @@ -59,7 +303,7 @@ object KonanFakeOverrideClassFilter : FakeOverrideClassFilter { .any { it.signature?.isInteropSignature() ?: false } override fun needToConstructFakeOverrides(clazz: IrClass): Boolean { - return !clazz.hasInteropSuperClass() + return !clazz.hasInteropSuperClass() && clazz !is IrLazyClass } } @@ -74,6 +318,7 @@ internal class KonanIrLinker( private val cenumsProvider: IrProviderForCEnumAndCStructStubs, exportedDependencies: List, private val cachedLibraries: CachedLibraries, + private val lazyIrForCaches: Boolean, override val userVisibleIrModulesSupport: UserVisibleIrModulesSupport ) : KotlinIrLinker(currentModule, messageLogger, builtIns, symbolTable, exportedDependencies) { @@ -92,27 +337,205 @@ internal class KonanIrLinker( override val fakeOverrideBuilder: FakeOverrideBuilder = FakeOverrideBuilder(this, symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), KonanFakeOverrideClassFilter) - override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy): IrModuleDeserializer { - if (moduleDescriptor === forwardModuleDescriptor) { - return forwardDeclarationDeserializer ?: error("forward declaration deserializer expected") - } + val nonCachedLibraryModuleDeserializers = mutableMapOf() + val cachedLibraryModuleDeserializers = mutableMapOf() - if (klib != null && klib.isInteropLibrary()) { - // See https://youtrack.jetbrains.com/issue/KT-43517. - // Disabling this flag forces linker to generate IR. - val isCached = false //cachedLibraries.isLibraryCached(klib) - return KonanInteropModuleDeserializer(moduleDescriptor, klib, isCached) - } + override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy) = + when { + moduleDescriptor === forwardModuleDescriptor -> { + forwardDeclarationDeserializer ?: error("forward declaration deserializer expected") + } + klib == null -> { + error("Expecting kotlin library for $moduleDescriptor") + } + klib.isInteropLibrary() -> { + // See https://youtrack.jetbrains.com/issue/KT-43517. + // Disabling this flag forces linker to generate IR. + val isCached = false //cachedLibraries.isLibraryCached(klib) + KonanInteropModuleDeserializer(moduleDescriptor, klib, isCached) + } + lazyIrForCaches && cachedLibraries.isLibraryCached(klib) -> { + KonanCachedLibraryModuleDeserializer(moduleDescriptor, klib).also { + cachedLibraryModuleDeserializers[moduleDescriptor] = it + } + } + else -> { + KonanModuleDeserializer(moduleDescriptor, klib, strategyResolver).also { + nonCachedLibraryModuleDeserializers[moduleDescriptor] = it + } + } + } - return KonanModuleDeserializer(moduleDescriptor, klib ?: error("Expecting kotlin library"), strategyResolver) + override fun postProcess() { + if (lazyIrForCaches) + stubGenerator.unboundSymbolGeneration = true + super.postProcess() } - private inner class KonanModuleDeserializer( + private val IrClass.firstNonClassParent: IrDeclarationParent + get() { + var parent = parent + while (parent is IrClass) parent = parent.parent + return parent + } + + private fun IrClass.getOuterClasses(takeOnlyInner: Boolean): List { + var outerClass = this + val outerClasses = mutableListOf(outerClass) + while (outerClass.isInner || !takeOnlyInner) { + outerClass = outerClass.parent as? IrClass ?: break + outerClasses.add(outerClass) + } + outerClasses.reverse() + return outerClasses + } + + private val InvalidIndex = -1 + + inner class KonanModuleDeserializer( moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary, strategyResolver: (String) -> DeserializationStrategy ): BasicIrModuleDeserializer(this@KonanIrLinker, moduleDescriptor, klib, strategyResolver, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList()) + + fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference { + val signature = irFunction.symbol.signature + ?: error("No signature for ${irFunction.render()}") + val topLevelSignature = signature.topLevelSignature() + val fileDeserializationState = moduleReversedFileIndex[topLevelSignature] + ?: error("No file deserializer for ${topLevelSignature.render()}") + val declarationIndex = fileDeserializationState.fileDeserializer.reversedSignatureIndex[topLevelSignature] + ?: error("No declaration for ${topLevelSignature.render()}") + val fileReader = fileDeserializationState.fileReader + val symbolDeserializer = fileDeserializationState.fileDeserializer.symbolDeserializer + val protoDeclaration = fileReader.declaration(declarationIndex) + + val outerClasses = (irFunction.parent as? IrClass)?.getOuterClasses(takeOnlyInner = false) ?: emptyList() + require((outerClasses.getOrNull(0)?.parent ?: irFunction.parent) is IrFile) { + "Local inline functions are not supported: ${irFunction.render()}" + } + + val typeParameterSigs = mutableListOf() + val protoFunction = if (outerClasses.isEmpty()) { + val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner + if (irProperty == null) + protoDeclaration.irFunction + else protoDeclaration.irProperty.findAccessor(irProperty, irFunction) + } else { + val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner } + var protoClass = protoDeclaration.irClass + outerClasses.indices.forEach { classIndex -> + if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) { + (0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) { + BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId + } + } + if (classIndex < outerClasses.size - 1) + protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer) + } + protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer) + } + + val functionSignature = BinarySymbolData.decode(protoFunction.base.base.symbol).signatureId + (0 until protoFunction.base.typeParameterCount).mapTo(typeParameterSigs) { + BinarySymbolData.decode(protoFunction.base.getTypeParameter(it).base.symbol).signatureId + } + val defaultValues = mutableListOf() + val valueParameterSigs = (0 until protoFunction.base.valueParameterCount).map { + val valueParameter = protoFunction.base.getValueParameter(it) + defaultValues.add(if (valueParameter.hasDefaultValue()) valueParameter.defaultValue else InvalidIndex) + BinarySymbolData.decode(valueParameter.base.symbol).signatureId + } + val extensionReceiverSig = irFunction.extensionReceiverParameter?.let { + BinarySymbolData.decode(protoFunction.base.extensionReceiver.base.symbol).signatureId + } ?: InvalidIndex + val dispatchReceiverSig = irFunction.dispatchReceiverParameter?.let { + BinarySymbolData.decode(protoFunction.base.dispatchReceiver.base.symbol).signatureId + } ?: InvalidIndex + + return SerializedInlineFunctionReference(fileDeserializationState.fileIndex, functionSignature, protoFunction.base.body, + irFunction.startOffset, irFunction.endOffset, extensionReceiverSig, dispatchReceiverSig, + valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray()) + } + + fun buildClassFields(irClass: IrClass, fields: List): SerializedClassFields { + val signature = irClass.symbol.signature + ?: error("No signature for ${irClass.render()}") + val topLevelSignature = signature.topLevelSignature() + val fileDeserializationState = moduleReversedFileIndex[topLevelSignature] + ?: error("No file deserializer for ${topLevelSignature.render()}") + val fileDeserializer = fileDeserializationState.fileDeserializer + val declarationIndex = fileDeserializer.reversedSignatureIndex[topLevelSignature] + ?: error("No declaration for ${topLevelSignature.render()}") + val fileReader = fileDeserializationState.fileReader + val symbolDeserializer = fileDeserializer.symbolDeserializer + val protoDeclaration = fileReader.declaration(declarationIndex) + + val outerClasses = irClass.getOuterClasses(takeOnlyInner = false) + require(outerClasses.first().parent is IrFile) { "Local classes are not supported: ${irClass.render()}" } + + val typeParameterSigs = mutableListOf() + var protoClass = protoDeclaration.irClass + val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner } + for (classIndex in outerClasses.indices) { + if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) { + (0 until protoClass.typeParameterCount).mapTo(typeParameterSigs) { + BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId + } + } + if (classIndex < outerClasses.size - 1) + protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer) + } + + val protoFields = mutableListOf() + for (i in 0 until protoClass.declarationCount) { + val declaration = protoClass.getDeclaration(i) + if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_FIELD) + protoFields.add(declaration.irField) + else if (declaration.declaratorCase == ProtoDeclaration.DeclaratorCase.IR_PROPERTY) { + val protoProperty = declaration.irProperty + if (protoProperty.hasBackingField()) + protoFields.add(protoProperty.backingField) + } + } + val protoFieldsMap = mutableMapOf() + protoFields.forEach { + val nameAndType = BinaryNameAndType.decode(it.nameType) + val name = fileReader.string(nameAndType.nameIndex) + val prev = protoFieldsMap[name] + if (prev != null) + error("Class ${irClass.render()} has two fields with same name '$name'") + protoFieldsMap[name] = it + } + + val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures + return SerializedClassFields( + fileDeserializationState.fileIndex, + BinarySymbolData.decode(protoClass.base.symbol).signatureId, + typeParameterSigs.toIntArray(), + Array(fields.size) { + val field = fields[it] + val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}") + val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}") + val nameAndType = BinaryNameAndType.decode(protoField.nameType) + var flags = 0 + if (field.isConst) + flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST + if (field.hasConstInitializer) + flags = flags or SerializedClassFieldInfo.FLAG_CONST_INITIALIZER + val classifier = irField.type.classifierOrNull ?: error("Fields of type ${irField.type.render()} are not supported") + val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull() + + SerializedClassFieldInfo( + nameAndType.nameIndex, + primitiveBinaryType?.ordinal ?: InvalidIndex, + if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false) + InvalidIndex + else nameAndType.typeIndex, + flags) + }) + } } private inner class KonanInteropModuleDeserializer( @@ -121,14 +544,15 @@ internal class KonanIrLinker( private val isLibraryCached: Boolean ) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { init { - assert(klib.isInteropLibrary()) + require(klib.isInteropLibrary()) } private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder( moduleDescriptor, KonanManglerDesc, DescriptorByIdSignatureFinder.LookupMode.MODULE_ONLY ) - private fun IdSignature.isInteropSignature(): Boolean = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() + + private fun IdSignature.isInteropSignature() = IdSignature.Flags.IS_NATIVE_INTEROP_LIBRARY.test() override fun contains(idSig: IdSignature): Boolean { if (idSig.isPubliclyVisible) { @@ -170,9 +594,233 @@ internal class KonanIrLinker( override val moduleDependencies: Collection = listOfNotNull(forwardDeclarationDeserializer) } + inner class KonanCachedLibraryModuleDeserializer( + moduleDescriptor: ModuleDescriptor, + override val klib: KotlinLibrary + ) : IrModuleDeserializer(moduleDescriptor, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT) { + + private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinder( + moduleDescriptor, KonanManglerDesc, + DescriptorByIdSignatureFinder.LookupMode.MODULE_ONLY + ) + + override fun contains(idSig: IdSignature) = + idSig.isPubliclyVisible && descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) != null + + override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + val descriptor = descriptorByIdSignatureFinder.findDescriptorBySignature(idSig) + ?: error("Expecting descriptor for $idSig") + + return (stubGenerator.generateMemberStub(descriptor) as IrSymbolOwner).symbol + } + + override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns) + + override val moduleDependencies by lazy { + moduleDescriptor.allDependencyModules + .filter { it != moduleDescriptor } + .map { resolveModuleDeserializer(it, null) } + } + + inner class FileDeserializationInfo(val fileReader: IrLibraryFileFromBytes, val file: IrFile, + val declarationDeserializer: IrDeclarationDeserializer, + val fakeOverrideBuilder: FakeOverrideBuilder) + + private val filesDeserializationInfo by lazy { + val result = mutableListOf() + val fileCount = klib.fileCount() + + for (i in 0 until fileCount) { + val fileStream = klib.file(i).codedInputStream + val fileProto = ProtoFile.parseFrom(fileStream, ExtensionRegistryLite.newInstance()) + + val fileReader = IrLibraryFileFromBytes(IrKlibBytesSource(klib, i)) + val file = fileReader.createFile(moduleFragment, fileProto) + + val symbolDeserializer = IrSymbolDeserializer( + symbolTable, fileReader, file.symbol, emptyList(), { }, { _, symbol -> symbol }) + { idSig, symbolKind -> + val topLevelSig = idSig.topLevelSignature() + val actualModuleDeserializer = resolveModuleDeserializer(moduleDescriptor, null) + .findModuleDeserializerForTopLevelId(topLevelSig) + ?: handleSignatureIdNotFoundInModuleWithDependencies(idSig, this) + + actualModuleDeserializer.deserializeIrSymbol(idSig, symbolKind) + } + + val fakeOverrideBuilder = FakeOverrideBuilder( + object : FileLocalAwareLinker { + override fun tryReferencingSimpleFunctionByLocalSignature(parent: IrDeclaration, idSignature: IdSignature) = + if (idSignature.isPubliclyVisible) null else symbolDeserializer.referenceSimpleFunctionByLocalSignature(idSignature) + + override fun tryReferencingPropertyByLocalSignature(parent: IrDeclaration, idSignature: IdSignature) = + if (idSignature.isPubliclyVisible) null else symbolDeserializer.referencePropertyByLocalSignature(idSignature) + }, + symbolTable, KonanManglerIr, IrTypeSystemContextImpl(builtIns), KonanFakeOverrideClassFilter) + + val declarationDeserializer = IrDeclarationDeserializer( + builtIns, + symbolTable, + IrFactoryImpl, + fileReader, + file, + allowErrorNodes = false, + deserializeInlineFunctions = true, + deserializeBodies = true, + symbolDeserializer, + fakeOverrideBuilder.platformSpecificClassFilter, + fakeOverrideBuilder, + compatibilityMode = CompatibilityMode(libraryAbiVersion) + ) + + result.add(FileDeserializationInfo(fileReader, file, declarationDeserializer, fakeOverrideBuilder)) + } + + result + } + + private val inlineFunctionReferences by lazy { + cachedLibraries.getLibraryCache(klib)!!.serializedInlineFunctionBodies.associateBy { + filesDeserializationInfo[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.functionSignature) + } + } + + private val inlineFunctionFiles = mutableMapOf() + + fun deserializeInlineFunction(function: IrFunction): InlineFunctionOriginInfo { + val packageFragment = function.findPackage() as? IrExternalPackageFragment + ?: error("Expected an external package fragment for ${function.render()}") + if (function.parents.any { (it as? IrFunction)?.isInline == true}) { + // Already deserialized by the top-most inline function. + return InlineFunctionOriginInfo( + inlineFunctionFiles[packageFragment] + ?: error("${function.render()} should've been deserialized along with its parent"), + function.startOffset, function.endOffset + ) + } + + val signature = function.symbol.signature + ?: error("No signature for ${function.render()}") + val inlineFunctionReference = inlineFunctionReferences[signature] + ?: error("No inline function reference for ${function.render()}, sig = ${signature.render()}") + val fileDeserializationInfo = filesDeserializationInfo[inlineFunctionReference.file] + val declarationDeserializer = fileDeserializationInfo.declarationDeserializer + val symbolDeserializer = declarationDeserializer.symbolDeserializer + + val outerClasses = (function.parent as? IrClass)?.getOuterClasses(takeOnlyInner = true) ?: emptyList() + require((outerClasses.getOrNull(0)?.firstNonClassParent ?: function.parent) is IrExternalPackageFragment) { + "Local inline functions are not supported: ${function.render()}" + } + + var endToEndTypeParameterIndex = 0 + outerClasses.forEach { outerClass -> + outerClass.typeParameters.forEach { parameter -> + val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++] + symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex)) + } + } + function.typeParameters.forEach { parameter -> + val sigIndex = inlineFunctionReference.typeParameterSigs[endToEndTypeParameterIndex++] + symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex)) + } + function.valueParameters.forEachIndexed { index, parameter -> + val sigIndex = inlineFunctionReference.valueParameterSigs[index] + symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex)) + } + function.extensionReceiverParameter?.let { parameter -> + val sigIndex = inlineFunctionReference.extensionReceiverSig + require(sigIndex != InvalidIndex) { "Expected a valid sig reference to the extension receiver for ${function.render()}" } + symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex)) + } + function.dispatchReceiverParameter?.let { parameter -> + val sigIndex = inlineFunctionReference.dispatchReceiverSig + require(sigIndex != InvalidIndex) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" } + symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex)) + } + + function.body = declarationDeserializer.deserializeStatementBody(inlineFunctionReference.body) as IrBody + + function.valueParameters.forEachIndexed { index, parameter -> + val defaultValueIndex = inlineFunctionReference.defaultValues[index] + if (defaultValueIndex != InvalidIndex) + parameter.defaultValue = declarationDeserializer.deserializeExpressionBody(defaultValueIndex) + } + + fileDeserializationInfo.fakeOverrideBuilder.provideFakeOverrides() + + inlineFunctionFiles[packageFragment]?.let { + require(it == fileDeserializationInfo.file) { + "Different files ${it.fileEntry.name} and ${fileDeserializationInfo.file.fileEntry.name} have the same $packageFragment" + } + } + inlineFunctionFiles[packageFragment] = fileDeserializationInfo.file + + return InlineFunctionOriginInfo(fileDeserializationInfo.file, inlineFunctionReference.startOffset, inlineFunctionReference.endOffset) + } + + private val classesFields by lazy { + cachedLibraries.getLibraryCache(klib)!!.serializedClassFields.associateBy { + filesDeserializationInfo[it.file].declarationDeserializer.symbolDeserializer.deserializeIdSignature(it.classSignature) + } + } + + fun deserializeClassFields(irClass: IrClass): List { + val signature = irClass.symbol.signature + ?: error("No signature for ${irClass.render()}") + val serializedClassFields = classesFields[signature] + ?: error("No class fields for ${irClass.render()}, sig = ${signature.render()}") + val fileDeserializationInfo = filesDeserializationInfo[serializedClassFields.file] + val declarationDeserializer = fileDeserializationInfo.declarationDeserializer + val symbolDeserializer = declarationDeserializer.symbolDeserializer + + val outerClasses = irClass.getOuterClasses(takeOnlyInner = true) + require(outerClasses.first().firstNonClassParent is IrExternalPackageFragment) { + "Local classes are not supported: ${irClass.render()}" + } + + var endToEndTypeParameterIndex = 0 + outerClasses.forEach { outerClass -> + outerClass.typeParameters.forEach { parameter -> + val sigIndex = serializedClassFields.typeParameterSigs[endToEndTypeParameterIndex++] + symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex)) + } + } + + fun getByClassId(classId: ClassId): IrClassSymbol { + val classIdSig = getPublicSignature(classId.packageFqName, classId.relativeClassName.asString()) + return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol + } + + return serializedClassFields.fields.map { + val name = fileDeserializationInfo.fileReader.string(it.name) + val type = when { + it.type != InvalidIndex -> declarationDeserializer.deserializeIrType(it.type) + it.binaryType == InvalidIndex -> builtIns.anyNType + else -> when (PrimitiveBinaryType.values().getOrNull(it.binaryType)) { + PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType + PrimitiveBinaryType.BYTE -> builtIns.byteType + PrimitiveBinaryType.SHORT -> builtIns.shortType + PrimitiveBinaryType.INT -> builtIns.intType + PrimitiveBinaryType.LONG -> builtIns.longType + PrimitiveBinaryType.FLOAT -> builtIns.floatType + PrimitiveBinaryType.DOUBLE -> builtIns.doubleType + PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType + PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType + else -> error("Bad binary type of field $name of ${irClass.render()}") + } + } + ClassLayoutBuilder.FieldInfo( + name, type, + isConst = (it.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0, + hasConstInitializer = (it.flags and SerializedClassFieldInfo.FLAG_CONST_INITIALIZER) != 0, + irField = null) + } + } + } + private inner class KonanForwardDeclarationModuleDeserializer(moduleDescriptor: ModuleDescriptor) : IrModuleDeserializer(moduleDescriptor, KotlinAbiVersion.CURRENT) { init { - assert(moduleDescriptor.isForwardDeclarationModule) + require(moduleDescriptor.isForwardDeclarationModule) } private val declaredDeclaration = mutableMapOf() @@ -190,10 +838,10 @@ internal class KonanIrLinker( override fun contains(idSig: IdSignature): Boolean = idSig.isForwardDeclarationSignature() private fun resolveDescriptor(idSig: IdSignature): ClassDescriptor = - with(idSig as IdSignature.CommonSignature) { - val classId = ClassId(packageFqName(), FqName(declarationFqName), false) - moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig") - } + with(idSig as IdSignature.CommonSignature) { + val classId = ClassId(packageFqName(), FqName(declarationFqName), false) + moduleDescriptor.findClassAcrossModuleDependencies(classId) ?: error("No declaration found with $idSig") + } private fun buildForwardDeclarationStub(descriptor: ClassDescriptor): IrClass { return stubGenerator.generateClassStub(descriptor).also { @@ -202,7 +850,9 @@ internal class KonanIrLinker( } 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)" } + require(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) {