From 182662f7edec1c8fc04d996fb65bb8e1f7b37fb6 Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Fri, 14 Oct 2022 17:00:20 +0300 Subject: [PATCH] [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. --- .../jetbrains/kotlin/backend/konan/Context.kt | 14 ++-- .../konan/KonanCompilerFrontendServices.kt | 3 +- .../konan/TopDownAnalyzerFacadeForKonan.kt | 5 +- .../konan/driver/StaticCompilerDriver.kt | 57 ++++--------- .../backend/konan/driver/phases/Frontend.kt | 82 +++++++++++++++++++ .../konan/driver/phases/PhaseBuilders.kt | 36 ++++++++ 6 files changed, 147 insertions(+), 50 deletions(-) create mode 100644 kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Frontend.kt create mode 100644 kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PhaseBuilders.kt diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index b449ada46ea..d3d27b82988 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -62,13 +62,13 @@ internal class NativeMapping : DefaultMapping() { val loweredInlineClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping() } -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]. */ diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanCompilerFrontendServices.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanCompilerFrontendServices.kt index 7c1525bc43f..4ffb104e2fe 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanCompilerFrontendServices.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanCompilerFrontendServices.kt @@ -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) { +internal fun ComponentProvider.postprocessComponents(context: FrontendContext, files: Collection) { context.frontendServices = this.get() context.config.configuration.get(KonanConfigKeys.EMIT_LAZY_OBJC_HEADER_FILE)?.let { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt index fe4659309d5..fc49692e58a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/TopDownAnalyzerFacadeForKonan.kt @@ -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, context: Context): AnalysisResult { + fun analyzeFiles(files: Collection, context: FrontendContext): AnalysisResult { val config = context.config val moduleName = Name.special("<${config.moduleId}>") @@ -69,7 +70,7 @@ internal object TopDownAnalyzerFacadeForKonan { files: Collection, trace: BindingTrace, moduleContext: ModuleContext, - context: Context, + context: FrontendContext, projectContext: ProjectContext, additionalPackages: List = emptyList() ): AnalysisResult { diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/StaticCompilerDriver.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/StaticCompilerDriver.kt index 7f4410de0a8..9d8ba97ba03 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/StaticCompilerDriver.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/StaticCompilerDriver.kt @@ -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 - } - } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Frontend.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Frontend.kt new file mode 100644 index 00000000000..86e250f4aea --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/Frontend.kt @@ -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 PhaseEngine.runFrontend(environment: KotlinCoreEnvironment): FrontendPhaseOutput { + return this.runPhase(FrontendPhase, environment) +} \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PhaseBuilders.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PhaseBuilders.kt new file mode 100644 index 00000000000..98b5f8e154a --- /dev/null +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/PhaseBuilders.kt @@ -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 createSimpleNamedCompilerPhase( + name: String, + description: String, + outputIfNotEnabled: (PhaseConfigurationService, PhaserState, Context, Input) -> Output, + phaseBody: (Context, Input) -> Output +): SimpleNamedCompilerPhase = object : SimpleNamedCompilerPhase(name, description) { + override fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState, context: Context, input: Input): Output = + outputIfNotEnabled(phaseConfig, phaserState, context, input) + + override fun phaseBody(context: Context, input: Input): Output = + phaseBody(context, input) +} + +internal fun createSimpleNamedCompilerPhase( + name: String, + description: String, + phaseBody: (Context, Input) -> Unit +): SimpleNamedCompilerPhase = object : SimpleNamedCompilerPhase(name, description) { + override fun outputIfNotEnabled(phaseConfig: PhaseConfigurationService, phaserState: PhaserState, context: Context, input: Input) {} + + override fun phaseBody(context: Context, input: Input): Unit = + phaseBody(context, input) +} +