[K/N][IR][codegen][caches] Speed-up of per-file caches
This commit is contained in:
+4
-1
@@ -219,11 +219,14 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
description = "Path to file to cache",
|
||||
delimiter = ""
|
||||
)
|
||||
var fileToCache: String? = null
|
||||
var filesToCache: Array<String>? = null
|
||||
|
||||
@Argument(value = "-Xmake-per-file-cache", description = "Force compiler to produce per-file cache")
|
||||
var makePerFileCache: Boolean = false
|
||||
|
||||
@Argument(value = "-Xbatched-per-file-cache-build", valueDescription = "{disable|enable}", description = "Build per-file cache in one batch")
|
||||
var batchedPerFileCacheBuild: String? = null
|
||||
|
||||
@Argument(value = "-Xexport-kdoc", description = "Export KDoc in framework header")
|
||||
var exportKDoc: Boolean = false
|
||||
|
||||
|
||||
@@ -285,11 +285,20 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
libraryToAddToCache?.let { put(LIBRARY_TO_ADD_TO_CACHE, it) }
|
||||
put(CACHE_DIRECTORIES, cacheDirectories)
|
||||
put(CACHED_LIBRARIES, parseCachedLibraries(arguments, configuration))
|
||||
val fileToCache = arguments.fileToCache
|
||||
if (outputKind == CompilerOutputKind.PRELIMINARY_CACHE && fileToCache == null)
|
||||
val filesToCache = arguments.filesToCache
|
||||
if (outputKind == CompilerOutputKind.PRELIMINARY_CACHE && filesToCache.isNullOrEmpty())
|
||||
configuration.report(ERROR, "preliminary_cache only supported for per-file caches")
|
||||
fileToCache?.let { put(FILE_TO_CACHE, it) }
|
||||
filesToCache?.let { put(FILES_TO_CACHE, it.toList()) }
|
||||
put(MAKE_PER_FILE_CACHE, arguments.makePerFileCache)
|
||||
putIfNotNull(BATCHED_PER_FILE_CACHE_BUILD, when (arguments.batchedPerFileCacheBuild) {
|
||||
null -> null
|
||||
"enable" -> true
|
||||
"disable" -> false
|
||||
else -> {
|
||||
configuration.report(ERROR, "Expected 'enable' or 'disable' for batchedPerFileCacheBuild")
|
||||
false
|
||||
}
|
||||
})
|
||||
|
||||
parseShortModuleName(arguments, configuration, outputKind)?.let {
|
||||
put(SHORT_MODULE_NAME, it)
|
||||
|
||||
+3
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
|
||||
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
@@ -33,6 +34,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS")
|
||||
|
||||
val IrPackageFragment.isFunctionInterfaceFile get() = packageFragmentDescriptor is FunctionInterfacePackageFragment
|
||||
|
||||
abstract class KonanIrAbstractDescriptorBasedFunctionFactory : IrProvider, IrAbstractDescriptorBasedFunctionFactory()
|
||||
|
||||
internal class LazyIrFunctionFactory(
|
||||
|
||||
+39
-19
@@ -34,17 +34,25 @@ sealed class CacheDeserializationStrategy {
|
||||
override fun contains(fqName: FqName, fileName: String) = true
|
||||
}
|
||||
|
||||
class SingleFile(val filePath: String) : CacheDeserializationStrategy() {
|
||||
class SingleFile(val filePath: String, val fqName: String) : CacheDeserializationStrategy() {
|
||||
override fun contains(filePath: String) = filePath == this.filePath
|
||||
|
||||
lateinit var fqName: String
|
||||
|
||||
override fun contains(fqName: FqName, fileName: String) =
|
||||
fqName.asString() == this.fqName && File(filePath).name == fileName
|
||||
}
|
||||
|
||||
class MultipleFiles(filePaths: List<String>, fqNames: List<String>) : CacheDeserializationStrategy() {
|
||||
private val filePaths = filePaths.toSet()
|
||||
|
||||
private val fqNamesWithNames = fqNames.mapIndexed { i: Int, fqName: String -> Pair(fqName, File(filePaths[i]).name) }.toSet()
|
||||
|
||||
override fun contains(filePath: String) = filePath in filePaths
|
||||
|
||||
override fun contains(fqName: FqName, fileName: String) = Pair(fqName.asString(), fileName) in fqNamesWithNames
|
||||
}
|
||||
}
|
||||
|
||||
class PartialCacheInfo(val klib: KotlinLibrary, val strategy: CacheDeserializationStrategy)
|
||||
class PartialCacheInfo(val klib: KotlinLibrary, var strategy: CacheDeserializationStrategy)
|
||||
|
||||
class CacheSupport(
|
||||
private val configuration: CompilerConfiguration,
|
||||
@@ -64,7 +72,7 @@ class CacheSupport(
|
||||
?: configuration.reportCompilationError("cache directory $it is not found or not a directory")
|
||||
}
|
||||
|
||||
internal fun tryGetImplicitOutput(): String? {
|
||||
internal fun tryGetImplicitOutput(explicitlyProducePerFileCache: Boolean): String? {
|
||||
val libraryToCache = libraryToCache ?: return null
|
||||
// Put the resulting library in the first cache directory.
|
||||
val cacheDirectory = implicitCacheDirectories.firstOrNull() ?: return null
|
||||
@@ -75,19 +83,13 @@ class CacheSupport(
|
||||
else
|
||||
CachedLibraries.getPerFileCachedLibraryName(libraryToCache.klib)
|
||||
)
|
||||
if (singleFileStrategy == null)
|
||||
return baseLibraryCacheDirectory.absolutePath
|
||||
val singleFilePath = singleFileStrategy?.filePath
|
||||
?: return baseLibraryCacheDirectory.absolutePath
|
||||
|
||||
val fileToCache = singleFileStrategy.filePath
|
||||
val fileProtos = Array<ProtoFile>(libraryToCache.klib.fileCount()) {
|
||||
ProtoFile.parseFrom(libraryToCache.klib.file(it).codedInputStream, ExtensionRegistryLite.newInstance())
|
||||
}
|
||||
val fileIndex = fileProtos.indexOfFirst { it.fileEntry.name == fileToCache }
|
||||
require(fileIndex >= 0) { "No file found in klib with path $fileToCache" }
|
||||
val fileReader = IrLibraryFileFromBytes(IrKlibBytesSource(libraryToCache.klib, fileIndex))
|
||||
val fqName = fileReader.deserializeFqName(fileProtos[fileIndex].fqNameList)
|
||||
singleFileStrategy.fqName = fqName
|
||||
val fileCacheDirectory = baseLibraryCacheDirectory.child(cacheFileId(fqName, fileToCache))
|
||||
val fqName = singleFileStrategy.fqName
|
||||
val fileCacheDirectory = baseLibraryCacheDirectory.child(cacheFileId(fqName, singleFilePath))
|
||||
if (!explicitlyProducePerFileCache)
|
||||
return fileCacheDirectory.absolutePath
|
||||
val contentDirName = if (produce == CompilerOutputKind.PRELIMINARY_CACHE)
|
||||
CachedLibraries.PER_FILE_CACHE_IR_LEVEL_DIR_NAME
|
||||
else CachedLibraries.PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME
|
||||
@@ -132,8 +134,26 @@ class CacheSupport(
|
||||
if (libraryCache != null && libraryCache.granularity == CachedLibraries.Granularity.MODULE)
|
||||
null
|
||||
else {
|
||||
val fileToCache = configuration.get(KonanConfigKeys.FILE_TO_CACHE)
|
||||
PartialCacheInfo(libraryToAddToCache, if (fileToCache == null) CacheDeserializationStrategy.WholeModule else CacheDeserializationStrategy.SingleFile(fileToCache))
|
||||
val filesToCache = configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
||||
|
||||
val strategy = if (filesToCache.isNullOrEmpty())
|
||||
CacheDeserializationStrategy.WholeModule
|
||||
else {
|
||||
val fileProtos = Array<ProtoFile>(libraryToAddToCache.fileCount()) {
|
||||
ProtoFile.parseFrom(libraryToAddToCache.file(it).codedInputStream, ExtensionRegistryLite.newInstance())
|
||||
}
|
||||
val fileNameToIndex = fileProtos.withIndex().associate { it.value.fileEntry.name to it.index }
|
||||
val fqNames = filesToCache.map { fileName ->
|
||||
val index = fileNameToIndex[fileName] ?: error("No file with path $fileName is found in klib ${libraryToAddToCache.libraryName}")
|
||||
val fileReader = IrLibraryFileFromBytes(IrKlibBytesSource(libraryToAddToCache, index))
|
||||
fileReader.deserializeFqName(fileProtos[index].fqNameList)
|
||||
}
|
||||
if (configuration.get(KonanConfigKeys.BATCHED_PER_FILE_CACHE_BUILD) == false)
|
||||
CacheDeserializationStrategy.SingleFile(filesToCache.single(), fqNames.single())
|
||||
else
|
||||
CacheDeserializationStrategy.MultipleFiles(filesToCache, fqNames)
|
||||
}
|
||||
PartialCacheInfo(libraryToAddToCache, strategy)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-5
@@ -90,22 +90,25 @@ class CachedLibraries(
|
||||
private val cacheDirsContents = mutableMapOf<String, Set<String>>()
|
||||
|
||||
private fun selectCache(library: KotlinLibrary, cacheDir: File): Cache? {
|
||||
val cacheBinaryPartDir = cacheDir.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME)
|
||||
// See Linker.renameOutput why is it ok to have an empty cache directory.
|
||||
val cacheDirContents = cacheDirsContents.getOrPut(cacheDir.absolutePath) {
|
||||
cacheBinaryPartDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
||||
cacheDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
||||
}
|
||||
if (cacheDirContents.isEmpty()) return null
|
||||
val cacheBinaryPartDir = cacheDir.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME)
|
||||
val cacheBinaryPartDirContents = cacheDirsContents.getOrPut(cacheBinaryPartDir.absolutePath) {
|
||||
cacheBinaryPartDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
||||
}
|
||||
val baseName = getCachedLibraryName(library)
|
||||
val dynamicFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.DYNAMIC_CACHE))
|
||||
val staticFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.STATIC_CACHE))
|
||||
|
||||
if (dynamicFile.absolutePath in cacheDirContents && staticFile.absolutePath in cacheDirContents)
|
||||
if (dynamicFile.absolutePath in cacheBinaryPartDirContents && staticFile.absolutePath in cacheBinaryPartDirContents)
|
||||
error("Both dynamic and static caches files cannot be in the same directory." +
|
||||
" Library: ${library.libraryName}, path to cache: ${cacheDir.absolutePath}")
|
||||
return when {
|
||||
dynamicFile.absolutePath in cacheDirContents -> Cache(Kind.DYNAMIC, Granularity.MODULE, dynamicFile.absolutePath)
|
||||
staticFile.absolutePath in cacheDirContents -> Cache(Kind.STATIC, Granularity.MODULE, staticFile.absolutePath)
|
||||
dynamicFile.absolutePath in cacheBinaryPartDirContents -> Cache(Kind.DYNAMIC, Granularity.MODULE, dynamicFile.absolutePath)
|
||||
staticFile.absolutePath in cacheBinaryPartDirContents -> Cache(Kind.STATIC, Granularity.MODULE, staticFile.absolutePath)
|
||||
else -> Cache(Kind.STATIC, Granularity.FILE, cacheDir.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -70,6 +70,9 @@ val CompilerOutputKind.isCache: Boolean
|
||||
get() = this == CompilerOutputKind.STATIC_CACHE || this == CompilerOutputKind.DYNAMIC_CACHE
|
||||
|| this == CompilerOutputKind.PRELIMINARY_CACHE
|
||||
|
||||
val KonanConfig.involvesCodegen: Boolean
|
||||
get() = produce != CompilerOutputKind.LIBRARY && produce != CompilerOutputKind.PRELIMINARY_CACHE && !omitFrameworkBinary
|
||||
|
||||
internal fun llvmIrDumpCallback(state: ActionState, module: IrModuleFragment, context: Context) {
|
||||
module.let{}
|
||||
if (state.beforeOrAfter == BeforeOrAfter.AFTER && state.phase.name in context.configuration.getList(KonanConfigKeys.SAVE_LLVM_IR)) {
|
||||
|
||||
+20
-13
@@ -143,7 +143,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
lazyValues[member] = newValue
|
||||
}
|
||||
|
||||
private val localClassNames = mutableMapOf<IrAttributeContainer, String>()
|
||||
val localClassNames = mutableMapOf<IrAttributeContainer, String>()
|
||||
|
||||
fun getLocalClassName(container: IrAttributeContainer): String? = localClassNames[container.attributeOwnerId]
|
||||
|
||||
@@ -227,22 +227,32 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
|
||||
var llvmModule: LLVMModuleRef? = null
|
||||
set(module) {
|
||||
if (field != null) {
|
||||
throw Error("Another LLVMModule in the context.")
|
||||
}
|
||||
field = module!!
|
||||
|
||||
llvm = Llvm(this, module)
|
||||
debugInfo = DebugInfo(this)
|
||||
}
|
||||
|
||||
lateinit var runtime: Runtime
|
||||
|
||||
private var runtimeDisposed = false
|
||||
|
||||
fun disposeRuntime() {
|
||||
if (runtimeDisposed) return
|
||||
if (::runtime.isInitialized) {
|
||||
LLVMDisposeTargetData(runtime.targetData)
|
||||
LLVMDisposeModule(runtime.llvmModule)
|
||||
}
|
||||
runtimeDisposed = true
|
||||
}
|
||||
|
||||
lateinit var llvmImports: LlvmImports
|
||||
lateinit var llvm: Llvm
|
||||
val llvmImports: LlvmImports = Llvm.ImportsImpl(this)
|
||||
lateinit var llvmDeclarations: LlvmDeclarations
|
||||
lateinit var bitcodeFileName: String
|
||||
lateinit var library: KonanLibraryLayout
|
||||
|
||||
private var llvmDisposed = false
|
||||
var llvmDisposed = false
|
||||
|
||||
fun disposeLlvm() {
|
||||
if (llvmDisposed) return
|
||||
@@ -250,15 +260,10 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
LLVMDisposeDIBuilder(debugInfo.builder)
|
||||
if (llvmModule != null)
|
||||
LLVMDisposeModule(llvmModule)
|
||||
if (::llvm.isInitialized) {
|
||||
LLVMDisposeTargetData(llvm.runtime.targetData)
|
||||
LLVMDisposeModule(llvm.runtime.llvmModule)
|
||||
}
|
||||
tryDisposeLLVMContext()
|
||||
llvmDisposed = true
|
||||
}
|
||||
|
||||
val cStubsManager = CStubsManager(config.target)
|
||||
var cStubsManager = CStubsManager(config.target)
|
||||
|
||||
val coverage = CoverageManager(this)
|
||||
|
||||
@@ -354,7 +359,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
val llvmModuleSpecification: LlvmModuleSpecification by lazy {
|
||||
when {
|
||||
config.produce.isCache ->
|
||||
CacheLlvmModuleSpecification(config.cachedLibraries, config.libraryToCache!!.klib)
|
||||
CacheLlvmModuleSpecification(this, config.cachedLibraries, config.libraryToCache!!)
|
||||
else -> DefaultLlvmModuleSpecification(config.cachedLibraries)
|
||||
}
|
||||
}
|
||||
@@ -370,6 +375,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
||||
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
|
||||
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
|
||||
|
||||
val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>()
|
||||
|
||||
val targetAbiInfo: TargetAbiInfo by lazy {
|
||||
when {
|
||||
config.target == KonanTarget.MINGW_X64 -> {
|
||||
|
||||
+20
-5
@@ -410,13 +410,28 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
internal val libraryToCache: PartialCacheInfo?
|
||||
get() = cacheSupport.libraryToCache
|
||||
|
||||
internal val producePerFileCache = libraryToCache?.strategy is CacheDeserializationStrategy.SingleFile
|
||||
internal val producePerFileCache
|
||||
get() = libraryToCache?.strategy is CacheDeserializationStrategy.SingleFile
|
||||
|
||||
val outputFiles =
|
||||
OutputFiles(configuration.get(KonanConfigKeys.OUTPUT) ?: cacheSupport.tryGetImplicitOutput(),
|
||||
target, produce, producePerFileCache)
|
||||
internal val produceBatchedPerFileCache
|
||||
get() = configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) == true
|
||||
&& configuration.get(KonanConfigKeys.BATCHED_PER_FILE_CACHE_BUILD) != false
|
||||
|
||||
val tempFiles = TempFiles(outputFiles.outputName, configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR))
|
||||
lateinit var outputFiles: OutputFiles
|
||||
|
||||
lateinit var tempFiles: TempFiles
|
||||
|
||||
init {
|
||||
recreateOutputFiles(producePerFileCache)
|
||||
}
|
||||
|
||||
fun recreateOutputFiles(explicitlyProducePerFileCache: Boolean) {
|
||||
val outputPath = configuration.get(KonanConfigKeys.OUTPUT) ?: cacheSupport.tryGetImplicitOutput(explicitlyProducePerFileCache)
|
||||
outputFiles = OutputFiles(outputPath, target, produce, explicitlyProducePerFileCache)
|
||||
tempFiles = TempFiles(outputFiles.outputName, configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR))
|
||||
|
||||
println("ZZZ: ${outputFiles.outputName}")
|
||||
}
|
||||
|
||||
val outputFile get() = outputFiles.mainFileName
|
||||
|
||||
|
||||
+4
-2
@@ -44,10 +44,12 @@ class KonanConfigKeys {
|
||||
= CompilerConfigurationKey.create<List<String>>("paths to directories containing caches")
|
||||
val CACHED_LIBRARIES: CompilerConfigurationKey<Map<String, String>>
|
||||
= CompilerConfigurationKey.create<Map<String, String>>("mapping from library paths to cache paths")
|
||||
val FILE_TO_CACHE: CompilerConfigurationKey<String?>
|
||||
= CompilerConfigurationKey.create<String?>("which file should be compiled to cache")
|
||||
val FILES_TO_CACHE: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create<List<String>>("which files should be compiled to cache")
|
||||
val MAKE_PER_FILE_CACHE: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create<Boolean>("make per-file cache")
|
||||
val BATCHED_PER_FILE_CACHE_BUILD: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create<Boolean>("build per-file caches in batches")
|
||||
val FRAMEWORK_IMPORT_HEADERS: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create<List<String>>("headers imported to framework header")
|
||||
val FRIEND_MODULES: CompilerConfigurationKey<List<String>>
|
||||
|
||||
+13
-5
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
|
||||
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.backend.konan.llvm.tryDisposeLLVMContext
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
@@ -29,7 +30,7 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
||||
fun run() {
|
||||
val fileNames = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE)?.let { libPath ->
|
||||
if (configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) != true)
|
||||
null
|
||||
configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
||||
else {
|
||||
val lib = createKonanLibrary(File(libPath), "default", null, true)
|
||||
(0 until lib.fileCount()).map { fileIndex ->
|
||||
@@ -42,8 +43,14 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
||||
if (fileNames == null) {
|
||||
KonanConfig(project, configuration).runTopLevelPhases()
|
||||
} else {
|
||||
fileNames.forEach { buildFileCache(it, CompilerOutputKind.PRELIMINARY_CACHE) }
|
||||
fileNames.forEach { buildFileCache(it, configuration.get(KonanConfigKeys.PRODUCE)!!) }
|
||||
configuration.put(KonanConfigKeys.MAKE_PER_FILE_CACHE, true)
|
||||
if (configuration.get(KonanConfigKeys.BATCHED_PER_FILE_CACHE_BUILD) == false) {
|
||||
fileNames.forEach { buildFileCache(it, CompilerOutputKind.PRELIMINARY_CACHE) }
|
||||
fileNames.forEach { buildFileCache(it, configuration.get(KonanConfigKeys.PRODUCE)!!) }
|
||||
} else {
|
||||
configuration.put(KonanConfigKeys.FILES_TO_CACHE, fileNames)
|
||||
KonanConfig(project, configuration).runTopLevelPhases()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +58,7 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
||||
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(KonanConfigKeys.FILES_TO_CACHE, listOf(fileName))
|
||||
subConfiguration.put(CLIConfigurationKeys.PHASE_CONFIG, phaseConfig.toBuilder().build())
|
||||
KonanConfig(project, subConfiguration).runTopLevelPhases()
|
||||
}
|
||||
@@ -102,6 +108,8 @@ private fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreE
|
||||
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
||||
} finally {
|
||||
context.disposeLlvm()
|
||||
context.disposeRuntime()
|
||||
tryDisposeLLVMContext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-18
@@ -82,8 +82,8 @@ internal fun makeKonanModuleOpPhase(
|
||||
actions = modulePhaseActions
|
||||
)
|
||||
|
||||
internal val specialBackendChecksPhase = konanUnitPhase(
|
||||
op = { irModule!!.files.forEach { SpecialBackendChecksTraversal(this).lower(it) } },
|
||||
internal val specialBackendChecksPhase = makeKonanModuleLoweringPhase(
|
||||
::SpecialBackendChecksTraversal,
|
||||
name = "SpecialBackendChecks",
|
||||
description = "Special backend checks"
|
||||
)
|
||||
@@ -151,6 +151,18 @@ internal val inventNamesForLocalClasses = makeKonanFileLoweringPhase(
|
||||
|
||||
internal val extractLocalClassesFromInlineBodies = makeKonanFileOpPhase(
|
||||
{ context, irFile ->
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
if (declaration.isInline)
|
||||
context.inlineFunctionsSupport.saveNonLoweredInlineFunction(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
})
|
||||
|
||||
LocalClassesInInlineLambdasLowering(context).lower(irFile)
|
||||
LocalClassesInInlineFunctionsLowering(context).lower(irFile)
|
||||
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(irFile)
|
||||
@@ -168,18 +180,6 @@ internal val wrapInlineDeclarationsWithReifiedTypeParametersLowering = makeKonan
|
||||
|
||||
internal val inlinePhase = makeKonanFileOpPhase(
|
||||
{ context, irFile ->
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
if (declaration.isInline)
|
||||
context.inlineFunctionsSupport.getNonLoweredInlineFunction(declaration)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
}
|
||||
})
|
||||
|
||||
FunctionInlining(context, NativeInlineFunctionResolver(context)).lower(irFile)
|
||||
},
|
||||
name = "Inline",
|
||||
@@ -286,12 +286,10 @@ internal val rangeContainsLoweringPhase = makeKonanFileLoweringPhase(
|
||||
description = "Optimizes calls to contains() for ClosedRanges"
|
||||
)
|
||||
|
||||
internal val functionsWithoutBoundCheck = makeKonanModuleOpPhase(
|
||||
internal val functionsWithoutBoundCheck = konanUnitPhase(
|
||||
name = "FunctionsWithoutBoundCheckGenerator",
|
||||
description = "Functions without bounds check generation",
|
||||
op = { context, _ ->
|
||||
FunctionsWithoutBoundCheckGenerator(context).generate()
|
||||
}
|
||||
op = { FunctionsWithoutBoundCheckGenerator(this).generate() }
|
||||
)
|
||||
|
||||
internal val forLoopsPhase = makeKonanFileOpPhase(
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ internal class CacheStorage(val context: Context) {
|
||||
context.config.outputFiles.prepareTempDirectories()
|
||||
if (!isPreliminaryCache)
|
||||
saveCacheBitcodeDependencies()
|
||||
if (isPreliminaryCache || context.configuration.get(KonanConfigKeys.FILE_TO_CACHE) == null) {
|
||||
if (isPreliminaryCache || !context.config.producePerFileCache || context.config.produceBatchedPerFileCache) {
|
||||
saveInlineFunctionBodies()
|
||||
saveClassFields()
|
||||
}
|
||||
|
||||
+13
-2
@@ -6,8 +6,10 @@
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.ir.konanLibrary
|
||||
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
|
||||
@@ -41,10 +43,19 @@ internal class DefaultLlvmModuleSpecification(cachedLibraries: CachedLibraries)
|
||||
}
|
||||
|
||||
internal class CacheLlvmModuleSpecification(
|
||||
private val context: Context,
|
||||
cachedLibraries: CachedLibraries,
|
||||
private val libraryToCache: KotlinLibrary
|
||||
private val libraryToCache: PartialCacheInfo
|
||||
) : LlvmModuleSpecificationBase(cachedLibraries) {
|
||||
override val isFinal = false
|
||||
|
||||
override fun containsLibrary(library: KotlinLibrary): Boolean = library == libraryToCache
|
||||
override fun containsLibrary(library: KotlinLibrary): Boolean = library == libraryToCache.klib
|
||||
|
||||
override fun containsDeclaration(declaration: IrDeclaration): Boolean {
|
||||
if (context.shouldDefineFunctionClasses && declaration.getPackageFragment().isFunctionInterfaceFile)
|
||||
return true
|
||||
if (!super.containsDeclaration(declaration)) return false
|
||||
return (libraryToCache.strategy as? CacheDeserializationStrategy.SingleFile)
|
||||
?.filePath.let { it == null || it == declaration.fileOrNull?.path }
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ class OutputFiles(outputPath: String?, target: KonanTarget, val produce: Compile
|
||||
outputName.substring(0, outputName.lastIndexOf(File.separatorChar) /* skip [PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME]*/)
|
||||
else null
|
||||
|
||||
val perFileCacheFileName = pathToPerFileCache?.let { File(it).name }
|
||||
val perFileCacheFileName = File(pathToPerFileCache ?: outputName).absoluteFile.name
|
||||
|
||||
val cacheFileName = File((pathToPerFileCache ?: outputName).fullOutputName()).absoluteFile.name
|
||||
|
||||
|
||||
+92
-30
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
|
||||
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.*
|
||||
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -67,7 +68,7 @@ internal fun fileValidationCallback(state: ActionState, irFile: IrFile, context:
|
||||
internal fun konanUnitPhase(
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<AnyNamedPhase> = emptySet(),
|
||||
prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||
op: Context.() -> Unit
|
||||
) = namedOpUnitPhase(name, description, prerequisite, op)
|
||||
|
||||
@@ -328,6 +329,49 @@ internal val dependenciesLowerPhase = NamedCompilerPhase(
|
||||
}
|
||||
})
|
||||
|
||||
internal val umbrellaCompilation = NamedCompilerPhase(
|
||||
name = "UmbrellaCompilation",
|
||||
description = "A batched compilation with shared FE and ME phases",
|
||||
prerequisite = emptySet(),
|
||||
lower = object : CompilerPhase<Context, Unit, Unit> {
|
||||
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
|
||||
val module = context.irModules.values.single()
|
||||
|
||||
val files = module.files.toList()
|
||||
module.files.clear()
|
||||
val functionInterfaceFiles = files.filter { it.isFunctionInterfaceFile }
|
||||
|
||||
for (file in files) {
|
||||
if (file.isFunctionInterfaceFile) continue
|
||||
|
||||
// Pretend we're about to create a single file cache.
|
||||
context.config.cacheSupport.libraryToCache!!.strategy =
|
||||
CacheDeserializationStrategy.SingleFile(file.path, file.fqName.asString())
|
||||
context.config.recreateOutputFiles(explicitlyProducePerFileCache = false)
|
||||
|
||||
module.files += file
|
||||
if (context.shouldDefineFunctionClasses)
|
||||
module.files += functionInterfaceFiles
|
||||
|
||||
entireBackend.invoke(phaseConfig, phaserState, context, Unit)
|
||||
|
||||
module.files.clear()
|
||||
context.irModule!!.files.clear() // [dependenciesLowerPhase] puts all files to [context.irModule] for codegen.
|
||||
|
||||
context.inlineFunctionBodies.clear()
|
||||
context.classFields.clear()
|
||||
context.calledFromExportedInlineFunctions.clear()
|
||||
context.constructedFromExportedInlineFunctions.clear()
|
||||
context.localClassNames.clear()
|
||||
context.testCasesToDump.clear()
|
||||
context.mapping.loweredInlineFunctions.clear()
|
||||
context.cStubsManager = CStubsManager(context.config.target)
|
||||
}
|
||||
|
||||
module.files += files
|
||||
}
|
||||
})
|
||||
|
||||
internal val dumpTestsPhase = makeCustomPhase<Context, IrModuleFragment>(
|
||||
name = "dumpTestsPhase",
|
||||
description = "Dump the list of all available tests",
|
||||
@@ -408,12 +452,10 @@ private val bitcodePostprocessingPhase = NamedCompilerPhase(
|
||||
rewriteExternalCallsCheckerGlobals
|
||||
)
|
||||
|
||||
private val backendCodegen = namedUnitPhase(
|
||||
private val backendCodegen = NamedCompilerPhase(
|
||||
name = "Backend codegen",
|
||||
description = "Backend code generation",
|
||||
lower = takeFromContext<Context, Unit, IrModuleFragment> { it.irModule!! } then
|
||||
entryPointPhase then
|
||||
functionsWithoutBoundCheck then
|
||||
lower = entryPointPhase then
|
||||
allLoweringsPhase then // Lower current module first.
|
||||
dependenciesLowerPhase then // Then lower all libraries in topological order.
|
||||
// With that we guarantee that inline functions are unlowered while being inlined.
|
||||
@@ -422,36 +464,53 @@ private val backendCodegen = namedUnitPhase(
|
||||
verifyBitcodePhase then
|
||||
printBitcodePhase then
|
||||
linkBitcodeDependenciesPhase then
|
||||
bitcodePostprocessingPhase then
|
||||
unitSink()
|
||||
bitcodePostprocessingPhase
|
||||
)
|
||||
|
||||
private val entireBackend = NamedCompilerPhase(
|
||||
name = "EntireBackend",
|
||||
description = "Entire backend",
|
||||
lower = createLLVMImportsPhase then
|
||||
buildAdditionalCacheInfoPhase then
|
||||
takeFromContext { it.irModule!! } then
|
||||
specialBackendChecksPhase then
|
||||
backendCodegen then
|
||||
unitSink() then
|
||||
saveAdditionalCacheInfoPhase then
|
||||
produceOutputPhase then
|
||||
disposeLLVMPhase then
|
||||
objectFilesPhase then
|
||||
linkerPhase then
|
||||
finalizeCachePhase
|
||||
)
|
||||
|
||||
private val middleEnd = NamedCompilerPhase(
|
||||
name = "MiddleEnd",
|
||||
description = "Build and prepare IR for back end",
|
||||
lower = createSymbolTablePhase then
|
||||
objCExportPhase then
|
||||
buildCExportsPhase then
|
||||
psiToIrPhase then
|
||||
destroySymbolTablePhase then
|
||||
copyDefaultValuesToActualPhase then
|
||||
checkSamSuperTypesPhase then
|
||||
serializerPhase then
|
||||
functionsWithoutBoundCheck
|
||||
)
|
||||
|
||||
private val singleCompilation = NamedCompilerPhase(
|
||||
name = "SingleCompilation",
|
||||
description = "Single compilation",
|
||||
lower = entireBackend
|
||||
)
|
||||
|
||||
// Have to hide Context as type parameter in order to expose toplevelPhase outside of this module.
|
||||
val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
|
||||
name = "Compiler",
|
||||
description = "The whole compilation process",
|
||||
lower = createSymbolTablePhase then
|
||||
objCExportPhase then
|
||||
buildCExportsPhase then
|
||||
psiToIrPhase then
|
||||
buildAdditionalCacheInfoPhase then
|
||||
destroySymbolTablePhase then
|
||||
copyDefaultValuesToActualPhase then
|
||||
checkSamSuperTypesPhase then
|
||||
serializerPhase then
|
||||
specialBackendChecksPhase then
|
||||
namedUnitPhase(
|
||||
name = "Backend",
|
||||
description = "All backend",
|
||||
lower = backendCodegen then
|
||||
produceOutputPhase then
|
||||
disposeLLVMPhase then
|
||||
unitSink()
|
||||
) then
|
||||
saveAdditionalCacheInfoPhase then
|
||||
objectFilesPhase then
|
||||
linkerPhase then
|
||||
finalizeCachePhase
|
||||
lower = middleEnd then
|
||||
singleCompilation then
|
||||
umbrellaCompilation
|
||||
)
|
||||
|
||||
internal fun PhaseConfig.disableIf(phase: AnyNamedPhase, condition: Boolean) {
|
||||
@@ -472,6 +531,9 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
||||
|
||||
disable(localEscapeAnalysisPhase)
|
||||
|
||||
disableIf(singleCompilation, config.produceBatchedPerFileCache)
|
||||
disableUnless(umbrellaCompilation, config.produceBatchedPerFileCache)
|
||||
|
||||
// Don't serialize anything to a final executable.
|
||||
disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
|
||||
disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM)
|
||||
@@ -480,7 +542,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
||||
disableUnless(finalizeCachePhase, config.produce.isCache)
|
||||
disableUnless(exportInternalAbiPhase, config.produce.isCache)
|
||||
disableUnless(buildCExportsPhase, config.produce.isNativeLibrary)
|
||||
disableIf(backendCodegen, config.produce == CompilerOutputKind.LIBRARY || config.omitFrameworkBinary || config.produce == CompilerOutputKind.PRELIMINARY_CACHE)
|
||||
disableUnless(backendCodegen, config.involvesCodegen)
|
||||
disableUnless(checkExternalCallsPhase, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
|
||||
disableUnless(rewriteExternalCallsCheckerGlobals, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
|
||||
disableUnless(stringConcatenationTypeNarrowingPhase, config.optimizationsEnabled)
|
||||
|
||||
+11
-2
@@ -405,9 +405,18 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
|
||||
* All fields of the class instance.
|
||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
||||
*/
|
||||
val fields: List<FieldInfo> by lazy {
|
||||
val fields: List<FieldInfo>
|
||||
get() = fieldsInternal.map { fieldInfo ->
|
||||
val mappedField = fieldInfo.irField?.let { context.mapping.lateInitFieldToNullableField[it] ?: it }
|
||||
if (mappedField == fieldInfo.irField)
|
||||
fieldInfo
|
||||
else
|
||||
mappedField!!.toFieldInfo().also { it.index = fieldInfo.index }
|
||||
}
|
||||
|
||||
private val fieldsInternal: List<FieldInfo> by lazy {
|
||||
val superClass = irClass.getSuperClassNotAny()
|
||||
val superFields = if (superClass != null) context.getLayoutBuilder(superClass).fields else emptyList()
|
||||
val superFields = if (superClass != null) context.getLayoutBuilder(superClass).fieldsInternal else emptyList()
|
||||
|
||||
val declaredFields = getDeclaredFields()
|
||||
val sortedDeclaredFields = if (irClass.hasAnnotation(KonanFqNames.noReorderFields))
|
||||
|
||||
+18
-4
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.backend.konan.optimizations.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isFunction
|
||||
import org.jetbrains.kotlin.ir.util.isReal
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.konan.target.Architecture
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -39,7 +36,12 @@ internal val contextLLVMSetupPhase = makeKonanModuleOpPhase(
|
||||
// (see Llvm class in ContextUtils)
|
||||
// Which in turn is determined by the clang flags
|
||||
// used to compile runtime.bc.
|
||||
// TODO
|
||||
llvmContext = LLVMContextCreate()!!
|
||||
context.llvmDisposed = false
|
||||
|
||||
context.runtime = Runtime(context.config.distribution.compilerInterface(context.config.target))
|
||||
|
||||
val llvmModule = LLVMModuleCreateWithNameInContext("out", llvmContext)!!
|
||||
context.llvmModule = llvmModule
|
||||
context.debugInfo.builder = LLVMCreateDIBuilder(llvmModule)
|
||||
@@ -72,12 +74,24 @@ internal val createLLVMDeclarationsPhase = makeKonanModuleOpPhase(
|
||||
}
|
||||
)
|
||||
|
||||
internal val createLLVMImportsPhase = namedUnitPhase(
|
||||
name = "CreateLLVMImoorts",
|
||||
description = "Create LLVM imports",
|
||||
lower = object : CompilerPhase<Context, Unit, Unit> {
|
||||
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
|
||||
context.llvmImports = Llvm.ImportsImpl(context)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
internal val disposeLLVMPhase = namedUnitPhase(
|
||||
name = "DisposeLLVM",
|
||||
description = "Dispose LLVM",
|
||||
lower = object : CompilerPhase<Context, Unit, Unit> {
|
||||
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
|
||||
context.disposeLlvm()
|
||||
context.disposeRuntime()
|
||||
tryDisposeLLVMContext()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
+1
-2
@@ -444,8 +444,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
|
||||
|
||||
private val target = context.config.target
|
||||
|
||||
val runtimeFile = context.config.distribution.compilerInterface(target)
|
||||
override val runtime = Runtime(runtimeFile) // TODO: dispose
|
||||
override val runtime get() = context.runtime
|
||||
|
||||
val targetTriple = runtime.target
|
||||
|
||||
|
||||
+1
-1
@@ -2858,7 +2858,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
library == null -> context.config.moduleId.moduleConstructorName
|
||||
library == context.config.libraryToCache?.klib
|
||||
&& context.config.producePerFileCache ->
|
||||
fileCtorName(library.uniqueName, context.config.outputFiles.perFileCacheFileName!!)
|
||||
fileCtorName(library.uniqueName, context.config.outputFiles.perFileCacheFileName)
|
||||
else -> library.moduleConstructorName
|
||||
}
|
||||
|
||||
|
||||
-4
@@ -12,12 +12,8 @@ import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.KonanBinaryInterface.functionName
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
+35
-21
@@ -22,8 +22,19 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class InlineFunctionsSupport(mapping: NativeMapping) {
|
||||
private val notLoweredInlineFunctions = mapping.notLoweredInlineFunctions
|
||||
fun getNonLoweredInlineFunction(function: IrFunction) = notLoweredInlineFunctions.getOrPut(function.symbol) {
|
||||
function.deepCopyWithVariables().also { it.patchDeclarationParents(function.parent) }
|
||||
|
||||
fun saveNonLoweredInlineFunction(function: IrFunction) {
|
||||
getNonLoweredInlineFunction(function, copy = false)
|
||||
}
|
||||
|
||||
fun getNonLoweredInlineFunction(function: IrFunction, copy: Boolean): IrFunction {
|
||||
val notLoweredInlineFunction = notLoweredInlineFunctions.getOrPut(function.symbol) {
|
||||
function.deepCopyWithVariables().also { it.patchDeclarationParents(function.parent) }
|
||||
}
|
||||
return if (copy)
|
||||
notLoweredInlineFunction.deepCopyWithVariables().also { it.patchDeclarationParents(function.parent) }
|
||||
else
|
||||
notLoweredInlineFunction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +46,11 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
|
||||
context.mapping.loweredInlineFunctions[function]?.let { return it.irFunction }
|
||||
|
||||
val packageFragment = function.getPackageFragment()
|
||||
val notLoweredFunction = if (packageFragment !is IrExternalPackageFragment) {
|
||||
context.inlineFunctionsSupport.getNonLoweredInlineFunction(function).also {
|
||||
val (possiblyLoweredFunction, shouldLower) = if (packageFragment !is IrExternalPackageFragment) {
|
||||
context.inlineFunctionsSupport.getNonLoweredInlineFunction(function, copy = context.config.produceBatchedPerFileCache).also {
|
||||
context.mapping.loweredInlineFunctions[function] =
|
||||
InlineFunctionOriginInfo(it, packageFragment as IrFile, function.startOffset, function.endOffset)
|
||||
}
|
||||
} to true
|
||||
} else {
|
||||
// The function is from Lazy IR, get its body from the IR linker.
|
||||
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
||||
@@ -48,35 +59,38 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
|
||||
require(context.config.cachedLibraries.isLibraryCached(moduleDeserializer.klib)) {
|
||||
"No IR and no cache for ${function.render()}"
|
||||
}
|
||||
context.mapping.loweredInlineFunctions[function] = moduleDeserializer.deserializeInlineFunction(function)
|
||||
function
|
||||
val (shouldLower, deserializedInlineFunction) = moduleDeserializer.deserializeInlineFunction(function)
|
||||
context.mapping.loweredInlineFunctions[function] = deserializedInlineFunction
|
||||
function to shouldLower
|
||||
}
|
||||
|
||||
val body = notLoweredFunction.body ?: return notLoweredFunction
|
||||
if (!shouldLower) return possiblyLoweredFunction
|
||||
|
||||
PreInlineLowering(context).lower(body, notLoweredFunction, context.mapping.loweredInlineFunctions[function]!!.irFile)
|
||||
val body = possiblyLoweredFunction.body ?: return possiblyLoweredFunction
|
||||
|
||||
ArrayConstructorLowering(context).lower(body, notLoweredFunction)
|
||||
PreInlineLowering(context).lower(body, possiblyLoweredFunction, context.mapping.loweredInlineFunctions[function]!!.irFile)
|
||||
|
||||
NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(notLoweredFunction)
|
||||
NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(notLoweredFunction)
|
||||
LateinitUsageLowering(context).lower(body, notLoweredFunction)
|
||||
ArrayConstructorLowering(context).lower(body, possiblyLoweredFunction)
|
||||
|
||||
SharedVariablesLowering(context).lower(body, notLoweredFunction)
|
||||
NullableFieldsForLateinitCreationLowering(context).lowerWithLocalDeclarations(possiblyLoweredFunction)
|
||||
NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(possiblyLoweredFunction)
|
||||
LateinitUsageLowering(context).lower(body, possiblyLoweredFunction)
|
||||
|
||||
OuterThisLowering(context).lower(notLoweredFunction)
|
||||
SharedVariablesLowering(context).lower(body, possiblyLoweredFunction)
|
||||
|
||||
LocalClassesInInlineLambdasLowering(context).lower(body, notLoweredFunction)
|
||||
OuterThisLowering(context).lower(possiblyLoweredFunction)
|
||||
|
||||
if (packageFragment !is IrExternalPackageFragment) {
|
||||
LocalClassesInInlineLambdasLowering(context).lower(body, possiblyLoweredFunction)
|
||||
|
||||
if (context.llvmModuleSpecification.containsDeclaration(function)) {
|
||||
// Do not extract local classes off of inline functions from cached libraries.
|
||||
LocalClassesInInlineFunctionsLowering(context).lower(body, notLoweredFunction)
|
||||
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, notLoweredFunction)
|
||||
LocalClassesInInlineFunctionsLowering(context).lower(body, possiblyLoweredFunction)
|
||||
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, possiblyLoweredFunction)
|
||||
}
|
||||
|
||||
WrapInlineDeclarationsWithReifiedTypeParametersLowering(context).lower(body, notLoweredFunction)
|
||||
WrapInlineDeclarationsWithReifiedTypeParametersLowering(context).lower(body, possiblyLoweredFunction)
|
||||
|
||||
return notLoweredFunction
|
||||
return possiblyLoweredFunction
|
||||
}
|
||||
|
||||
private fun DeclarationTransformer.lowerWithLocalDeclarations(function: IrFunction) {
|
||||
|
||||
+24
-9
@@ -307,6 +307,8 @@ object KonanFakeOverrideClassFilter : FakeOverrideClassFilter {
|
||||
}
|
||||
}
|
||||
|
||||
internal data class DeserializedInlineFunction(val firstAccess: Boolean, val function: InlineFunctionOriginInfo)
|
||||
|
||||
internal class KonanIrLinker(
|
||||
private val currentModule: ModuleDescriptor,
|
||||
override val translationPluginContext: TranslationPluginContext?,
|
||||
@@ -387,14 +389,18 @@ internal class KonanIrLinker(
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun getExternalDeclarationFileName(declaration: IrDeclaration) = with(declaration) {
|
||||
val externalPackageFragment = getPackageFragment() as? IrExternalPackageFragment
|
||||
?: error("Expected an external package fragment for ${render()}")
|
||||
val moduleDescriptor = externalPackageFragment.packageFragmentDescriptor.containingDeclaration
|
||||
val moduleDeserializer = moduleDeserializers[moduleDescriptor]
|
||||
?: error("No module deserializer for $moduleDescriptor")
|
||||
val idSig = moduleDeserializer.descriptorSignatures[descriptor] ?: error("No signature for $descriptor")
|
||||
idSig.topLevelSignature().fileSignature()?.fileName ?: error("No file for $idSig")
|
||||
fun getExternalDeclarationFileName(declaration: IrDeclaration) = when (val packageFragment = declaration.getPackageFragment()) {
|
||||
is IrFile -> packageFragment.path
|
||||
|
||||
is IrExternalPackageFragment -> {
|
||||
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
||||
val moduleDeserializer = moduleDeserializers[moduleDescriptor] ?: error("No module deserializer for $moduleDescriptor")
|
||||
val descriptor = declaration.descriptor
|
||||
val idSig = moduleDeserializer.descriptorSignatures[descriptor] ?: error("No signature for $descriptor")
|
||||
idSig.topLevelSignature().fileSignature()?.fileName ?: error("No file for $idSig")
|
||||
}
|
||||
|
||||
else -> error("Unknown package fragment kind ${packageFragment::class.java}")
|
||||
}
|
||||
|
||||
private val IrClass.firstNonClassParent: IrDeclarationParent
|
||||
@@ -637,7 +643,16 @@ internal class KonanIrLinker(
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeInlineFunction(function: IrFunction): InlineFunctionOriginInfo {
|
||||
private val deserializedInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||
|
||||
fun deserializeInlineFunction(function: IrFunction): DeserializedInlineFunction {
|
||||
deserializedInlineFunctions[function]?.let { return DeserializedInlineFunction(firstAccess = false, it) }
|
||||
val result = deserializeInlineFunctionInternal(function)
|
||||
deserializedInlineFunctions[function] = result
|
||||
return DeserializedInlineFunction(firstAccess = true, result)
|
||||
}
|
||||
|
||||
private fun deserializeInlineFunctionInternal(function: IrFunction): InlineFunctionOriginInfo {
|
||||
val packageFragment = function.getPackageFragment() as? IrExternalPackageFragment
|
||||
?: error("Expected an external package fragment for ${function.render()}")
|
||||
if (function.parents.any { (it as? IrFunction)?.isInline == true }) {
|
||||
|
||||
Reference in New Issue
Block a user