[K/N] Introduce multiple compiler drivers
We want to move from current compilation pipeline that is defined in TopLevelPhases.kt to a "dynamic" one. The main drawback of the current one is that it is built around single Context, single IR module, single compiler output, etc. It is now as flexible as Kotlin/Native compiler requires. For example, it is pretty hard to support multiple Apple frameworks or a proper separate compilation. To mitigate this problem, we are going to move to a new "dynamic" compiler pipeline that relies on an explicit data passing between different compiler phases. For example, it allows to use single phase output as an input for multiple independent subsequent phases. Or vice versa, e.g. use outputs of multiple "produce object file" phases by a single linker phase. This commit introduces `CompilerDriver` hierarchy which is required during transition period.
This commit is contained in:
committed by
Space Team
parent
89d3060e00
commit
6ef4277d89
+13
-72
@@ -6,24 +6,17 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlinx.cinterop.usingJvmCInteropCallbacks
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.backend.common.serialization.codedInputStream
|
||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.backend.konan.driver.CompilerDriver
|
||||
import org.jetbrains.kotlin.backend.konan.driver.DynamicCompilerDriver
|
||||
import org.jetbrains.kotlin.backend.konan.driver.StaticCompilerDriver
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.impl.createKonanLibrary
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment, val configuration: CompilerConfiguration) {
|
||||
fun run() {
|
||||
@@ -43,12 +36,9 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
||||
configuration.put(KonanConfigKeys.FILES_TO_CACHE, fileNames)
|
||||
}
|
||||
|
||||
KonanConfig(project, configuration).runTopLevelPhases()
|
||||
}
|
||||
|
||||
private fun KonanConfig.runTopLevelPhases() {
|
||||
ensureModuleName(this)
|
||||
runTopLevelPhases(this, environment)
|
||||
val konanConfig = KonanConfig(project, configuration)
|
||||
ensureModuleName(konanConfig)
|
||||
pickCompilerDriver().run(konanConfig, environment)
|
||||
}
|
||||
|
||||
private fun ensureModuleName(config: KonanConfig) {
|
||||
@@ -62,62 +52,13 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
||||
|
||||
val config = konanConfig.configuration
|
||||
|
||||
val targets = konanConfig.targetManager
|
||||
if (config.get(KonanConfigKeys.LIST_TARGETS) ?: false) {
|
||||
targets.list()
|
||||
}
|
||||
|
||||
val context = Context(konanConfig)
|
||||
context.environment = environment
|
||||
context.phaseConfig.konanPhasesConfig(konanConfig) // TODO: Wrong place to call it
|
||||
|
||||
if (konanConfig.infoArgsOnly) return
|
||||
|
||||
if (!context.frontendPhase()) return
|
||||
|
||||
usingNativeMemoryAllocator {
|
||||
usingJvmCInteropCallbacks {
|
||||
try {
|
||||
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
||||
} finally {
|
||||
context.disposeGenerationState()
|
||||
}
|
||||
private fun pickCompilerDriver(): CompilerDriver {
|
||||
// Dynamic driver is WIP, so it might not support all possible configurations.
|
||||
return if (DynamicCompilerDriver.supportsConfig()) {
|
||||
DynamicCompilerDriver()
|
||||
} else {
|
||||
StaticCompilerDriver()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if should generate code.
|
||||
internal fun Context.frontendPhase(): Boolean {
|
||||
lateinit var analysisResult: AnalysisResult
|
||||
|
||||
do {
|
||||
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(
|
||||
messageCollector,
|
||||
environment.configuration.languageVersionSettings,
|
||||
environment.configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||
)
|
||||
|
||||
// Build AST and binding info.
|
||||
analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles()) {
|
||||
TopDownAnalyzerFacadeForKonan.analyzeFiles(environment.getSourceFiles(), this)
|
||||
}
|
||||
if (analyzerWithCompilerReport.hasErrors()) {
|
||||
throw KonanCompilationException()
|
||||
}
|
||||
analysisResult = analyzerWithCompilerReport.analysisResult
|
||||
if (analysisResult is AnalysisResult.RetryWithAdditionalRoots) {
|
||||
environment.addKotlinSourceRoots(analysisResult.additionalKotlinRoots)
|
||||
}
|
||||
} while(analysisResult is AnalysisResult.RetryWithAdditionalRoots)
|
||||
|
||||
moduleDescriptor = analysisResult.moduleDescriptor
|
||||
bindingContext = analysisResult.bindingContext
|
||||
|
||||
return analysisResult.shouldGenerateCode
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.backend.konan.driver
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfig
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
|
||||
/**
|
||||
* Compiler driver orchestrates and connects different parts of compiler into a complete pipeline.
|
||||
*/
|
||||
internal sealed class CompilerDriver {
|
||||
/**
|
||||
* Entry point for compilation pipeline.
|
||||
*/
|
||||
abstract fun run(config: KonanConfig, environment: KotlinCoreEnvironment)
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.backend.konan.driver
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfig
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
|
||||
/**
|
||||
* Dynamic driver does not "know" upfront which phases will be executed.
|
||||
*/
|
||||
internal class DynamicCompilerDriver : CompilerDriver() {
|
||||
|
||||
companion object {
|
||||
// Will become non-trivial in the future.
|
||||
fun supportsConfig(): Boolean =
|
||||
false
|
||||
}
|
||||
|
||||
override fun run(config: KonanConfig, environment: KotlinCoreEnvironment) = when (config.produce) {
|
||||
CompilerOutputKind.PROGRAM -> error("Dynamic compiler driver does not support `program` output yet.")
|
||||
CompilerOutputKind.DYNAMIC -> error("Dynamic compiler driver does not support `dynamic` output yet.")
|
||||
CompilerOutputKind.STATIC -> error("Dynamic compiler driver does not support `static` output yet.")
|
||||
CompilerOutputKind.FRAMEWORK -> error("Dynamic compiler driver does not support `framework` output yet.")
|
||||
CompilerOutputKind.LIBRARY -> error("Dynamic compiler driver does not support `library` output yet.")
|
||||
CompilerOutputKind.BITCODE -> error("Dynamic compiler driver does not support `bitcode` output yet.")
|
||||
CompilerOutputKind.DYNAMIC_CACHE -> error("Dynamic compiler driver does not support `dynamic_cache` output yet.")
|
||||
CompilerOutputKind.STATIC_CACHE -> error("Dynamic compiler driver does not support `static_cache` output yet.")
|
||||
CompilerOutputKind.PRELIMINARY_CACHE -> TODO()
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.backend.konan.driver
|
||||
|
||||
import kotlinx.cinterop.usingJvmCInteropCallbacks
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
/**
|
||||
* Static compiler uses statically-defined compilation pipeline and a single Context during whole compilation.
|
||||
* Superseded by [DynamicCompilerDriver] and will be removed once dynamic driver become complete.
|
||||
*/
|
||||
internal class StaticCompilerDriver : CompilerDriver() {
|
||||
override fun run(config: KonanConfig, environment: KotlinCoreEnvironment) {
|
||||
runTopLevelPhases(config, environment)
|
||||
}
|
||||
|
||||
private fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
||||
|
||||
val config = konanConfig.configuration
|
||||
|
||||
val targets = konanConfig.targetManager
|
||||
if (config.get(KonanConfigKeys.LIST_TARGETS) ?: false) {
|
||||
targets.list()
|
||||
}
|
||||
|
||||
val context = Context(konanConfig)
|
||||
context.environment = environment
|
||||
context.phaseConfig.konanPhasesConfig(konanConfig) // TODO: Wrong place to call it
|
||||
|
||||
if (konanConfig.infoArgsOnly) return
|
||||
|
||||
if (!context.frontendPhase()) return
|
||||
|
||||
usingNativeMemoryAllocator {
|
||||
usingJvmCInteropCallbacks {
|
||||
try {
|
||||
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
||||
} finally {
|
||||
context.disposeGenerationState()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if should generate code.
|
||||
private fun Context.frontendPhase(): Boolean {
|
||||
lateinit var analysisResult: AnalysisResult
|
||||
|
||||
do {
|
||||
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(
|
||||
messageCollector,
|
||||
environment.configuration.languageVersionSettings,
|
||||
environment.configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
|
||||
)
|
||||
|
||||
// Build AST and binding info.
|
||||
analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles()) {
|
||||
TopDownAnalyzerFacadeForKonan.analyzeFiles(environment.getSourceFiles(), this)
|
||||
}
|
||||
if (analyzerWithCompilerReport.hasErrors()) {
|
||||
throw KonanCompilationException()
|
||||
}
|
||||
analysisResult = analyzerWithCompilerReport.analysisResult
|
||||
if (analysisResult is AnalysisResult.RetryWithAdditionalRoots) {
|
||||
environment.addKotlinSourceRoots(analysisResult.additionalKotlinRoots)
|
||||
}
|
||||
} while(analysisResult is AnalysisResult.RetryWithAdditionalRoots)
|
||||
|
||||
moduleDescriptor = analysisResult.moduleDescriptor
|
||||
bindingContext = analysisResult.bindingContext
|
||||
|
||||
return analysisResult.shouldGenerateCode
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user