From 5d6ca27c93b5fd22965b4d09c30765d6729d04f7 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 13 Sep 2021 23:42:32 +0200 Subject: [PATCH] JVM IR: introduce CodegenFactory.convertToIr The steps of psi2ir and JVM backend need to be separated in the API because in case of cyclic module dependencies (which are allowed in JPS) psi2ir should be run first on all sources, and then JVM backend on each module separately. `CodegenFactory.convertToIr` does nothing in the old backend. Also, move the ignoreErrors to GenerationState for simplicity. --- .../kotlin/codegen/CodegenFactory.kt | 38 ++++++++++++++-- .../kotlin/codegen/KotlinCodegenFacade.java | 7 ++- .../kotlin/codegen/state/GenerationState.kt | 10 +++-- .../kotlin/backend/jvm/JvmIrCodegenFactory.kt | 43 ++++++++----------- .../kotlin/test/backend/ir/IrBackendInput.kt | 2 + .../test/backend/ir/JvmIrBackendFacade.kt | 4 +- .../classic/ClassicFrontend2IrConverter.kt | 5 ++- .../frontend/fir/Fir2IrResultsConverter.kt | 2 +- .../plugin/impl/KJvmReplCompilerBase.kt | 6 ++- 9 files changed, 79 insertions(+), 38 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenFactory.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenFactory.kt index 224882e1080..b1d1bf12fa0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenFactory.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenFactory.kt @@ -16,15 +16,43 @@ package org.jetbrains.kotlin.codegen +import com.intellij.openapi.project.Project import com.intellij.util.containers.MultiMap import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingContext interface CodegenFactory { - fun generateModule(state: GenerationState, files: Collection) + fun convertToIr(input: IrConversionInput): BackendInput + + fun generateModule(state: GenerationState, input: BackendInput) + + class IrConversionInput( + val project: Project, + val files: Collection, + val configuration: CompilerConfiguration, + val module: ModuleDescriptor, + val bindingContext: BindingContext, + val languageVersionSettings: LanguageVersionSettings, + val ignoreErrors: Boolean, + ) { + companion object { + fun fromGenerationState(state: GenerationState): IrConversionInput = + with(state) { + IrConversionInput( + project, files, configuration, module, originalFrontendBindingContext, languageVersionSettings, ignoreErrors + ) + } + } + } + + interface BackendInput companion object { fun doCheckCancelled(state: GenerationState) { @@ -36,11 +64,15 @@ interface CodegenFactory { } object DefaultCodegenFactory : CodegenFactory { - override fun generateModule(state: GenerationState, files: Collection) { + object DummyOldBackendInput : CodegenFactory.BackendInput + + override fun convertToIr(input: CodegenFactory.IrConversionInput): CodegenFactory.BackendInput = DummyOldBackendInput + + override fun generateModule(state: GenerationState, input: CodegenFactory.BackendInput) { val filesInPackages = MultiMap() val filesInMultifileClasses = MultiMap() - for (file in files) { + for (file in state.files) { val fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(file) if (fileClassInfo.withJvmMultifileClass) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java index bf9d4c7afc1..a51d05134e9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/KotlinCodegenFacade.java @@ -32,7 +32,12 @@ public class KotlinCodegenFacade { ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); - state.getCodegenFactory().generateModule(state, state.getFiles()); + CodegenFactory.IrConversionInput psi2irInput = CodegenFactory.IrConversionInput.Companion.fromGenerationState(state); + CodegenFactory.BackendInput backendInput = state.getCodegenFactory().convertToIr(psi2irInput); + + ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); + + state.getCodegenFactory().generateModule(state, backendInput); CodegenFactory.Companion.doCheckCancelled(state); state.getFactory().done(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index 7c5c2ccf131..5cf29511774 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -67,9 +67,9 @@ class GenerationState private constructor( private val onIndependentPartCompilationEnd: GenerationStateEventCallback, wantsDiagnostics: Boolean, val jvmBackendClassResolver: JvmBackendClassResolver, - val isIrBackend: Boolean + val isIrBackend: Boolean, + val ignoreErrors: Boolean, ) { - class Builder( private val project: Project, private val builderFactory: ClassBuilderFactory, @@ -118,12 +118,16 @@ class GenerationState private constructor( fun isIrBackend(v: Boolean) = apply { isIrBackend = v } + var ignoreErrors: Boolean = false + fun ignoreErrors(v: Boolean): Builder = + apply { ignoreErrors = v } + fun build() = GenerationState( project, builderFactory, module, bindingContext, files, configuration, generateDeclaredClassFilter, codegenFactory, targetId, moduleName, outDirectory, onIndependentPartCompilationEnd, wantsDiagnostics, - jvmBackendClassResolver, isIrBackend + jvmBackendClassResolver, isIrBackend, ignoreErrors ) } 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 5ac85cab269..62b04404e41 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 @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.linkage.IrProvider import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl @@ -45,7 +44,6 @@ open class JvmIrCodegenFactory( private val jvmGeneratorExtensions: JvmGeneratorExtensionsImpl = JvmGeneratorExtensionsImpl(configuration), ) : CodegenFactory { data class JvmIrBackendInput( - val state: GenerationState, val irModuleFragment: IrModuleFragment, val symbolTable: SymbolTable, val phaseConfig: PhaseConfig?, @@ -53,26 +51,20 @@ open class JvmIrCodegenFactory( val extensions: JvmGeneratorExtensionsImpl, val backendExtension: JvmBackendExtension, val notifyCodegenStart: () -> Unit, - ) + ) : CodegenFactory.BackendInput - override fun generateModule(state: GenerationState, files: Collection) { - val input = convertToIr(state, files) - doGenerateFilesInternal(input) - } - - @JvmOverloads - fun convertToIr(state: GenerationState, files: Collection, ignoreErrors: Boolean = false): JvmIrBackendInput { + override fun convertToIr(input: CodegenFactory.IrConversionInput): JvmIrBackendInput { val (mangler, symbolTable) = if (externalSymbolTable != null) externalMangler!! to externalSymbolTable else { - val mangler = JvmDescriptorMangler(MainFunctionDetector(state.bindingContext, state.languageVersionSettings)) + val mangler = JvmDescriptorMangler(MainFunctionDetector(input.bindingContext, input.languageVersionSettings)) val symbolTable = SymbolTable(JvmIdSignatureDescriptor(mangler), IrFactoryImpl, JvmNameProvider) mangler to symbolTable } - val psi2ir = Psi2IrTranslator(state.languageVersionSettings, Psi2IrConfiguration(ignoreErrors)) - val messageLogger = state.configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None - val psi2irContext = psi2ir.createGeneratorContext(state.module, state.bindingContext, symbolTable, jvmGeneratorExtensions) - val pluginExtensions = IrGenerationExtension.getInstances(state.project) + val psi2ir = Psi2IrTranslator(input.languageVersionSettings, Psi2IrConfiguration(input.ignoreErrors)) + val messageLogger = input.configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None + val psi2irContext = psi2ir.createGeneratorContext(input.module, input.bindingContext, symbolTable, jvmGeneratorExtensions) + val pluginExtensions = IrGenerationExtension.getInstances(input.project) val stubGenerator = DeclarationStubGeneratorImpl(psi2irContext.moduleDescriptor, symbolTable, psi2irContext.irBuiltIns, jvmGeneratorExtensions) @@ -111,7 +103,7 @@ open class JvmIrCodegenFactory( } } - SourceDeclarationsPreprocessor(psi2irContext).run(files) + SourceDeclarationsPreprocessor(psi2irContext).run(input.files) for (extension in pluginExtensions) { psi2ir.addPostprocessingStep { module -> @@ -143,7 +135,7 @@ open class JvmIrCodegenFactory( val irProviders = listOf(irLinker) val irModuleFragment = - psi2ir.generateModuleFragment(psi2irContext, files, irProviders, pluginExtensions, expectDescriptorToSymbol = null) + psi2ir.generateModuleFragment(psi2irContext, input.files, irProviders, pluginExtensions, expectDescriptorToSymbol = null) irLinker.postProcess() stubGenerator.unboundSymbolGeneration = true @@ -151,13 +143,12 @@ open class JvmIrCodegenFactory( // We need to compile all files we reference in Klibs irModuleFragment.files.addAll(dependencies.flatMap { it.files }) - if (!state.configuration.getBoolean(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT)) { - val originalBindingContext = state.originalFrontendBindingContext as? CleanableBindingContext - ?: error("BindingContext should be cleanable in JVM IR to avoid leaking memory: ${state.originalFrontendBindingContext}") + if (!input.configuration.getBoolean(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT)) { + val originalBindingContext = input.bindingContext as? CleanableBindingContext + ?: error("BindingContext should be cleanable in JVM IR to avoid leaking memory: ${input.bindingContext}") originalBindingContext.clear() } return JvmIrBackendInput( - state, irModuleFragment, symbolTable, phaseConfig, @@ -177,8 +168,9 @@ open class JvmIrCodegenFactory( return result.toList() } - fun doGenerateFilesInternal(input: JvmIrBackendInput) { - val (state, irModuleFragment, symbolTable, customPhaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart) = input + override fun generateModule(state: GenerationState, input: CodegenFactory.BackendInput) { + val (irModuleFragment, symbolTable, customPhaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart) = + input as JvmIrBackendInput val irSerializer = if (state.configuration.getBoolean(JVMConfigurationKeys.SERIALIZE_IR)) JvmIrSerializerImpl(state.configuration) else null @@ -208,9 +200,10 @@ open class JvmIrCodegenFactory( notifyCodegenStart: () -> Unit = {} ) { val irProviders = configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions) - doGenerateFilesInternal( + generateModule( + state, JvmIrBackendInput( - state, irModuleFragment, symbolTable, phaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart + irModuleFragment, symbolTable, phaseConfig, irProviders, extensions, backendExtension, notifyCodegenStart ) ) } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrBackendInput.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrBackendInput.kt index c9e21b8bc17..ca92efdbb4b 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrBackendInput.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrBackendInput.kt @@ -6,11 +6,13 @@ package org.jetbrains.kotlin.test.backend.ir import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory +import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.test.model.BackendKinds import org.jetbrains.kotlin.test.model.ResultingArtifact // IR backend (JVM, JS, Native) data class IrBackendInput( + val state: GenerationState, val backendInput: JvmIrCodegenFactory.JvmIrBackendInput ) : ResultingArtifact.BackendInput() { override val kind: BackendKinds.IrBackend diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/JvmIrBackendFacade.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/JvmIrBackendFacade.kt index 1e21f3e79c8..f0a1ce8aeea 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/JvmIrBackendFacade.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/JvmIrBackendFacade.kt @@ -22,10 +22,10 @@ class JvmIrBackendFacade( module: TestModule, inputArtifact: IrBackendInput ): BinaryArtifacts.Jvm? { - val state = inputArtifact.backendInput.state + val state = inputArtifact.state val codegenFactory = state.codegenFactory as JvmIrCodegenFactory try { - codegenFactory.doGenerateFilesInternal(inputArtifact.backendInput) + codegenFactory.generateModule(state, inputArtifact.backendInput) } catch (e: BackendException) { if (CodegenTestDirectives.IGNORE_ERRORS in module.directives) { return null diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt index cd3ada99688..9e774194d12 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/classic/ClassicFrontend2IrConverter.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.frontend.classic import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.codegen.ClassBuilderFactories +import org.jetbrains.kotlin.codegen.CodegenFactory import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.test.backend.ir.IrBackendInput import org.jetbrains.kotlin.test.directives.CodegenTestDirectives @@ -41,9 +42,9 @@ class ClassicFrontend2IrConverter( files, configuration ).codegenFactory(codegenFactory) .isIrBackend(true) + .ignoreErrors(CodegenTestDirectives.IGNORE_ERRORS in module.directives) .build() - val ignoreErrors = CodegenTestDirectives.IGNORE_ERRORS in module.directives - return IrBackendInput(codegenFactory.convertToIr(state, files, ignoreErrors)) + return IrBackendInput(state, codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationState(state))) } } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrResultsConverter.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrResultsConverter.kt index 5cf9a3e80f9..4a5c50dc91d 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrResultsConverter.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/Fir2IrResultsConverter.kt @@ -75,8 +75,8 @@ class Fir2IrResultsConverter( val irProviders = codegenFactory.configureBuiltInsAndGenerateIrProvidersInFrontendIRMode(irModuleFragment, symbolTable, extensions) return IrBackendInput( + generationState, JvmIrCodegenFactory.JvmIrBackendInput( - generationState, irModuleFragment, symbolTable, phaseConfig, diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt index d3b499358ba..133ed12222d 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/KJvmReplCompilerBase.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollectorBasedReporter import org.jetbrains.kotlin.cli.common.repl.LineId import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.codegen.ClassBuilderFactories +import org.jetbrains.kotlin.codegen.CodegenFactory import org.jetbrains.kotlin.codegen.KotlinCodegenFacade import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.JVMConfigurationKeys @@ -200,7 +201,10 @@ open class KJvmReplCompilerBase( .codegenFactory(codegenFactory) .build() - generationState.codegenFactory.generateModule(generationState, generationState.files) + codegenFactory.generateModule( + generationState, + codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationState(generationState)), + ) return generationState }