[K/N][build] Added -Xmake-per-file-cache compiler option
This commit is contained in:
+3
@@ -221,6 +221,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
var fileToCache: String? = null
|
var fileToCache: String? = null
|
||||||
|
|
||||||
|
@Argument(value = "-Xmake-per-file-cache", description = "Force compiler to produce per-file cache")
|
||||||
|
var makePerFileCache: Boolean = false
|
||||||
|
|
||||||
@Argument(value = "-Xexport-kdoc", description = "Export KDoc in framework header")
|
@Argument(value = "-Xexport-kdoc", description = "Export KDoc in framework header")
|
||||||
var exportKDoc: Boolean = false
|
var exportKDoc: Boolean = false
|
||||||
|
|
||||||
|
|||||||
+41
-3
@@ -12,10 +12,33 @@ fun CompilerPhase<*, *, *>.toPhaseMap(): MutableMap<String, AnyNamedPhase> =
|
|||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PhaseConfigBuilder(private val compoundPhase: CompilerPhase<*, *, *>) {
|
||||||
|
val enabled = mutableSetOf<AnyNamedPhase>()
|
||||||
|
val verbose = mutableSetOf<AnyNamedPhase>()
|
||||||
|
val toDumpStateBefore = mutableSetOf<AnyNamedPhase>()
|
||||||
|
val toDumpStateAfter = mutableSetOf<AnyNamedPhase>()
|
||||||
|
var dumpToDirectory: String? = null
|
||||||
|
var dumpOnlyFqName: String? = null
|
||||||
|
val toValidateStateBefore = mutableSetOf<AnyNamedPhase>()
|
||||||
|
val toValidateStateAfter = mutableSetOf<AnyNamedPhase>()
|
||||||
|
val namesOfElementsExcludedFromDumping = mutableSetOf<String>()
|
||||||
|
var needProfiling = false
|
||||||
|
var checkConditions = false
|
||||||
|
var checkStickyConditions = false
|
||||||
|
|
||||||
|
fun build() = PhaseConfig(
|
||||||
|
compoundPhase, compoundPhase.toPhaseMap(), enabled,
|
||||||
|
verbose, toDumpStateBefore, toDumpStateAfter, dumpToDirectory, dumpOnlyFqName,
|
||||||
|
toValidateStateBefore, toValidateStateAfter,
|
||||||
|
namesOfElementsExcludedFromDumping,
|
||||||
|
needProfiling, checkConditions, checkStickyConditions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class PhaseConfig(
|
class PhaseConfig(
|
||||||
private val compoundPhase: CompilerPhase<*, *, *>,
|
private val compoundPhase: CompilerPhase<*, *, *>,
|
||||||
private val phases: MutableMap<String, AnyNamedPhase> = compoundPhase.toPhaseMap(),
|
private val phases: Map<String, AnyNamedPhase> = compoundPhase.toPhaseMap(),
|
||||||
enabled: MutableSet<AnyNamedPhase> = phases.values.toMutableSet(),
|
private val initiallyEnabled: Set<AnyNamedPhase> = phases.values.toSet(),
|
||||||
val verbose: Set<AnyNamedPhase> = emptySet(),
|
val verbose: Set<AnyNamedPhase> = emptySet(),
|
||||||
val toDumpStateBefore: Set<AnyNamedPhase> = emptySet(),
|
val toDumpStateBefore: Set<AnyNamedPhase> = emptySet(),
|
||||||
val toDumpStateAfter: Set<AnyNamedPhase> = emptySet(),
|
val toDumpStateAfter: Set<AnyNamedPhase> = emptySet(),
|
||||||
@@ -28,7 +51,22 @@ class PhaseConfig(
|
|||||||
val checkConditions: Boolean = false,
|
val checkConditions: Boolean = false,
|
||||||
val checkStickyConditions: Boolean = false
|
val checkStickyConditions: Boolean = false
|
||||||
) {
|
) {
|
||||||
private val enabledMut = enabled
|
fun toBuilder() = PhaseConfigBuilder(compoundPhase).also {
|
||||||
|
it.enabled.addAll(initiallyEnabled)
|
||||||
|
it.verbose.addAll(verbose)
|
||||||
|
it.toDumpStateBefore.addAll(toDumpStateBefore)
|
||||||
|
it.toDumpStateAfter.addAll(toDumpStateAfter)
|
||||||
|
it.dumpToDirectory = dumpToDirectory
|
||||||
|
it.dumpOnlyFqName = dumpOnlyFqName
|
||||||
|
it.toValidateStateBefore.addAll(toValidateStateBefore)
|
||||||
|
it.toValidateStateAfter.addAll(toValidateStateAfter)
|
||||||
|
it.namesOfElementsExcludedFromDumping.addAll(namesOfElementsExcludedFromDumping)
|
||||||
|
it.needProfiling = needProfiling
|
||||||
|
it.checkConditions = checkConditions
|
||||||
|
it.checkStickyConditions = checkStickyConditions
|
||||||
|
}
|
||||||
|
|
||||||
|
private val enabledMut = initiallyEnabled.toMutableSet()
|
||||||
|
|
||||||
val enabled: Set<AnyNamedPhase> get() = enabledMut
|
val enabled: Set<AnyNamedPhase> get() = enabledMut
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.konan.CURRENT
|
|||||||
import org.jetbrains.kotlin.konan.CompilerVersion
|
import org.jetbrains.kotlin.konan.CompilerVersion
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.library.uniqueName
|
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.util.profile
|
import org.jetbrains.kotlin.util.profile
|
||||||
@@ -90,13 +89,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
configuration.put(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME, arguments.renderInternalDiagnosticNames)
|
configuration.put(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME, arguments.renderInternalDiagnosticNames)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val konanConfig = KonanConfig(project, configuration)
|
KonanDriver(project, environment, configuration).run()
|
||||||
try {
|
|
||||||
ensureModuleName(konanConfig, environment)
|
|
||||||
runTopLevelPhases(konanConfig, environment)
|
|
||||||
} finally {
|
|
||||||
konanConfig.dispose()
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e is KonanCompilationException || e is CompilationErrorException)
|
if (e is KonanCompilationException || e is CompilationErrorException)
|
||||||
return ExitCode.COMPILATION_ERROR
|
return ExitCode.COMPILATION_ERROR
|
||||||
@@ -123,18 +116,6 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
return this?.asList<String>() ?: listOf<String>()
|
return this?.asList<String>() ?: listOf<String>()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureModuleName(config: KonanConfig, environment: KotlinCoreEnvironment) {
|
|
||||||
if (environment.getSourceFiles().isEmpty()) {
|
|
||||||
val libraries = config.resolvedLibraries.getFullList()
|
|
||||||
val moduleName = config.moduleId
|
|
||||||
if (libraries.any { it.uniqueName == moduleName }) {
|
|
||||||
val kexeModuleName = "${moduleName}_kexe"
|
|
||||||
config.configuration.put(KonanConfigKeys.MODULE_NAME, kexeModuleName)
|
|
||||||
assert(libraries.none { it.uniqueName == kexeModuleName })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// It is executed before doExecute().
|
// It is executed before doExecute().
|
||||||
override fun setupPlatformSpecificArgumentsAndServices(
|
override fun setupPlatformSpecificArgumentsAndServices(
|
||||||
configuration: CompilerConfiguration,
|
configuration: CompilerConfiguration,
|
||||||
@@ -308,6 +289,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
if (outputKind == CompilerOutputKind.PRELIMINARY_CACHE && fileToCache == null)
|
if (outputKind == CompilerOutputKind.PRELIMINARY_CACHE && fileToCache == null)
|
||||||
configuration.report(ERROR, "preliminary_cache only supported for per-file caches")
|
configuration.report(ERROR, "preliminary_cache only supported for per-file caches")
|
||||||
fileToCache?.let { put(FILE_TO_CACHE, it) }
|
fileToCache?.let { put(FILE_TO_CACHE, it) }
|
||||||
|
put(MAKE_PER_FILE_CACHE, arguments.makePerFileCache)
|
||||||
|
|
||||||
parseShortModuleName(arguments, configuration, outputKind)?.let {
|
parseShortModuleName(arguments, configuration, outputKind)?.let {
|
||||||
put(SHORT_MODULE_NAME, it)
|
put(SHORT_MODULE_NAME, it)
|
||||||
|
|||||||
+2
@@ -46,6 +46,8 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create<Map<String, String>>("mapping from library paths to cache paths")
|
= CompilerConfigurationKey.create<Map<String, String>>("mapping from library paths to cache paths")
|
||||||
val FILE_TO_CACHE: CompilerConfigurationKey<String?>
|
val FILE_TO_CACHE: CompilerConfigurationKey<String?>
|
||||||
= CompilerConfigurationKey.create<String?>("which file should be compiled to cache")
|
= CompilerConfigurationKey.create<String?>("which file should be compiled to cache")
|
||||||
|
val MAKE_PER_FILE_CACHE: CompilerConfigurationKey<Boolean>
|
||||||
|
= CompilerConfigurationKey.create<Boolean>("make per-file cache")
|
||||||
val FRAMEWORK_IMPORT_HEADERS: CompilerConfigurationKey<List<String>>
|
val FRAMEWORK_IMPORT_HEADERS: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create<List<String>>("headers imported to framework header")
|
= CompilerConfigurationKey.create<List<String>>("headers imported to framework header")
|
||||||
val FRIEND_MODULES: CompilerConfigurationKey<List<String>>
|
val FRIEND_MODULES: CompilerConfigurationKey<List<String>>
|
||||||
|
|||||||
+64
-2
@@ -5,19 +5,81 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import kotlinx.cinterop.usingJvmCInteropCallbacks
|
import kotlinx.cinterop.usingJvmCInteropCallbacks
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
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.backend.common.serialization.codedInputStream
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
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.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
|
import org.jetbrains.kotlin.konan.library.impl.createKonanLibrary
|
||||||
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
|
import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator
|
||||||
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
|
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
|
|
||||||
fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment, val configuration: CompilerConfiguration) {
|
||||||
|
fun run() {
|
||||||
|
val fileNames = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE)?.let { libPath ->
|
||||||
|
if (configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) != true)
|
||||||
|
null
|
||||||
|
else {
|
||||||
|
val lib = createKonanLibrary(File(libPath), "default", null, true)
|
||||||
|
(0 until lib.fileCount()).map { fileIndex ->
|
||||||
|
val proto = IrFile.parseFrom(lib.file(fileIndex).codedInputStream, ExtensionRegistryLite.newInstance())
|
||||||
|
proto.fileEntry.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileNames == null) {
|
||||||
|
KonanConfig(project, configuration).runTopLevelPhases()
|
||||||
|
} else {
|
||||||
|
fileNames.forEach { buildFileCache(it, CompilerOutputKind.PRELIMINARY_CACHE) }
|
||||||
|
fileNames.forEach { buildFileCache(it, configuration.get(KonanConfigKeys.PRODUCE)!!) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildFileCache(fileName: String, cacheKind: CompilerOutputKind) {
|
||||||
|
val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)!!
|
||||||
|
val subConfiguration = configuration.copy()
|
||||||
|
subConfiguration.put(KonanConfigKeys.PRODUCE, cacheKind)
|
||||||
|
subConfiguration.put(KonanConfigKeys.FILE_TO_CACHE, fileName)
|
||||||
|
subConfiguration.put(KonanConfigKeys.MAKE_PER_FILE_CACHE, false)
|
||||||
|
subConfiguration.put(CLIConfigurationKeys.PHASE_CONFIG, phaseConfig.toBuilder().build())
|
||||||
|
KonanConfig(project, subConfiguration).runTopLevelPhases()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KonanConfig.runTopLevelPhases() {
|
||||||
|
try {
|
||||||
|
ensureModuleName(this)
|
||||||
|
runTopLevelPhases(this, environment)
|
||||||
|
} finally {
|
||||||
|
dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ensureModuleName(config: KonanConfig) {
|
||||||
|
if (environment.getSourceFiles().isEmpty()) {
|
||||||
|
val libraries = config.resolvedLibraries.getFullList()
|
||||||
|
val moduleName = config.moduleId
|
||||||
|
if (libraries.any { it.uniqueName == moduleName }) {
|
||||||
|
val kexeModuleName = "${moduleName}_kexe"
|
||||||
|
config.configuration.put(KonanConfigKeys.MODULE_NAME, kexeModuleName)
|
||||||
|
assert(libraries.none { it.uniqueName == kexeModuleName })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironment) {
|
||||||
|
|
||||||
val config = konanConfig.configuration
|
val config = konanConfig.configuration
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user