[K/N] A proper FrontendPhase

Rewrite frontend compiler phase using the new machinery.
As a side effect, some lateinit context properties are not lazy anymore.
This commit is contained in:
Sergey Bogolepov
2022-10-14 17:00:20 +03:00
committed by Space Team
parent 4bae6d794c
commit 182662f7ed
6 changed files with 147 additions and 50 deletions
@@ -62,13 +62,13 @@ internal class NativeMapping : DefaultMapping() {
val loweredInlineClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrSimpleFunction>()
}
internal class Context(config: KonanConfig) : KonanBackendContext(config), ConfigChecks {
lateinit var frontendServices: FrontendServices
lateinit var environment: KotlinCoreEnvironment
lateinit var bindingContext: BindingContext
lateinit var moduleDescriptor: ModuleDescriptor
internal class Context(
config: KonanConfig,
val environment: KotlinCoreEnvironment,
val frontendServices: FrontendServices,
var bindingContext: BindingContext,
val moduleDescriptor: ModuleDescriptor,
) : KonanBackendContext(config), ConfigChecks {
/**
* Valid from [createSymbolTablePhase] until [destroySymbolTablePhase].
*/
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.backend.konan.driver.phases.FrontendContext
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportLazy
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportLazyImpl
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportProblemCollector
@@ -45,7 +46,7 @@ internal fun StorageComponentContainer.initContainer(config: KonanConfig) {
}
}
internal fun ComponentProvider.postprocessComponents(context: Context, files: Collection<KtFile>) {
internal fun ComponentProvider.postprocessComponents(context: FrontendContext, files: Collection<KtFile>) {
context.frontendServices = this.get<FrontendServices>()
context.config.configuration.get(KonanConfigKeys.EMIT_LAZY_OBJC_HEADER_FILE)?.let {
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.backend.konan.driver.phases.FrontendContext
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.config.CommonConfigurationKeys
@@ -30,7 +31,7 @@ internal object TopDownAnalyzerFacadeForKonan {
private val nativeFactories = KlibMetadataFactories(::KonanBuiltIns, NullFlexibleTypeDeserializer, NativeTypeTransformer())
fun analyzeFiles(files: Collection<KtFile>, context: Context): AnalysisResult {
fun analyzeFiles(files: Collection<KtFile>, context: FrontendContext): AnalysisResult {
val config = context.config
val moduleName = Name.special("<${config.moduleId}>")
@@ -69,7 +70,7 @@ internal object TopDownAnalyzerFacadeForKonan {
files: Collection<KtFile>,
trace: BindingTrace,
moduleContext: ModuleContext,
context: Context,
context: FrontendContext,
projectContext: ProjectContext,
additionalPackages: List<PackageFragmentProvider> = emptyList()
): AnalysisResult {
@@ -6,13 +6,12 @@
package org.jetbrains.kotlin.backend.konan.driver
import kotlinx.cinterop.usingJvmCInteropCallbacks
import org.jetbrains.kotlin.analyzer.AnalysisResult
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.backend.konan.driver.phases.FrontendContextImpl
import org.jetbrains.kotlin.backend.konan.driver.phases.FrontendPhase
import org.jetbrains.kotlin.backend.konan.driver.phases.FrontendPhaseOutput
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
/**
@@ -33,13 +32,22 @@ internal class StaticCompilerDriver : CompilerDriver() {
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
val frontendContext = FrontendContextImpl(konanConfig)
val frontendOutput = FrontendPhase.phaseBody(frontendContext, environment)
if (frontendOutput is FrontendPhaseOutput.ShouldNotGenerateCode) {
return
}
require(frontendOutput is FrontendPhaseOutput.Full)
val context = Context(
konanConfig,
environment,
frontendOutput.frontendServices,
frontendOutput.bindingContext,
frontendOutput.moduleDescriptor,
)
context.phaseConfig.konanPhasesConfig(konanConfig) // TODO: Wrong place to call it
usingNativeMemoryAllocator {
usingJvmCInteropCallbacks {
@@ -51,35 +59,4 @@ internal class StaticCompilerDriver : CompilerDriver() {
}
}
}
// 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
}
}
@@ -0,0 +1,82 @@
/*
* 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.phases
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.backend.konan.FrontendServices
import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.KonanConfig
import org.jetbrains.kotlin.backend.konan.TopDownAnalyzerFacadeForKonan
import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine
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.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
sealed class FrontendPhaseOutput {
object ShouldNotGenerateCode : FrontendPhaseOutput()
data class Full(
val moduleDescriptor: ModuleDescriptor,
val bindingContext: BindingContext,
val frontendServices: FrontendServices,
val environment: KotlinCoreEnvironment,
) : FrontendPhaseOutput()
}
internal interface FrontendContext : PhaseContext {
var frontendServices: FrontendServices
}
internal class FrontendContextImpl(
config: KonanConfig
) : BasicPhaseContext(config), FrontendContext {
override lateinit var frontendServices: FrontendServices
}
internal val FrontendPhase = createSimpleNamedCompilerPhase(
"Frontend", "Compiler frontend",
outputIfNotEnabled = { _, _, _, _ -> FrontendPhaseOutput.ShouldNotGenerateCode }
) { context: FrontendContext, input: KotlinCoreEnvironment ->
lateinit var analysisResult: AnalysisResult
do {
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(
context.messageCollector,
input.configuration.languageVersionSettings,
input.configuration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
)
// Build AST and binding info.
analyzerWithCompilerReport.analyzeAndReport(input.getSourceFiles()) {
TopDownAnalyzerFacadeForKonan.analyzeFiles(input.getSourceFiles(), context)
}
if (analyzerWithCompilerReport.hasErrors()) {
throw KonanCompilationException()
}
analysisResult = analyzerWithCompilerReport.analysisResult
if (analysisResult is AnalysisResult.RetryWithAdditionalRoots) {
input.addKotlinSourceRoots(analysisResult.additionalKotlinRoots)
}
} while (analysisResult is AnalysisResult.RetryWithAdditionalRoots)
val moduleDescriptor = analysisResult.moduleDescriptor
val bindingContext = analysisResult.bindingContext
if (analysisResult.shouldGenerateCode) {
FrontendPhaseOutput.Full(moduleDescriptor, bindingContext, context.frontendServices, input)
} else {
FrontendPhaseOutput.ShouldNotGenerateCode
}
}
internal fun <T : FrontendContext> PhaseEngine<T>.runFrontend(environment: KotlinCoreEnvironment): FrontendPhaseOutput {
return this.runPhase(FrontendPhase, environment)
}
@@ -0,0 +1,36 @@
/*
* 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.phases
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfigurationService
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
import org.jetbrains.kotlin.backend.common.phaser.SimpleNamedCompilerPhase
internal fun <Context : LoggingContext, Input, Output> createSimpleNamedCompilerPhase(
name: String,
description: String,
outputIfNotEnabled: (PhaseConfigurationService, PhaserState<Input>, Context, Input) -> Output,
phaseBody: (Context, Input) -> Output
): SimpleNamedCompilerPhase<Context, Input, Output> = object : SimpleNamedCompilerPhase<Context, Input, Output>(name, description) {
override fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input): Output =
outputIfNotEnabled(phaseConfig, phaserState, context, input)
override fun phaseBody(context: Context, input: Input): Output =
phaseBody(context, input)
}
internal fun <Context : LoggingContext, Input> createSimpleNamedCompilerPhase(
name: String,
description: String,
phaseBody: (Context, Input) -> Unit
): SimpleNamedCompilerPhase<Context, Input, Unit> = object : SimpleNamedCompilerPhase<Context, Input, Unit>(name, description) {
override fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Input>, context: Context, input: Input) {}
override fun phaseBody(context: Context, input: Input): Unit =
phaseBody(context, input)
}