From f7d3312ad54c969217fc66c983474215bb83de5b Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Thu, 2 Feb 2023 17:47:29 +0200 Subject: [PATCH] [K/N] Finish refactoring TempFiles usages 1. Introduce CExportFiles class This class aggregates all files that are created specifically for C export. Adding more such classes for other output kinds should help getting rid of OutputFiles class. 2. Remove NativeGenerationState.tempFiles Making NativeGenerationState (and compiler phases in general) unaware of files and their lifetime is necessary for making phases simpler and easier to compose. --- .../backend/konan/NativeGenerationState.kt | 1 - .../konan/driver/phases/TopLevelPhases.kt | 44 +++++++++---------- .../konan/driver/utilities/FileManagement.kt | 16 ++++++- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt index a4275325f9b..b47335503e2 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/NativeGenerationState.kt @@ -47,7 +47,6 @@ internal class NativeGenerationState( val dependenciesTracker: DependenciesTracker, val llvmModuleSpecification: LlvmModuleSpecification, val outputFiles: OutputFiles, - val tempFiles: TempFiles, val llvmModuleName: String, ) : BasicPhaseContext(config), BackendContextHolder, LlvmIrHolder { val outputFile = outputFiles.mainFileName diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt index 6ef07dca2af..2375a0002fb 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/phases/TopLevelPhases.kt @@ -8,9 +8,9 @@ package org.jetbrains.kotlin.backend.konan.driver.phases import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.driver.PhaseContext import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine +import org.jetbrains.kotlin.backend.konan.driver.utilities.CExportFiles import org.jetbrains.kotlin.backend.konan.driver.utilities.createTempFiles import org.jetbrains.kotlin.backend.konan.ir.konanLibrary -import org.jetbrains.kotlin.backend.konan.llvm.getName import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclaration @@ -65,14 +65,23 @@ internal fun PhaseEngine.runBackend(backendContext: Contex val outputFiles = OutputFiles(outputPath, config.target, config.produce) val generationState = NativeGenerationState(context.config, backendContext, fragment.cacheDeserializationStrategy, fragment.dependenciesTracker, fragment.llvmModuleSpecification, outputFiles, - tempFiles, llvmModuleName = "out" // TODO: Currently, all llvm modules are named as "out" which might lead to collisions. ) backendEngine.useContext(generationState) { generationStateEngine -> + val bitcodeFile = tempFiles.create(generationState.llvmModuleName, ".bc").javaFile() + val cExportFiles = if (config.produce.isNativeLibrary) { + CExportFiles( + cppAdapter = tempFiles.create("api", ".cpp").javaFile(), + bitcodeAdapter = tempFiles.create("api", ".bc").javaFile(), + header = outputFiles.cAdapterHeader.javaFile(), + def = if (config.target.family == Family.MINGW) outputFiles.cAdapterDef.javaFile() else null, + ) + } else null // TODO: Make this work if we first compile all the fragments and only after that run the link phases. - val it = generationStateEngine.compileModule(fragment.irModule) + generationStateEngine.compileModule(fragment.irModule, bitcodeFile, cExportFiles) // Split here - compileAndLink(it, it.outputFiles.mainFileName, it.outputFiles, it.temporaryFiles, isCoverageEnabled = false) + val moduleCompilationOutput = ModuleCompilationOutput(bitcodeFile, generationState.dependenciesTracker.collectResult()) + compileAndLink(moduleCompilationOutput, outputFiles.mainFileName, outputFiles, tempFiles, isCoverageEnabled = false) } } finally { tempFiles.dispose() @@ -152,10 +161,6 @@ private fun PhaseEngine.splitIntoFragments( internal data class ModuleCompilationOutput( val bitcodeFile: File, val dependenciesTrackingResult: DependenciesTrackingResult, - // Passing tempFiles and output files through this file looks silly and incorrect. - // TODO: Refactor these classes and remove them from here. - val temporaryFiles: TempFiles, - val outputFiles: OutputFiles, ) /** @@ -165,23 +170,19 @@ internal data class ModuleCompilationOutput( * 4. Optimizes it. * 5. Serializes it to a bitcode file. */ -internal fun PhaseEngine.compileModule(module: IrModuleFragment): ModuleCompilationOutput { +internal fun PhaseEngine.compileModule(module: IrModuleFragment, bitcodeFile: File, cExportFiles: CExportFiles?) { if (context.config.produce.isCache) { runPhase(BuildAdditionalCacheInfoPhase, module) } if (context.config.produce == CompilerOutputKind.PROGRAM) { runPhase(EntryPointPhase, module) } - runBackendCodegen(module) + runBackendCodegen(module, cExportFiles) runBitcodePostProcessing() if (context.config.produce.isCache) { runPhase(SaveAdditionalCacheInfoPhase) } - // TODO: Currently, all llvm modules are named as "out" which might lead to collisions. - val bitcodeFile = context.tempFiles.create(context.llvm.module.getName(), ".bc").javaFile() runPhase(WriteBitcodeFilePhase, WriteBitcodeFileInput(context.llvm.module, bitcodeFile)) - val dependenciesTrackingResult = context.dependenciesTracker.collectResult() - return ModuleCompilationOutput(bitcodeFile, dependenciesTrackingResult, context.tempFiles, context.outputFiles) } internal fun PhaseEngine.compileAndLink( @@ -227,7 +228,7 @@ internal fun PhaseEngine.compileAndLink( } -internal fun PhaseEngine.runBackendCodegen(module: IrModuleFragment) { +internal fun PhaseEngine.runBackendCodegen(module: IrModuleFragment, cExportFiles: CExportFiles?) { runAllLowerings(module) val dependenciesToCompile = findDependenciesToCompile() // TODO: KonanLibraryResolver.TopologicalLibraryOrder actually returns libraries in the reverse topological order. @@ -238,17 +239,16 @@ internal fun PhaseEngine.runBackendCodegen(module: IrModu mergeDependencies(module, dependenciesToCompile) runCodegen(module) val generatedBitcodeFiles = if (context.config.produce.isNativeLibrary) { - val cppAdapterFile = context.tempFiles.create("api", ".cpp").javaFile() - val bitcodeAdapterFile = context.tempFiles.create("api", ".bc").javaFile() + require(cExportFiles != null) val input = CExportGenerateApiInput( context.context.cAdapterExportedElements!!, - headerFile = context.outputFiles.cAdapterHeader.javaFile(), - defFile = if (context.config.target.family == Family.MINGW) context.outputFiles.cAdapterDef.javaFile() else null, - cppAdapterFile = cppAdapterFile + headerFile = cExportFiles.header, + defFile = cExportFiles.def, + cppAdapterFile = cExportFiles.cppAdapter ) runPhase(CExportGenerateApiPhase, input) - runPhase(CExportCompileAdapterPhase, CExportCompileAdapterInput(cppAdapterFile, bitcodeAdapterFile)) - listOf(bitcodeAdapterFile) + runPhase(CExportCompileAdapterPhase, CExportCompileAdapterInput(cExportFiles.cppAdapter, cExportFiles.bitcodeAdapter)) + listOf(cExportFiles.bitcodeAdapter) } else { emptyList() } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/FileManagement.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/FileManagement.kt index 793442cea3a..2a2d18b1f0b 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/FileManagement.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/driver/utilities/FileManagement.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.konan.CacheSupport import org.jetbrains.kotlin.backend.konan.KonanConfig import org.jetbrains.kotlin.backend.konan.KonanConfigKeys import org.jetbrains.kotlin.konan.TempFiles +import java.io.File internal fun createTempFiles(config: KonanConfig, cacheDeserializationStrategy: CacheDeserializationStrategy?): TempFiles { val pathToTempDir = config.configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR)?.let { @@ -19,4 +20,17 @@ internal fun createTempFiles(config: KonanConfig, cacheDeserializationStrategy: else org.jetbrains.kotlin.konan.file.File(it, CacheSupport.cacheFileId(singleFileStrategy.fqName, singleFileStrategy.filePath)).path } return TempFiles(pathToTempDir) -} \ No newline at end of file +} + +/** + * Files that are generated only during compilation of C dynamic/static library. + * + * TODO: At some point this class and it usages can be generalized to all possible compiler outputs, + * so instead of OutputFiles we will create a series of classes for each specific compiler output kit. + */ +internal class CExportFiles( + val cppAdapter: File, + val bitcodeAdapter: File, + val header: File, + val def: File?, +) \ No newline at end of file