Add AnalysisHandlerExtension extension point for K2Native
frontendPhase is moved out of back phases to allow frontend only mode. AnalysisHandlerExtension allows compiler plugins to: 1. Intercept and override the default analysis. 2. Utilize the compiler infrastructure to do custom analysis. A well know plugin on the JVM platform is KAPT.
This commit is contained in:
committed by
TeamCityServer
parent
8e7b561b10
commit
dba127a4d8
@@ -180,6 +180,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
put(PRINT_DESCRIPTORS, arguments.printDescriptors)
|
||||
put(PRINT_LOCATIONS, arguments.printLocations)
|
||||
put(PRINT_BITCODE, arguments.printBitCode)
|
||||
put(PRINT_FILES, arguments.printFiles)
|
||||
|
||||
put(PURGE_USER_LIBS, arguments.purgeUserLibs)
|
||||
|
||||
|
||||
+3
@@ -199,6 +199,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-Xprint-locations", deprecatedName = "--print_locations", description = "Print locations")
|
||||
var printLocations: Boolean = false
|
||||
|
||||
@Argument(value = "-Xprint-files", description = "Print files")
|
||||
var printFiles: Boolean = false
|
||||
|
||||
@Argument(value="-Xpurge-user-libs", deprecatedName = "--purge_user_libs", description = "Don't link unused libraries even explicitly specified")
|
||||
var purgeUserLibs: Boolean = false
|
||||
|
||||
|
||||
+2
@@ -410,6 +410,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
|
||||
fun shouldPrintLocations() = config.configuration.getBoolean(KonanConfigKeys.PRINT_LOCATIONS)
|
||||
|
||||
fun shouldPrintFiles() = config.configuration.getBoolean(KonanConfigKeys.PRINT_FILES)
|
||||
|
||||
fun shouldProfilePhases() = config.phaseConfig.needProfiling
|
||||
|
||||
fun shouldContainDebugInfo() = config.debug
|
||||
|
||||
+2
@@ -106,6 +106,8 @@ class KonanConfigKeys {
|
||||
= CompilerConfigurationKey.create("print ir with descriptors")
|
||||
val PRINT_LOCATIONS: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("print locations")
|
||||
val PRINT_FILES: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("print files")
|
||||
val PRODUCE: CompilerConfigurationKey<CompilerOutputKind>
|
||||
= CompilerConfigurationKey.create("compiler output kind")
|
||||
val PURGE_USER_LIBS: CompilerConfigurationKey<Boolean>
|
||||
|
||||
+31
@@ -5,9 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
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.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
||||
@@ -25,6 +28,8 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
|
||||
|
||||
if (konanConfig.infoArgsOnly) return
|
||||
|
||||
if (!context.frontendPhase()) return
|
||||
|
||||
try {
|
||||
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
||||
} finally {
|
||||
@@ -36,3 +41,29 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if should generate code.
|
||||
internal fun Context.frontendPhase(): Boolean {
|
||||
lateinit var analysisResult: AnalysisResult
|
||||
|
||||
do {
|
||||
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector,
|
||||
environment.configuration.languageVersionSettings)
|
||||
|
||||
// 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
|
||||
}
|
||||
+27
-6
@@ -28,9 +28,11 @@ import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.extensions.AnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
import org.jetbrains.kotlin.serialization.konan.KotlinResolvedModuleDescriptors
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
internal object TopDownAnalyzerFacadeForKonan {
|
||||
|
||||
@@ -64,7 +66,7 @@ internal object TopDownAnalyzerFacadeForKonan {
|
||||
additionalPackages += functionInterfacePackageFragmentProvider(projectContext.storageManager, module)
|
||||
}
|
||||
|
||||
return analyzeFilesWithGivenTrace(files, BindingTraceContext(), moduleContext, context, additionalPackages)
|
||||
return analyzeFilesWithGivenTrace(files, BindingTraceContext(), moduleContext, context, projectContext, additionalPackages)
|
||||
}
|
||||
|
||||
fun analyzeFilesWithGivenTrace(
|
||||
@@ -72,15 +74,16 @@ internal object TopDownAnalyzerFacadeForKonan {
|
||||
trace: BindingTrace,
|
||||
moduleContext: ModuleContext,
|
||||
context: Context,
|
||||
projectContext: ProjectContext,
|
||||
additionalPackages: List<PackageFragmentProvider> = emptyList()
|
||||
): AnalysisResult {
|
||||
|
||||
// we print out each file we compile if frontend phase is verbose
|
||||
files.takeIf {
|
||||
frontendPhase in context.phaseConfig.verbose
|
||||
context.shouldPrintFiles()
|
||||
} ?.forEach(::println)
|
||||
|
||||
val analyzerForKonan = createTopDownAnalyzerProviderForKonan(
|
||||
val container = createTopDownAnalyzerProviderForKonan(
|
||||
moduleContext, trace,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
context.config.configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!,
|
||||
@@ -89,10 +92,28 @@ internal object TopDownAnalyzerFacadeForKonan {
|
||||
initContainer(context.config)
|
||||
}.apply {
|
||||
postprocessComponents(context, files)
|
||||
}.get<LazyTopDownAnalyzer>()
|
||||
}
|
||||
|
||||
analyzerForKonan.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
|
||||
return AnalysisResult.success(trace.bindingContext, moduleContext.module)
|
||||
val analyzerForKonan = container.get<LazyTopDownAnalyzer>()
|
||||
val project = context.config.project
|
||||
val moduleDescriptor = moduleContext.module
|
||||
val analysisHandlerExtensions = AnalysisHandlerExtension.getInstances(project)
|
||||
|
||||
// Mimic the behavior in the jvm frontend. The extensions have 2 chances to override the normal analysis:
|
||||
// * If any of the extensions returns a non-null result, use it. Otherwise do the normal analysis.
|
||||
// * `analysisCompleted` can be used to override the result, too.
|
||||
var result = analysisHandlerExtensions.firstNotNullResult { extension ->
|
||||
extension.doAnalysis(project, moduleDescriptor, projectContext, files, trace, container)
|
||||
} ?: run {
|
||||
analyzerForKonan.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
|
||||
AnalysisResult.success(trace.bindingContext, moduleDescriptor)
|
||||
}
|
||||
|
||||
result = analysisHandlerExtensions.firstNotNullResult { extension ->
|
||||
extension.analysisCompleted(project, moduleDescriptor, trace, files)
|
||||
} ?: result
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fun checkForErrors(files: Collection<KtFile>, bindingContext: BindingContext) {
|
||||
|
||||
+1
-22
@@ -75,26 +75,6 @@ internal fun konanUnitPhase(
|
||||
op: Context.() -> Unit
|
||||
) = namedOpUnitPhase(name, description, prerequisite, op)
|
||||
|
||||
internal val frontendPhase = konanUnitPhase(
|
||||
op = {
|
||||
val environment = environment
|
||||
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(messageCollector,
|
||||
environment.configuration.languageVersionSettings)
|
||||
|
||||
// Build AST and binding info.
|
||||
analyzerWithCompilerReport.analyzeAndReport(environment.getSourceFiles()) {
|
||||
TopDownAnalyzerFacadeForKonan.analyzeFiles(environment.getSourceFiles(), this)
|
||||
}
|
||||
if (analyzerWithCompilerReport.hasErrors()) {
|
||||
throw KonanCompilationException()
|
||||
}
|
||||
moduleDescriptor = analyzerWithCompilerReport.analysisResult.moduleDescriptor
|
||||
bindingContext = analyzerWithCompilerReport.analysisResult.bindingContext
|
||||
},
|
||||
name = "Frontend",
|
||||
description = "Frontend builds AST"
|
||||
)
|
||||
|
||||
/**
|
||||
* Valid from [createSymbolTablePhase] until [destroySymbolTablePhase].
|
||||
*/
|
||||
@@ -425,8 +405,7 @@ private val backendCodegen = namedUnitPhase(
|
||||
val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
|
||||
name = "Compiler",
|
||||
description = "The whole compilation process",
|
||||
lower = frontendPhase then
|
||||
createSymbolTablePhase then
|
||||
lower = createSymbolTablePhase then
|
||||
objCExportPhase then
|
||||
buildCExportsPhase then
|
||||
psiToIrPhase then
|
||||
|
||||
Reference in New Issue
Block a user