JVM IR: support cyclic module dependencies
The only way to make the compiler compile several modules with a dependency loop is via the "build file", given by -Xbuild-file and used in the JPS (IntelliJ built-in build system) plugin. For the old frontend/backend it works like this: we _analyze_ sources of all modules once, as if it's one big module, and then for each module, we _generate_ (invoke backend) only sources of that module. Backend needs to be invoked separately per-module because every module has its own destination directory specified in the build file. For JVM IR, this separation into just two steps, analyze and generate, was problematic because there's psi2ir, which works like frontend, in that it needs the global analysis result to be able to create and link IR correctly. So, in case of JVM IR, we need to run psi2ir on the whole module after analysis and before generation. In this change, psi2ir is run on the whole module via `CodegenFactory.convertToIr` (which does nothing in the old backend), and then parts of the resulting IR module are extracted according to the original separation of the combined module into individual modules via `getModuleChunkBackendInput` by matching IrFile against KtFile. And then, backend is run for each such module. #KT-45915 Fixed #KT-48668 Fixed
This commit is contained in:
+42
-13
@@ -33,8 +33,8 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.common.toLogger
|
||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.CodegenFactory
|
||||
import org.jetbrains.kotlin.codegen.DefaultCodegenFactory
|
||||
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
@@ -113,6 +113,8 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
val localFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL)
|
||||
|
||||
val (codegenFactory, wholeBackendInput) = convertToIr(environment, result)
|
||||
|
||||
for (module in chunk) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
@@ -120,7 +122,8 @@ object KotlinToJVMBytecodeCompiler {
|
||||
if (!checkKotlinPackageUsage(environment.configuration, ktFiles)) return false
|
||||
val moduleConfiguration = projectConfiguration.applyModuleProperties(module, buildFile)
|
||||
|
||||
outputs[module] = generate(environment, moduleConfiguration, result, ktFiles, module)
|
||||
val backendInput = codegenFactory.getModuleChunkBackendInput(wholeBackendInput, ktFiles)
|
||||
outputs[module] = generate(environment, moduleConfiguration, result, ktFiles, module, codegenFactory, backendInput)
|
||||
}
|
||||
|
||||
return writeOutputs(environment.project, projectConfiguration, chunk, outputs, mainClassFqName)
|
||||
@@ -234,7 +237,28 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
result.throwIfError()
|
||||
|
||||
return generate(environment, environment.configuration, result, environment.getSourceFiles(), null)
|
||||
val (codegenFactory, backendInput) = convertToIr(environment, result)
|
||||
return generate(environment, environment.configuration, result, environment.getSourceFiles(), null, codegenFactory, backendInput)
|
||||
}
|
||||
|
||||
private fun convertToIr(environment: KotlinCoreEnvironment, result: AnalysisResult): Pair<CodegenFactory, CodegenFactory.BackendInput> {
|
||||
val configuration = environment.configuration
|
||||
val codegenFactory =
|
||||
if (configuration.getBoolean(JVMConfigurationKeys.IR)) JvmIrCodegenFactory(
|
||||
configuration, configuration.get(CLIConfigurationKeys.PHASE_CONFIG)
|
||||
) else DefaultCodegenFactory
|
||||
|
||||
val input = CodegenFactory.IrConversionInput(
|
||||
environment.project,
|
||||
environment.getSourceFiles(),
|
||||
configuration,
|
||||
result.moduleDescriptor,
|
||||
result.bindingContext,
|
||||
configuration.languageVersionSettings,
|
||||
false,
|
||||
)
|
||||
val backendInput = codegenFactory.convertToIr(input)
|
||||
return Pair(codegenFactory, backendInput)
|
||||
}
|
||||
|
||||
fun analyze(environment: KotlinCoreEnvironment): AnalysisResult? {
|
||||
@@ -304,9 +328,11 @@ object KotlinToJVMBytecodeCompiler {
|
||||
configuration: CompilerConfiguration,
|
||||
result: AnalysisResult,
|
||||
sourceFiles: List<KtFile>,
|
||||
module: Module?
|
||||
module: Module?,
|
||||
codegenFactory: CodegenFactory,
|
||||
backendInput: CodegenFactory.BackendInput,
|
||||
): GenerationState {
|
||||
val generationState = GenerationState.Builder(
|
||||
val state = GenerationState.Builder(
|
||||
environment.project,
|
||||
ClassBuilderFactories.BINARIES,
|
||||
result.moduleDescriptor,
|
||||
@@ -314,11 +340,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
sourceFiles,
|
||||
configuration
|
||||
)
|
||||
.codegenFactory(
|
||||
if (configuration.getBoolean(JVMConfigurationKeys.IR)) JvmIrCodegenFactory(
|
||||
configuration, configuration.get(CLIConfigurationKeys.PHASE_CONFIG)
|
||||
) else DefaultCodegenFactory
|
||||
)
|
||||
.codegenFactory(codegenFactory)
|
||||
.withModule(module)
|
||||
.onIndependentPartCompilationEnd(createOutputFilesFlushingCallbackIfPossible(configuration))
|
||||
.build()
|
||||
@@ -328,7 +350,14 @@ object KotlinToJVMBytecodeCompiler {
|
||||
val performanceManager = environment.configuration.get(CLIConfigurationKeys.PERF_MANAGER)
|
||||
performanceManager?.notifyGenerationStarted()
|
||||
|
||||
KotlinCodegenFacade.compileCorrectFiles(generationState)
|
||||
state.beforeCompile()
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
codegenFactory.generateModule(state, backendInput)
|
||||
|
||||
CodegenFactory.doCheckCancelled(state)
|
||||
state.factory.done()
|
||||
|
||||
performanceManager?.notifyGenerationFinished()
|
||||
|
||||
@@ -336,13 +365,13 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
AnalyzerWithCompilerReport.reportDiagnostics(
|
||||
FilteredJvmDiagnostics(
|
||||
generationState.collectedExtraJvmDiagnostics,
|
||||
state.collectedExtraJvmDiagnostics,
|
||||
result.bindingContext.diagnostics
|
||||
),
|
||||
environment.messageCollector
|
||||
)
|
||||
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
return generationState
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user