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_DESCRIPTORS, arguments.printDescriptors)
|
||||||
put(PRINT_LOCATIONS, arguments.printLocations)
|
put(PRINT_LOCATIONS, arguments.printLocations)
|
||||||
put(PRINT_BITCODE, arguments.printBitCode)
|
put(PRINT_BITCODE, arguments.printBitCode)
|
||||||
|
put(PRINT_FILES, arguments.printFiles)
|
||||||
|
|
||||||
put(PURGE_USER_LIBS, arguments.purgeUserLibs)
|
put(PURGE_USER_LIBS, arguments.purgeUserLibs)
|
||||||
|
|
||||||
|
|||||||
+3
@@ -199,6 +199,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
@Argument(value = "-Xprint-locations", deprecatedName = "--print_locations", description = "Print locations")
|
@Argument(value = "-Xprint-locations", deprecatedName = "--print_locations", description = "Print locations")
|
||||||
var printLocations: Boolean = false
|
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")
|
@Argument(value="-Xpurge-user-libs", deprecatedName = "--purge_user_libs", description = "Don't link unused libraries even explicitly specified")
|
||||||
var purgeUserLibs: Boolean = false
|
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 shouldPrintLocations() = config.configuration.getBoolean(KonanConfigKeys.PRINT_LOCATIONS)
|
||||||
|
|
||||||
|
fun shouldPrintFiles() = config.configuration.getBoolean(KonanConfigKeys.PRINT_FILES)
|
||||||
|
|
||||||
fun shouldProfilePhases() = config.phaseConfig.needProfiling
|
fun shouldProfilePhases() = config.phaseConfig.needProfiling
|
||||||
|
|
||||||
fun shouldContainDebugInfo() = config.debug
|
fun shouldContainDebugInfo() = config.debug
|
||||||
|
|||||||
+2
@@ -106,6 +106,8 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("print ir with descriptors")
|
= CompilerConfigurationKey.create("print ir with descriptors")
|
||||||
val PRINT_LOCATIONS: CompilerConfigurationKey<Boolean>
|
val PRINT_LOCATIONS: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("print locations")
|
= CompilerConfigurationKey.create("print locations")
|
||||||
|
val PRINT_FILES: CompilerConfigurationKey<Boolean>
|
||||||
|
= CompilerConfigurationKey.create("print files")
|
||||||
val PRODUCE: CompilerConfigurationKey<CompilerOutputKind>
|
val PRODUCE: CompilerConfigurationKey<CompilerOutputKind>
|
||||||
= CompilerConfigurationKey.create("compiler output kind")
|
= CompilerConfigurationKey.create("compiler output kind")
|
||||||
val PURGE_USER_LIBS: CompilerConfigurationKey<Boolean>
|
val PURGE_USER_LIBS: CompilerConfigurationKey<Boolean>
|
||||||
|
|||||||
+31
@@ -5,9 +5,12 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
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.CompilerPhase
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
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.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
|
|
||||||
fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
||||||
@@ -25,6 +28,8 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
|
|||||||
|
|
||||||
if (konanConfig.infoArgsOnly) return
|
if (konanConfig.infoArgsOnly) return
|
||||||
|
|
||||||
|
if (!context.frontendPhase()) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
||||||
} finally {
|
} 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.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
|
import org.jetbrains.kotlin.resolve.extensions.AnalysisHandlerExtension
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||||
import org.jetbrains.kotlin.serialization.konan.KotlinResolvedModuleDescriptors
|
import org.jetbrains.kotlin.serialization.konan.KotlinResolvedModuleDescriptors
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||||
|
|
||||||
internal object TopDownAnalyzerFacadeForKonan {
|
internal object TopDownAnalyzerFacadeForKonan {
|
||||||
|
|
||||||
@@ -64,7 +66,7 @@ internal object TopDownAnalyzerFacadeForKonan {
|
|||||||
additionalPackages += functionInterfacePackageFragmentProvider(projectContext.storageManager, module)
|
additionalPackages += functionInterfacePackageFragmentProvider(projectContext.storageManager, module)
|
||||||
}
|
}
|
||||||
|
|
||||||
return analyzeFilesWithGivenTrace(files, BindingTraceContext(), moduleContext, context, additionalPackages)
|
return analyzeFilesWithGivenTrace(files, BindingTraceContext(), moduleContext, context, projectContext, additionalPackages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun analyzeFilesWithGivenTrace(
|
fun analyzeFilesWithGivenTrace(
|
||||||
@@ -72,15 +74,16 @@ internal object TopDownAnalyzerFacadeForKonan {
|
|||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
context: Context,
|
context: Context,
|
||||||
|
projectContext: ProjectContext,
|
||||||
additionalPackages: List<PackageFragmentProvider> = emptyList()
|
additionalPackages: List<PackageFragmentProvider> = emptyList()
|
||||||
): AnalysisResult {
|
): AnalysisResult {
|
||||||
|
|
||||||
// we print out each file we compile if frontend phase is verbose
|
// we print out each file we compile if frontend phase is verbose
|
||||||
files.takeIf {
|
files.takeIf {
|
||||||
frontendPhase in context.phaseConfig.verbose
|
context.shouldPrintFiles()
|
||||||
} ?.forEach(::println)
|
} ?.forEach(::println)
|
||||||
|
|
||||||
val analyzerForKonan = createTopDownAnalyzerProviderForKonan(
|
val container = createTopDownAnalyzerProviderForKonan(
|
||||||
moduleContext, trace,
|
moduleContext, trace,
|
||||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||||
context.config.configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!,
|
context.config.configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!,
|
||||||
@@ -89,10 +92,28 @@ internal object TopDownAnalyzerFacadeForKonan {
|
|||||||
initContainer(context.config)
|
initContainer(context.config)
|
||||||
}.apply {
|
}.apply {
|
||||||
postprocessComponents(context, files)
|
postprocessComponents(context, files)
|
||||||
}.get<LazyTopDownAnalyzer>()
|
}
|
||||||
|
|
||||||
analyzerForKonan.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
|
val analyzerForKonan = container.get<LazyTopDownAnalyzer>()
|
||||||
return AnalysisResult.success(trace.bindingContext, moduleContext.module)
|
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) {
|
fun checkForErrors(files: Collection<KtFile>, bindingContext: BindingContext) {
|
||||||
|
|||||||
+1
-22
@@ -75,26 +75,6 @@ internal fun konanUnitPhase(
|
|||||||
op: Context.() -> Unit
|
op: Context.() -> Unit
|
||||||
) = namedOpUnitPhase(name, description, prerequisite, op)
|
) = 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].
|
* Valid from [createSymbolTablePhase] until [destroySymbolTablePhase].
|
||||||
*/
|
*/
|
||||||
@@ -425,8 +405,7 @@ private val backendCodegen = namedUnitPhase(
|
|||||||
val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
|
val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
|
||||||
name = "Compiler",
|
name = "Compiler",
|
||||||
description = "The whole compilation process",
|
description = "The whole compilation process",
|
||||||
lower = frontendPhase then
|
lower = createSymbolTablePhase then
|
||||||
createSymbolTablePhase then
|
|
||||||
objCExportPhase then
|
objCExportPhase then
|
||||||
buildCExportsPhase then
|
buildCExportsPhase then
|
||||||
psiToIrPhase then
|
psiToIrPhase then
|
||||||
|
|||||||
Reference in New Issue
Block a user