diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt index 75af896328c..a0a671a26cf 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/klib.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl import org.jetbrains.kotlin.ir.descriptors.IrDescriptorBasedFunctionFactory import org.jetbrains.kotlin.ir.linkage.IrDeserializer +import org.jetbrains.kotlin.ir.linkage.IrProvider import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.acceptVoid @@ -56,6 +57,8 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors +import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl +import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorForNotFoundClasses import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl import org.jetbrains.kotlin.resolve.BindingContext @@ -65,6 +68,7 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.util.DummyLogger import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.utils.DFS +import org.jetbrains.kotlin.utils.addToStdlib.runIf import java.io.File val KotlinLibrary.moduleName: String @@ -159,18 +163,32 @@ fun generateIrForKlibSerialization( val feContext = psi2IrContext.run { JsIrLinker.JsFePluginContext(moduleDescriptor, symbolTable, typeTranslator, irBuiltIns) } + val stubGenerator = DeclarationStubGeneratorImpl( + psi2IrContext.moduleDescriptor, + symbolTable, + irBuiltIns, + DescriptorByIdSignatureFinderImpl(psi2IrContext.moduleDescriptor, JsManglerDesc), + ) val irLinker = JsIrLinker( psi2IrContext.moduleDescriptor, messageLogger, psi2IrContext.irBuiltIns, psi2IrContext.symbolTable, feContext, - ICData(serializedIrFiles, errorPolicy.allowErrors) + ICData(serializedIrFiles, errorPolicy.allowErrors), + stubGenerator = stubGenerator ) sortedDependencies.map { irLinker.deserializeOnlyHeaderModule(getDescriptorByLibrary(it), it) } - val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, files, irLinker, messageLogger, expectDescriptorToSymbol) + val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins( + project, + files, + irLinker, + messageLogger, + expectDescriptorToSymbol, + stubGenerator + ) if (verifySignatures) { moduleFragment.acceptVoid(ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc))) @@ -449,7 +467,6 @@ fun getIrModuleInfoForSourceFiles( symbolTable.noUnboundLeft("Unbound symbols left after linker") } - // TODO: not sure whether this check should be enabled by default. Add configuration key for it. val mangleChecker = ManglerChecker(JsManglerIr, Ir2DescriptorManglerAdapter(JsManglerDesc)) if (verifySignatures) { @@ -514,7 +531,8 @@ fun GeneratorContext.generateModuleFragmentWithPlugins( files: List, irLinker: IrDeserializer, messageLogger: IrMessageLogger, - expectDescriptorToSymbol: MutableMap? = null + expectDescriptorToSymbol: MutableMap? = null, + stubGenerator: DeclarationStubGenerator? = null ): IrModuleFragment { val psi2Ir = Psi2IrTranslator(languageVersionSettings, configuration) @@ -535,12 +553,25 @@ fun GeneratorContext.generateModuleFragmentWithPlugins( for (extension in extensions) { psi2Ir.addPostprocessingStep { module -> - extension.generate(module, pluginContext) + val old = stubGenerator?.unboundSymbolGeneration + try { + stubGenerator?.unboundSymbolGeneration = true + extension.generate(module, pluginContext) + } finally { + stubGenerator?.unboundSymbolGeneration = old!! + } } } + } - return psi2Ir.generateModuleFragment(this, files, listOf(irLinker), extensions, expectDescriptorToSymbol) + return psi2Ir.generateModuleFragment( + this, + files, + listOf(stubGenerator ?: irLinker), + extensions, + expectDescriptorToSymbol + ) } private fun createBuiltIns(storageManager: StorageManager) = object : KotlinBuiltIns(storageManager) {} diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt index 35bb15b827f..201968dc7e4 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsIrLinker.kt @@ -7,11 +7,17 @@ package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideBuilder import org.jetbrains.kotlin.backend.common.serialization.* +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsSupport -import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.builders.TranslationPluginContext +import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl +import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.library.IrLibrary @@ -24,7 +30,8 @@ class JsIrLinker( override val translationPluginContext: TranslationPluginContext?, private val icData: ICData? = null, friendModules: Map> = emptyMap(), - override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols = false) + override val unlinkedDeclarationsSupport: UnlinkedDeclarationsSupport = JsUnlinkedDeclarationsSupport(allowUnboundSymbols = false), + private val stubGenerator: DeclarationStubGenerator? = null ) : KotlinIrLinker( currentModule = currentModule, messageLogger = messageLogger, @@ -46,9 +53,17 @@ class JsIrLinker( private val IrLibrary.libContainsErrorCode: Boolean get() = this is KotlinLibrary && this.containsErrorCode - override fun createModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: KotlinLibrary?, strategyResolver: (String) -> DeserializationStrategy): IrModuleDeserializer { + override fun createModuleDeserializer( + moduleDescriptor: ModuleDescriptor, + klib: KotlinLibrary?, + strategyResolver: (String) -> DeserializationStrategy + ): IrModuleDeserializer { require(klib != null) { "Expecting kotlin library" } - return JsModuleDeserializer(moduleDescriptor, klib, strategyResolver, klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT, klib.libContainsErrorCode) + val libraryAbiVersion = klib.versions.abiVersion ?: KotlinAbiVersion.CURRENT + return when (val lazyIrGenerator = stubGenerator) { + null -> JsModuleDeserializer(moduleDescriptor, klib, strategyResolver, libraryAbiVersion, klib.libContainsErrorCode) + else -> JsLazyIrModuleDeserializer(moduleDescriptor, libraryAbiVersion, builtIns, lazyIrGenerator) + } } private inner class JsModuleDeserializer(moduleDescriptor: ModuleDescriptor, klib: IrLibrary, strategyResolver: (String) -> DeserializationStrategy, libraryAbiVersion: KotlinAbiVersion, allowErrorCode: Boolean) : diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt new file mode 100644 index 00000000000..38c13d3cfd5 --- /dev/null +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsLazyIrModuleDeserializer.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2010-2022 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.backend.js.lower.serialization.ir + +import org.jetbrains.kotlin.backend.common.serialization.DescriptorByIdSignatureFinderImpl +import org.jetbrains.kotlin.backend.common.serialization.IrModuleDeserializer +import org.jetbrains.kotlin.backend.common.serialization.IrModuleDeserializerKind +import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.IrBuiltIns +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.IrField +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl +import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol +import org.jetbrains.kotlin.ir.symbols.IrSymbol +import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator +import org.jetbrains.kotlin.ir.util.IdSignature +import org.jetbrains.kotlin.library.KotlinAbiVersion + + +class JsLazyIrModuleDeserializer( + moduleDescriptor: ModuleDescriptor, + libraryAbiVersion: KotlinAbiVersion, + private val builtIns: IrBuiltIns, + private val stubGenerator: DeclarationStubGenerator +) : IrModuleDeserializer(moduleDescriptor, libraryAbiVersion) { + private val dependencies = emptyList() + + // TODO: implement proper check whether `idSig` belongs to this module + override fun contains(idSig: IdSignature): Boolean = true + + private val descriptorFinder = DescriptorByIdSignatureFinderImpl(moduleDescriptor, JsManglerDesc) + + private fun resolveDescriptor(idSig: IdSignature): DeclarationDescriptor { + return descriptorFinder.findDescriptorBySignature(idSig) ?: error("No descriptor found for $idSig") + } + + override fun deserializeIrSymbol(idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol { + val descriptor = resolveDescriptor(idSig) + + val declaration = stubGenerator.run { + when (symbolKind) { + BinarySymbolData.SymbolKind.CLASS_SYMBOL -> generateClassStub(descriptor as ClassDescriptor) + BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> generatePropertyStub(descriptor as PropertyDescriptor) + BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> generateFunctionStub(descriptor as FunctionDescriptor) + BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> generateConstructorStub(descriptor as ClassConstructorDescriptor) + BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> generateEnumEntryStub(descriptor as ClassDescriptor) + BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> generateTypeAliasStub(descriptor as TypeAliasDescriptor) + else -> error("Unexpected type $symbolKind for sig $idSig") + } + } + + return declaration.symbol + } + + @OptIn(ObsoleteDescriptorBasedAPI::class) + override fun declareIrSymbol(symbol: IrSymbol) { + if (symbol is IrFieldSymbol) { + declareFieldStub(symbol) + } else { + stubGenerator.generateMemberStub(symbol.descriptor) + } + } + + @OptIn(ObsoleteDescriptorBasedAPI::class) + private fun declareFieldStub(symbol: IrFieldSymbol): IrField { + return with(stubGenerator) { + val old = stubGenerator.unboundSymbolGeneration + try { + stubGenerator.unboundSymbolGeneration = true + generateFieldStub(symbol.descriptor) + } finally { + stubGenerator.unboundSymbolGeneration = old + } + } + } + + + override val moduleFragment: IrModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, emptyList()) + override val moduleDependencies: Collection = dependencies + + override val kind get() = IrModuleDeserializerKind.SYNTHETIC +} +