From 6b80c00cc6f16e72c8d10a33ce119c167f943471 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Tue, 13 Apr 2021 15:11:50 +0300 Subject: [PATCH] JVM_IR: deserialize lazy declarations --- .../backend/jvm/JvmGeneratorExtensionsImpl.kt | 21 +- .../kotlin/backend/jvm/JvmIrCodegenFactory.kt | 3 +- .../kotlin/backend/jvm/JvmFileFacadeClass.kt | 42 ++++ .../DeclarationStubGeneratorImpl.kt | 9 +- .../ir/declarations/impl/IrClassImpl.kt | 2 +- .../ir/declarations/lazy/IrLazyClass.kt | 13 +- .../ir/declarations/lazy/IrLazyFunction.kt | 17 +- .../ir/declarations/lazy/LazyIrFactory.kt | 158 +++++++++++++++ .../ir/util/DeclarationStubGenerator.kt | 4 +- .../kotlin/ir/util/StubGeneratorExtensions.kt | 36 +++- .../IrDeclarationDeserializer.kt | 6 +- compiler/ir/serialization.jvm/src/JvmIr.proto | 48 ----- .../deserializeLazyDeclarations.kt | 180 ++++++++++++++++++ .../backend/handlers/IrTextDumpHandler.kt | 2 +- .../kotlin/ir/AbstractIrTextTestCase.kt | 2 +- 15 files changed, 468 insertions(+), 75 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmFileFacadeClass.kt create mode 100644 compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/LazyIrFactory.kt create mode 100644 compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt index 12d1599f1b3..941131ebf2f 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol +import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor @@ -74,13 +75,19 @@ open class JvmGeneratorExtensionsImpl(private val generateFacades: Boolean = tru else IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB - override fun generateFacadeClass(irFactory: IrFactory, source: DeserializedContainerSource): IrClass? { - if (!generateFacades || source !is JvmPackagePartSource) return null - val facadeName = source.facadeClassName ?: source.className - return irFactory.buildClass { - origin = if (source.facadeClassName != null) IrDeclarationOrigin.JVM_MULTIFILE_CLASS else IrDeclarationOrigin.FILE_CLASS - name = facadeName.fqNameForTopLevelClassMaybeWithDollars.shortName() - }.also { + override fun generateFacadeClass( + irFactory: IrFactory, + deserializedSource: DeserializedContainerSource, + stubGenerator: DeclarationStubGenerator + ): IrClass? { + if (!generateFacades || deserializedSource !is JvmPackagePartSource) return null + val facadeName = deserializedSource.facadeClassName ?: deserializedSource.className + return JvmFileFacadeClass( + if (deserializedSource.facadeClassName != null) IrDeclarationOrigin.JVM_MULTIFILE_CLASS else IrDeclarationOrigin.FILE_CLASS, + facadeName.fqNameForTopLevelClassMaybeWithDollars.shortName(), + deserializedSource, + stubGenerator + ).also { it.createParameterDeclarations() classNameOverride[it] = facadeName } diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index 347e58f65d7..7ec0814ceae 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrLinker import org.jetbrains.kotlin.ir.builders.TranslationPluginContext +import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.MetadataSource @@ -78,7 +79,7 @@ open class JvmIrCodegenFactory( psi2irContext.irBuiltIns.functionFactory = functionFactory val stubGenerator = - DeclarationStubGeneratorImpl(psi2irContext.moduleDescriptor, symbolTable, state.languageVersionSettings, jvmGeneratorExtensions) + DeclarationStubGeneratorImpl(psi2irContext.moduleDescriptor, symbolTable, psi2irContext.irBuiltIns, jvmGeneratorExtensions) val frontEndContext = object : TranslationPluginContext { override val moduleDescriptor: ModuleDescriptor get() = psi2irContext.moduleDescriptor diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmFileFacadeClass.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmFileFacadeClass.kt new file mode 100644 index 00000000000..bd65f2bc46f --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmFileFacadeClass.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm + +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl +import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator +import org.jetbrains.kotlin.ir.util.DeserializableClass +import org.jetbrains.kotlin.name.Name + +class JvmFileFacadeClass( + origin: IrDeclarationOrigin, + name: Name, + source: SourceElement, + private val stubGenerator: DeclarationStubGenerator +) : IrClassImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin, + IrClassSymbolImpl(), name, ClassKind.CLASS, DescriptorVisibilities.PUBLIC, Modality.FINAL, + source = source +), DeserializableClass { + + private var irLoaded: Boolean? = null + + override fun loadIr(): Boolean { + irLoaded?.let { return it } + irLoaded = stubGenerator.extensions.deserializeFacadeClass( + this, + stubGenerator.moduleDescriptor, + stubGenerator.irBuiltIns, + stubGenerator.symbolTable, + parent, + allowErrorNodes = false + ) + return irLoaded as Boolean + } +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationStubGeneratorImpl.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationStubGeneratorImpl.kt index d58ee5d0220..64a139618de 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationStubGeneratorImpl.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/DeclarationStubGeneratorImpl.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.psi2ir.generators -import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.ir.declarations.lazy.LazyScopedTypeParametersResolver import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns @@ -19,13 +18,13 @@ import org.jetbrains.kotlin.ir.util.TypeTranslator class DeclarationStubGeneratorImpl( moduleDescriptor: ModuleDescriptor, symbolTable: SymbolTable, - languageVersionSettings: LanguageVersionSettings, + irBuiltins: IrBuiltIns, extensions: StubGeneratorExtensions = StubGeneratorExtensions.EMPTY, -) : DeclarationStubGenerator(moduleDescriptor, symbolTable, extensions) { +) : DeclarationStubGenerator(moduleDescriptor, symbolTable, irBuiltins, extensions) { override val typeTranslator: TypeTranslator = TypeTranslatorImpl( lazyTable, - languageVersionSettings, + irBuiltins.languageVersionSettings, moduleDescriptor, { LazyScopedTypeParametersResolver(lazyTable) }, true, @@ -42,7 +41,7 @@ fun generateTypicalIrProviderList( extensions: StubGeneratorExtensions = StubGeneratorExtensions.EMPTY ): List { val stubGenerator = DeclarationStubGeneratorImpl( - moduleDescriptor, symbolTable, irBuiltins.languageVersionSettings, extensions + moduleDescriptor, symbolTable, irBuiltins, extensions ) return listOfNotNull(deserializer, stubGenerator) } diff --git a/compiler/ir/ir.tree.impl/src/org/jetbrains/kotlin/ir/declarations/impl/IrClassImpl.kt b/compiler/ir/ir.tree.impl/src/org/jetbrains/kotlin/ir/declarations/impl/IrClassImpl.kt index c6cd8377145..91384a17777 100644 --- a/compiler/ir/ir.tree.impl/src/org/jetbrains/kotlin/ir/declarations/impl/IrClassImpl.kt +++ b/compiler/ir/ir.tree.impl/src/org/jetbrains/kotlin/ir/declarations/impl/IrClassImpl.kt @@ -25,7 +25,7 @@ import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.name.Name -class IrClassImpl( +open class IrClassImpl( override val startOffset: Int, override val endOffset: Int, override var origin: IrDeclarationOrigin, 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 47157ee4145..902e7429782 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 @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType 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.render import org.jetbrains.kotlin.metadata.ProtoBuf @@ -40,7 +41,7 @@ class IrLazyClass( override val isFun: Boolean, override val stubGenerator: DeclarationStubGenerator, override val typeTranslator: TypeTranslator -) : IrClass(), IrLazyDeclarationBase { +) : IrClass(), IrLazyDeclarationBase, DeserializableClass { init { symbol.bind(this) } @@ -110,4 +111,14 @@ class IrLazyClass( override var metadata: MetadataSource? get() = null set(_) = error("We should never need to store metadata of external declarations.") + + private var irLoaded: Boolean? = null + + override fun loadIr(): Boolean { + assert(parent is IrPackageFragment) + irLoaded?.let { return it } + return stubGenerator.extensions.deserializeLazyClass( + this, stubGenerator, parent, allowErrorNodes = false + ).also { irLoaded = it } + } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt index d9c439b5b8e..bf000f69171 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunction.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.withScope import org.jetbrains.kotlin.name.Name @@ -48,7 +49,13 @@ class IrLazyFunction( override var annotations: List by createLazyAnnotations() - override var body: IrBody? = null + override var body: IrBody? by lazyVar { + if (!isInline) return@lazyVar null + val toplevel = getToplevel() + val loaded = (toplevel as? DeserializableClass)?.loadIR() ?: false + // Underlying field has been set by IR loading + if (loaded) body else null + } override var returnType: IrType by createReturnType() @@ -99,4 +106,12 @@ class IrLazyFunction( init { symbol.bind(this) } + + private fun getToplevel(): IrDeclaration { + var current: IrDeclarationParent = parent + while (current is IrDeclaration && current.parent !is IrPackageFragment) { + current = current.parent + } + return current as IrDeclaration + } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/LazyIrFactory.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/LazyIrFactory.kt new file mode 100644 index 00000000000..de40e626424 --- /dev/null +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/LazyIrFactory.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.declarations.lazy + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DescriptorVisibility +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.SourceElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource + +// An IrFactory that does not recreate declarations for already bound symbols. +class LazyIrFactory( + private val delegate: IrFactory, +) : IrFactory by delegate { + override fun createClass( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + symbol: IrClassSymbol, + name: Name, + kind: ClassKind, + visibility: DescriptorVisibility, + modality: Modality, + isCompanion: Boolean, + isInner: Boolean, + isData: Boolean, + isExternal: Boolean, + isInline: Boolean, + isExpect: Boolean, + isFun: Boolean, + source: SourceElement + ): IrClass = if (symbol.isBound) + symbol.owner + else + delegate.createClass( + startOffset, endOffset, origin, symbol, name, kind, visibility, modality, + isCompanion, isInner, isData, isExternal, isInline, isExpect, isFun, source + ) + + override fun createConstructor( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + symbol: IrConstructorSymbol, + name: Name, + visibility: DescriptorVisibility, + returnType: IrType, + isInline: Boolean, + isExternal: Boolean, + isPrimary: Boolean, + isExpect: Boolean, + containerSource: DeserializedContainerSource? + ): IrConstructor = if (symbol.isBound) + symbol.owner + else + delegate.createConstructor( + startOffset, endOffset, origin, symbol, name, visibility, returnType, + isInline, isExternal, isPrimary, isExpect, containerSource + ) + + override fun createEnumEntry( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + symbol: IrEnumEntrySymbol, + name: Name + ): IrEnumEntry = if (symbol.isBound) + symbol.owner + else + delegate.createEnumEntry(startOffset, endOffset, origin, symbol, name) + + override fun createField( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + symbol: IrFieldSymbol, + name: Name, + type: IrType, + visibility: DescriptorVisibility, + isFinal: Boolean, + isExternal: Boolean, + isStatic: Boolean + ): IrField = if (symbol.isBound) + symbol.owner + else + delegate.createField(startOffset, endOffset, origin, symbol, name, type, visibility, isFinal, isExternal, isStatic) + + override fun createFunction( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + symbol: IrSimpleFunctionSymbol, + name: Name, + visibility: DescriptorVisibility, + modality: Modality, + returnType: IrType, + isInline: Boolean, + isExternal: Boolean, + isTailrec: Boolean, + isSuspend: Boolean, + isOperator: Boolean, + isInfix: Boolean, + isExpect: Boolean, + isFakeOverride: Boolean, + containerSource: DeserializedContainerSource? + ): IrSimpleFunction = if (symbol.isBound) + symbol.owner + else + delegate.createFunction( + startOffset, endOffset, origin, symbol, name, visibility, modality, returnType, + isInline, isExternal, isTailrec, isSuspend, isOperator, isInfix, isExpect, isFakeOverride, containerSource + ) + + override fun createProperty( + startOffset: Int, + endOffset: Int, + origin: IrDeclarationOrigin, + symbol: IrPropertySymbol, + name: Name, + visibility: DescriptorVisibility, + modality: Modality, + isVar: Boolean, + isConst: Boolean, + isLateinit: Boolean, + isDelegated: Boolean, + isExternal: Boolean, + isExpect: Boolean, + isFakeOverride: Boolean, + containerSource: DeserializedContainerSource? + ): IrProperty = if (symbol.isBound) + symbol.owner + else + delegate.createProperty( + startOffset, endOffset, origin, symbol, name, visibility, modality, + isVar, isConst, isLateinit, isDelegated, isExternal, isExpect, isFakeOverride, containerSource + ) + + override fun createTypeAlias( + startOffset: Int, + endOffset: Int, + symbol: IrTypeAliasSymbol, + name: Name, + visibility: DescriptorVisibility, + expandedType: IrType, + isActual: Boolean, + origin: IrDeclarationOrigin + ): IrTypeAlias = if (symbol.isBound) + symbol.owner + else + delegate.createTypeAlias(startOffset, endOffset, symbol, name, visibility, expandedType, isActual, origin) +} \ No newline at end of file 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 5c65fa8d04d..91a6d3a7471 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 @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.lazy.* +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl import org.jetbrains.kotlin.ir.linkage.IrProvider import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol @@ -41,6 +42,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs abstract class DeclarationStubGenerator( val moduleDescriptor: ModuleDescriptor, val symbolTable: SymbolTable, + val irBuiltIns: IrBuiltIns, val extensions: StubGeneratorExtensions = StubGeneratorExtensions.EMPTY, ) : IrProvider { protected val lazyTable = symbolTable.lazyWrapper @@ -89,7 +91,7 @@ abstract class DeclarationStubGenerator( val packageFragment = directMember.containingDeclaration as? PackageFragmentDescriptor ?: return null val containerSource = directMember.safeAs()?.containerSource ?: return null return facadeClassMap.getOrPut(containerSource) { - extensions.generateFacadeClass(symbolTable.irFactory, containerSource)?.also { facade -> + extensions.generateFacadeClass(symbolTable.irFactory, containerSource, this)?.also { facade -> val packageStub = generateOrGetEmptyExternalPackageFragmentStub(packageFragment) facade.parent = packageStub packageStub.declarations.add(facade) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt index 3eb847a2b37..f5def8db90f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt @@ -7,23 +7,49 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin -import org.jetbrains.kotlin.ir.declarations.IrFactory +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.types.KotlinType +interface DeserializableClass { + fun loadIr(): Boolean +} + open class StubGeneratorExtensions { open fun computeExternalDeclarationOrigin(descriptor: DeclarationDescriptor): IrDeclarationOrigin? = null - open fun generateFacadeClass(irFactory: IrFactory, source: DeserializedContainerSource): IrClass? = null + open fun generateFacadeClass( + irFactory: IrFactory, + deserializedSource: DeserializedContainerSource, + stubGenerator: DeclarationStubGenerator, + ): IrClass? = null open fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean = false open fun isStaticFunction(descriptor: FunctionDescriptor): Boolean = false + open fun deserializeLazyClass( + irClass: IrLazyClass, + moduleDescriptor: ModuleDescriptor, + irBuiltIns: IrBuiltIns, + symbolTable: SymbolTable, + parent: IrDeclarationParent, + allowErrorNodes: Boolean, + ): Boolean = false + + open fun deserializeFacadeClass( + irClass: IrClass, + moduleDescriptor: ModuleDescriptor, + irBuiltIns: IrBuiltIns, + symbolTable: SymbolTable, + parent: IrDeclarationParent, + allowErrorNodes: Boolean, + ): Boolean = false + open val enhancedNullability: EnhancedNullability get() = EnhancedNullability diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt index f0f91101ec9..c6015cb8190 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrDeclarationDeserializer.kt @@ -66,7 +66,7 @@ class IrDeclarationDeserializer( private val symbolTable: SymbolTable, val irFactory: IrFactory, private val fileReader: IrLibraryFile, - private val file: IrFile, + private val parent: IrDeclarationParent, val allowErrorNodes: Boolean, private val deserializeInlineFunctions: Boolean, private var deserializeBodies: Boolean, @@ -166,7 +166,7 @@ class IrDeclarationDeserializer( } } - private var currentParent: IrDeclarationParent = file + private var currentParent: IrDeclarationParent = parent private inline fun T.usingParent(block: T.() -> Unit): T = this.apply { @@ -298,7 +298,7 @@ class IrDeclarationDeserializer( } } - private fun deserializeIrClass(proto: ProtoClass): IrClass = + fun deserializeIrClass(proto: ProtoClass): IrClass = withDeserializedIrDeclarationBase(proto.base) { symbol, signature, startOffset, endOffset, origin, fcode -> val flags = ClassFlags.decode(fcode) diff --git a/compiler/ir/serialization.jvm/src/JvmIr.proto b/compiler/ir/serialization.jvm/src/JvmIr.proto index 2056f377f9f..274adfac9f7 100644 --- a/compiler/ir/serialization.jvm/src/JvmIr.proto +++ b/compiler/ir/serialization.jvm/src/JvmIr.proto @@ -7,27 +7,6 @@ option optimize_for = LITE_RUNTIME; /* Stored in JVM .class annotations */ -//message UniqIdInfo { -// required fixed64 id = 1; -// repeated int32 toplevel_fq_name = 2; -//} - -//message SignatureTable { -// repeated common.serialization.proto.IrSignature signature = 1; -//} -// -//message TypeTable { -// repeated common.serialization.proto.IrType type = 1; -//} - -//message UniqIdTable { -// repeated UniqIdInfo infos = 1; -//} - -//message StringTable { -// repeated string string = 1; -//} - message XStatementOrExpression { oneof kind { common.serialization.proto.IrStatement statement = 1; @@ -35,38 +14,11 @@ message XStatementOrExpression { } } -//message StatementsAndExpressionsTable { -// repeated XStatementOrExpression statement_or_expression = 1; -//} - -//message ExternalReference { -// required fixed64 id = 1; -// required int32 index = 2; /* index into the table of packages in ExternalRefs */ -//} -// -//message JvmExternalPackage { -// repeated int32 fq_name = 1; -// required common.serialization.proto.IrDeclarationContainer declaration_container = 2; -//} - -//message ExternalRefs { -// repeated JvmExternalPackage package = 1; -// repeated ExternalReference reference = 2; -//} - message AuxTables { repeated bytes type = 1; repeated bytes signature = 2; repeated bytes string = 3; repeated bytes body = 4; - -// required TypeTable type_table = 2; -// required SignatureTable signature_table = 1; -// required StringTable string_table = 3; -// required StatementsAndExpressionsTable statements_and_expressions_table = 4; - -// required ExternalRefs external_refs = 5; -// required UniqIdTable uniq_id_table = 6; } message JvmIrFile { diff --git a/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt new file mode 100644 index 00000000000..8cb5f8a680b --- /dev/null +++ b/compiler/ir/serialization.jvm/src/org/jetbrains/kotlin/backend/jvm/serialization/deserializeLazyDeclarations.kt @@ -0,0 +1,180 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.serialization + +import org.jetbrains.kotlin.backend.common.overrides.DefaultFakeOverrideClassFilter +import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder +import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker +import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinder +import org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer +import org.jetbrains.kotlin.backend.common.serialization.IrLibraryFile +import org.jetbrains.kotlin.backend.common.serialization.IrSymbolDeserializer +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData +import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer +import org.jetbrains.kotlin.backend.jvm.serialization.proto.JvmIr +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler +import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.lazy.LazyIrFactory +import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.protobuf.ByteString + +fun deserializeClassFromByteArray( + byteArray: ByteArray, + moduleDescriptor: ModuleDescriptor, + irBuiltIns: IrBuiltIns, + symbolTable: SymbolTable, + parent: IrDeclarationParent, + allowErrorNodes: Boolean, +) { + val irProto = JvmIr.JvmIrClass.parseFrom(byteArray) + val irLibraryFile = IrLibraryFileFromAnnotation( + irProto.auxTables.typeList, + irProto.auxTables.signatureList, + irProto.auxTables.stringList, + irProto.auxTables.bodyList + ) + val descriptorFinder = + DescriptorByIdSignatureFinder(moduleDescriptor, JvmDescriptorMangler(null), DescriptorByIdSignatureFinder.LookupMode.MODULE_WITH_DEPENDENCIES) + val symbolDeserializer = IrSymbolDeserializer( + symbolTable, + irLibraryFile, + /* TODO */ actuals = emptyList(), + enqueueLocalTopLevelDeclaration = {}, // just link to it in symbolTable + handleExpectActualMapping = { _, _ -> TODO() }, + deserializePublicSymbol = { idSignature, symbolKind -> + referencePublicSymbol(symbolTable, descriptorFinder, idSignature, symbolKind) + } + ) + + val lazyIrFactory = LazyIrFactory(irBuiltIns.irFactory) + + val deserializer = IrDeclarationDeserializer( + irBuiltIns, symbolTable, lazyIrFactory, irLibraryFile, parent, + allowErrorNodes = allowErrorNodes, + deserializeInlineFunctions = true, + deserializeBodies = true, + symbolDeserializer, + DefaultFakeOverrideClassFilter, + makeEmptyFakeOverrideBuilder(symbolTable, irBuiltIns) + ) + + deserializer.deserializeIrClass(irProto.irClass) +} + +fun deserializeIrFileFromByteArray( + byteArray: ByteArray, + moduleDescriptor: ModuleDescriptor, + irBuiltIns: IrBuiltIns, + symbolTable: SymbolTable, + facadeClass: IrClass, + allowErrorNodes: Boolean, +) { + val irProto = JvmIr.JvmIrFile.parseFrom(byteArray) + val irLibraryFile = IrLibraryFileFromAnnotation( + irProto.auxTables.typeList, + irProto.auxTables.signatureList, + irProto.auxTables.stringList, + irProto.auxTables.bodyList + ) + val descriptorFinder = + DescriptorByIdSignatureFinder(moduleDescriptor, JvmDescriptorMangler(null), DescriptorByIdSignatureFinder.LookupMode.MODULE_WITH_DEPENDENCIES) + val symbolDeserializer = IrSymbolDeserializer( + symbolTable, + irLibraryFile, + /* TODO */ actuals = emptyList(), + enqueueLocalTopLevelDeclaration = {}, // just link to it in symbolTable + handleExpectActualMapping = { _, _ -> TODO() }, + deserializePublicSymbol = { idSignature, symbolKind -> + referencePublicSymbol(symbolTable, descriptorFinder, idSignature, symbolKind) + } + ) + + val lazyIrFactory = LazyIrFactory(irBuiltIns.irFactory) + + val deserializer = IrDeclarationDeserializer( + irBuiltIns, symbolTable, lazyIrFactory, irLibraryFile, facadeClass, + allowErrorNodes = allowErrorNodes, + deserializeInlineFunctions = true, + deserializeBodies = true, + symbolDeserializer, + DefaultFakeOverrideClassFilter, + makeEmptyFakeOverrideBuilder(symbolTable, irBuiltIns) + ) + for (declarationProto in irProto.declarationList) { + deserializer.deserializeDeclaration(declarationProto) + } +} + +private class IrLibraryFileFromAnnotation( + val types: List, + val signatures: List, + val strings: List, + val bodies: List, +) : IrLibraryFile() { + override fun irDeclaration(index: Int): ByteArray { + error("This method is never supposed to be called") + } + + override fun type(index: Int): ByteArray = types[index].toByteArray() + override fun signature(index: Int): ByteArray = signatures[index].toByteArray() + override fun string(index: Int): ByteArray = strings[index].toByteArray() + override fun body(index: Int): ByteArray = bodies[index].toByteArray() +} + +private fun referencePublicSymbol( + symbolTable: SymbolTable, + descriptorFinder: DescriptorByIdSignatureFinder, + idSig: IdSignature, + symbolKind: BinarySymbolData.SymbolKind +): IrSymbol { + with(symbolTable) { + val descriptor = descriptorFinder.findDescriptorBySignature(idSig) + return if (descriptor != null) { + when (symbolKind) { + BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClass(descriptor as ClassDescriptor) + BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructor(descriptor as ClassConstructorDescriptor) + BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntry(descriptor as ClassDescriptor) + BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceField(descriptor as PropertyDescriptor) + BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunction(descriptor as FunctionDescriptor) + BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAlias(descriptor as TypeAliasDescriptor) + BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referenceProperty(descriptor as PropertyDescriptor) + else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig") + } + } else { + when (symbolKind) { + BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClassFromLinker(idSig) + BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructorFromLinker(idSig) + BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntryFromLinker(idSig) + BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL -> referenceFieldFromLinker(idSig) + BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunctionFromLinker(idSig) + BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAliasFromLinker(idSig) + BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referencePropertyFromLinker(idSig) + else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig") + } + } + } +} + +// TODO: implement properly +private fun makeEmptyFakeOverrideBuilder(symbolTable: SymbolTable, irBuiltIns: IrBuiltIns): FakeOverrideBuilder { + return FakeOverrideBuilder( + object : FileLocalAwareLinker { + override fun tryReferencingPropertyByLocalSignature(parent: IrDeclaration, idSignature: IdSignature): IrPropertySymbol? = null + override fun tryReferencingSimpleFunctionByLocalSignature( + parent: IrDeclaration, idSignature: IdSignature + ): IrSimpleFunctionSymbol? = null + }, + symbolTable, + IdSignatureSerializer(JvmIrMangler), + irBuiltIns + ) +} + diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrTextDumpHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrTextDumpHandler.kt index 17a2e672b2a..277579ec894 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrTextDumpHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/IrTextDumpHandler.kt @@ -85,7 +85,7 @@ class IrTextDumpHandler(testServices: TestServices) : AbstractIrHandler(testServ val stubGenerator = DeclarationStubGeneratorImpl( irModule.descriptor, SymbolTable(signaturer, IrFactoryImpl), // TODO - module.languageVersionSettings + irModule.irBuiltins ) val baseFile = testServices.moduleStructure.originalTestDataFiles.first() diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt index 602c03aa4fd..2c2279da400 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/ir/AbstractIrTextTestCase.kt @@ -58,7 +58,7 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() { val stubGenerator = DeclarationStubGeneratorImpl( irModule.descriptor, SymbolTable(signaturer, IrFactoryImpl), // TODO - myEnvironment.configuration.languageVersionSettings + irModule.irBuiltins ) val path = wholeFile.path