[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",
|
description = "Path to file to cache",
|
||||||
delimiter = ""
|
delimiter = ""
|
||||||
)
|
)
|
||||||
var fileToCache: String? = null
|
var filesToCache: Array<String>? = null
|
||||||
|
|
||||||
@Argument(value = "-Xmake-per-file-cache", description = "Force compiler to produce per-file cache")
|
@Argument(value = "-Xmake-per-file-cache", description = "Force compiler to produce per-file cache")
|
||||||
var makePerFileCache: Boolean = false
|
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")
|
@Argument(value = "-Xexport-kdoc", description = "Export KDoc in framework header")
|
||||||
var exportKDoc: Boolean = false
|
var exportKDoc: Boolean = false
|
||||||
|
|
||||||
|
|||||||
@@ -285,11 +285,20 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
libraryToAddToCache?.let { put(LIBRARY_TO_ADD_TO_CACHE, it) }
|
libraryToAddToCache?.let { put(LIBRARY_TO_ADD_TO_CACHE, it) }
|
||||||
put(CACHE_DIRECTORIES, cacheDirectories)
|
put(CACHE_DIRECTORIES, cacheDirectories)
|
||||||
put(CACHED_LIBRARIES, parseCachedLibraries(arguments, configuration))
|
put(CACHED_LIBRARIES, parseCachedLibraries(arguments, configuration))
|
||||||
val fileToCache = arguments.fileToCache
|
val filesToCache = arguments.filesToCache
|
||||||
if (outputKind == CompilerOutputKind.PRELIMINARY_CACHE && fileToCache == null)
|
if (outputKind == CompilerOutputKind.PRELIMINARY_CACHE && filesToCache.isNullOrEmpty())
|
||||||
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) }
|
filesToCache?.let { put(FILES_TO_CACHE, it.toList()) }
|
||||||
put(MAKE_PER_FILE_CACHE, arguments.makePerFileCache)
|
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 {
|
parseShortModuleName(arguments, configuration, outputKind)?.let {
|
||||||
put(SHORT_MODULE_NAME, it)
|
put(SHORT_MODULE_NAME, it)
|
||||||
|
|||||||
+3
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
|
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.FunctionClassDescriptor
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
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")
|
internal object DECLARATION_ORIGIN_FUNCTION_CLASS : IrDeclarationOriginImpl("DECLARATION_ORIGIN_FUNCTION_CLASS")
|
||||||
|
|
||||||
|
val IrPackageFragment.isFunctionInterfaceFile get() = packageFragmentDescriptor is FunctionInterfacePackageFragment
|
||||||
|
|
||||||
abstract class KonanIrAbstractDescriptorBasedFunctionFactory : IrProvider, IrAbstractDescriptorBasedFunctionFactory()
|
abstract class KonanIrAbstractDescriptorBasedFunctionFactory : IrProvider, IrAbstractDescriptorBasedFunctionFactory()
|
||||||
|
|
||||||
internal class LazyIrFunctionFactory(
|
internal class LazyIrFunctionFactory(
|
||||||
|
|||||||
+39
-19
@@ -34,17 +34,25 @@ sealed class CacheDeserializationStrategy {
|
|||||||
override fun contains(fqName: FqName, fileName: String) = true
|
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
|
override fun contains(filePath: String) = filePath == this.filePath
|
||||||
|
|
||||||
lateinit var fqName: String
|
|
||||||
|
|
||||||
override fun contains(fqName: FqName, fileName: String) =
|
override fun contains(fqName: FqName, fileName: String) =
|
||||||
fqName.asString() == this.fqName && File(filePath).name == fileName
|
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(
|
class CacheSupport(
|
||||||
private val configuration: CompilerConfiguration,
|
private val configuration: CompilerConfiguration,
|
||||||
@@ -64,7 +72,7 @@ class CacheSupport(
|
|||||||
?: configuration.reportCompilationError("cache directory $it is not found or not a directory")
|
?: 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
|
val libraryToCache = libraryToCache ?: return null
|
||||||
// Put the resulting library in the first cache directory.
|
// Put the resulting library in the first cache directory.
|
||||||
val cacheDirectory = implicitCacheDirectories.firstOrNull() ?: return null
|
val cacheDirectory = implicitCacheDirectories.firstOrNull() ?: return null
|
||||||
@@ -75,19 +83,13 @@ class CacheSupport(
|
|||||||
else
|
else
|
||||||
CachedLibraries.getPerFileCachedLibraryName(libraryToCache.klib)
|
CachedLibraries.getPerFileCachedLibraryName(libraryToCache.klib)
|
||||||
)
|
)
|
||||||
if (singleFileStrategy == null)
|
val singleFilePath = singleFileStrategy?.filePath
|
||||||
return baseLibraryCacheDirectory.absolutePath
|
?: return baseLibraryCacheDirectory.absolutePath
|
||||||
|
|
||||||
val fileToCache = singleFileStrategy.filePath
|
val fqName = singleFileStrategy.fqName
|
||||||
val fileProtos = Array<ProtoFile>(libraryToCache.klib.fileCount()) {
|
val fileCacheDirectory = baseLibraryCacheDirectory.child(cacheFileId(fqName, singleFilePath))
|
||||||
ProtoFile.parseFrom(libraryToCache.klib.file(it).codedInputStream, ExtensionRegistryLite.newInstance())
|
if (!explicitlyProducePerFileCache)
|
||||||
}
|
return fileCacheDirectory.absolutePath
|
||||||
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 contentDirName = if (produce == CompilerOutputKind.PRELIMINARY_CACHE)
|
val contentDirName = if (produce == CompilerOutputKind.PRELIMINARY_CACHE)
|
||||||
CachedLibraries.PER_FILE_CACHE_IR_LEVEL_DIR_NAME
|
CachedLibraries.PER_FILE_CACHE_IR_LEVEL_DIR_NAME
|
||||||
else CachedLibraries.PER_FILE_CACHE_BINARY_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)
|
if (libraryCache != null && libraryCache.granularity == CachedLibraries.Granularity.MODULE)
|
||||||
null
|
null
|
||||||
else {
|
else {
|
||||||
val fileToCache = configuration.get(KonanConfigKeys.FILE_TO_CACHE)
|
val filesToCache = configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
||||||
PartialCacheInfo(libraryToAddToCache, if (fileToCache == null) CacheDeserializationStrategy.WholeModule else CacheDeserializationStrategy.SingleFile(fileToCache))
|
|
||||||
|
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 val cacheDirsContents = mutableMapOf<String, Set<String>>()
|
||||||
|
|
||||||
private fun selectCache(library: KotlinLibrary, cacheDir: File): Cache? {
|
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.
|
// See Linker.renameOutput why is it ok to have an empty cache directory.
|
||||||
val cacheDirContents = cacheDirsContents.getOrPut(cacheDir.absolutePath) {
|
val cacheDirContents = cacheDirsContents.getOrPut(cacheDir.absolutePath) {
|
||||||
cacheBinaryPartDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
cacheDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
||||||
}
|
}
|
||||||
if (cacheDirContents.isEmpty()) return null
|
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 baseName = getCachedLibraryName(library)
|
||||||
val dynamicFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.DYNAMIC_CACHE))
|
val dynamicFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.DYNAMIC_CACHE))
|
||||||
val staticFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.STATIC_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." +
|
error("Both dynamic and static caches files cannot be in the same directory." +
|
||||||
" Library: ${library.libraryName}, path to cache: ${cacheDir.absolutePath}")
|
" Library: ${library.libraryName}, path to cache: ${cacheDir.absolutePath}")
|
||||||
return when {
|
return when {
|
||||||
dynamicFile.absolutePath in cacheDirContents -> Cache(Kind.DYNAMIC, Granularity.MODULE, dynamicFile.absolutePath)
|
dynamicFile.absolutePath in cacheBinaryPartDirContents -> Cache(Kind.DYNAMIC, Granularity.MODULE, dynamicFile.absolutePath)
|
||||||
staticFile.absolutePath in cacheDirContents -> Cache(Kind.STATIC, Granularity.MODULE, staticFile.absolutePath)
|
staticFile.absolutePath in cacheBinaryPartDirContents -> Cache(Kind.STATIC, Granularity.MODULE, staticFile.absolutePath)
|
||||||
else -> Cache(Kind.STATIC, Granularity.FILE, cacheDir.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
|
get() = this == CompilerOutputKind.STATIC_CACHE || this == CompilerOutputKind.DYNAMIC_CACHE
|
||||||
|| this == CompilerOutputKind.PRELIMINARY_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) {
|
internal fun llvmIrDumpCallback(state: ActionState, module: IrModuleFragment, context: Context) {
|
||||||
module.let{}
|
module.let{}
|
||||||
if (state.beforeOrAfter == BeforeOrAfter.AFTER && state.phase.name in context.configuration.getList(KonanConfigKeys.SAVE_LLVM_IR)) {
|
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
|
lazyValues[member] = newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
private val localClassNames = mutableMapOf<IrAttributeContainer, String>()
|
val localClassNames = mutableMapOf<IrAttributeContainer, String>()
|
||||||
|
|
||||||
fun getLocalClassName(container: IrAttributeContainer): String? = localClassNames[container.attributeOwnerId]
|
fun getLocalClassName(container: IrAttributeContainer): String? = localClassNames[container.attributeOwnerId]
|
||||||
|
|
||||||
@@ -227,22 +227,32 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
|
|
||||||
var llvmModule: LLVMModuleRef? = null
|
var llvmModule: LLVMModuleRef? = null
|
||||||
set(module) {
|
set(module) {
|
||||||
if (field != null) {
|
|
||||||
throw Error("Another LLVMModule in the context.")
|
|
||||||
}
|
|
||||||
field = module!!
|
field = module!!
|
||||||
|
|
||||||
llvm = Llvm(this, module)
|
llvm = Llvm(this, module)
|
||||||
debugInfo = DebugInfo(this)
|
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
|
lateinit var llvm: Llvm
|
||||||
val llvmImports: LlvmImports = Llvm.ImportsImpl(this)
|
|
||||||
lateinit var llvmDeclarations: LlvmDeclarations
|
lateinit var llvmDeclarations: LlvmDeclarations
|
||||||
lateinit var bitcodeFileName: String
|
lateinit var bitcodeFileName: String
|
||||||
lateinit var library: KonanLibraryLayout
|
lateinit var library: KonanLibraryLayout
|
||||||
|
|
||||||
private var llvmDisposed = false
|
var llvmDisposed = false
|
||||||
|
|
||||||
fun disposeLlvm() {
|
fun disposeLlvm() {
|
||||||
if (llvmDisposed) return
|
if (llvmDisposed) return
|
||||||
@@ -250,15 +260,10 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
LLVMDisposeDIBuilder(debugInfo.builder)
|
LLVMDisposeDIBuilder(debugInfo.builder)
|
||||||
if (llvmModule != null)
|
if (llvmModule != null)
|
||||||
LLVMDisposeModule(llvmModule)
|
LLVMDisposeModule(llvmModule)
|
||||||
if (::llvm.isInitialized) {
|
|
||||||
LLVMDisposeTargetData(llvm.runtime.targetData)
|
|
||||||
LLVMDisposeModule(llvm.runtime.llvmModule)
|
|
||||||
}
|
|
||||||
tryDisposeLLVMContext()
|
|
||||||
llvmDisposed = true
|
llvmDisposed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
val cStubsManager = CStubsManager(config.target)
|
var cStubsManager = CStubsManager(config.target)
|
||||||
|
|
||||||
val coverage = CoverageManager(this)
|
val coverage = CoverageManager(this)
|
||||||
|
|
||||||
@@ -354,7 +359,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
val llvmModuleSpecification: LlvmModuleSpecification by lazy {
|
val llvmModuleSpecification: LlvmModuleSpecification by lazy {
|
||||||
when {
|
when {
|
||||||
config.produce.isCache ->
|
config.produce.isCache ->
|
||||||
CacheLlvmModuleSpecification(config.cachedLibraries, config.libraryToCache!!.klib)
|
CacheLlvmModuleSpecification(this, config.cachedLibraries, config.libraryToCache!!)
|
||||||
else -> DefaultLlvmModuleSpecification(config.cachedLibraries)
|
else -> DefaultLlvmModuleSpecification(config.cachedLibraries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,6 +375,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
|
|||||||
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
|
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
|
||||||
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
|
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
|
||||||
|
|
||||||
|
val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>()
|
||||||
|
|
||||||
val targetAbiInfo: TargetAbiInfo by lazy {
|
val targetAbiInfo: TargetAbiInfo by lazy {
|
||||||
when {
|
when {
|
||||||
config.target == KonanTarget.MINGW_X64 -> {
|
config.target == KonanTarget.MINGW_X64 -> {
|
||||||
|
|||||||
+20
-5
@@ -410,13 +410,28 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
internal val libraryToCache: PartialCacheInfo?
|
internal val libraryToCache: PartialCacheInfo?
|
||||||
get() = cacheSupport.libraryToCache
|
get() = cacheSupport.libraryToCache
|
||||||
|
|
||||||
internal val producePerFileCache = libraryToCache?.strategy is CacheDeserializationStrategy.SingleFile
|
internal val producePerFileCache
|
||||||
|
get() = libraryToCache?.strategy is CacheDeserializationStrategy.SingleFile
|
||||||
|
|
||||||
val outputFiles =
|
internal val produceBatchedPerFileCache
|
||||||
OutputFiles(configuration.get(KonanConfigKeys.OUTPUT) ?: cacheSupport.tryGetImplicitOutput(),
|
get() = configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) == true
|
||||||
target, produce, producePerFileCache)
|
&& 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
|
val outputFile get() = outputFiles.mainFileName
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -44,10 +44,12 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create<List<String>>("paths to directories containing caches")
|
= CompilerConfigurationKey.create<List<String>>("paths to directories containing caches")
|
||||||
val CACHED_LIBRARIES: CompilerConfigurationKey<Map<String, String>>
|
val CACHED_LIBRARIES: CompilerConfigurationKey<Map<String, String>>
|
||||||
= 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 FILES_TO_CACHE: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create<String?>("which file should be compiled to cache")
|
= CompilerConfigurationKey.create<List<String>>("which files should be compiled to cache")
|
||||||
val MAKE_PER_FILE_CACHE: CompilerConfigurationKey<Boolean>
|
val MAKE_PER_FILE_CACHE: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create<Boolean>("make per-file cache")
|
= 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>>
|
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>>
|
||||||
|
|||||||
+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.phaser.invokeToplevel
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.codedInputStream
|
import org.jetbrains.kotlin.backend.common.serialization.codedInputStream
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile
|
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.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
|
||||||
@@ -29,7 +30,7 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
|||||||
fun run() {
|
fun run() {
|
||||||
val fileNames = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE)?.let { libPath ->
|
val fileNames = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE)?.let { libPath ->
|
||||||
if (configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) != true)
|
if (configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) != true)
|
||||||
null
|
configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
||||||
else {
|
else {
|
||||||
val lib = createKonanLibrary(File(libPath), "default", null, true)
|
val lib = createKonanLibrary(File(libPath), "default", null, true)
|
||||||
(0 until lib.fileCount()).map { fileIndex ->
|
(0 until lib.fileCount()).map { fileIndex ->
|
||||||
@@ -42,8 +43,14 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
|
|||||||
if (fileNames == null) {
|
if (fileNames == null) {
|
||||||
KonanConfig(project, configuration).runTopLevelPhases()
|
KonanConfig(project, configuration).runTopLevelPhases()
|
||||||
} else {
|
} else {
|
||||||
fileNames.forEach { buildFileCache(it, CompilerOutputKind.PRELIMINARY_CACHE) }
|
configuration.put(KonanConfigKeys.MAKE_PER_FILE_CACHE, true)
|
||||||
fileNames.forEach { buildFileCache(it, configuration.get(KonanConfigKeys.PRODUCE)!!) }
|
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 phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)!!
|
||||||
val subConfiguration = configuration.copy()
|
val subConfiguration = configuration.copy()
|
||||||
subConfiguration.put(KonanConfigKeys.PRODUCE, cacheKind)
|
subConfiguration.put(KonanConfigKeys.PRODUCE, cacheKind)
|
||||||
subConfiguration.put(KonanConfigKeys.FILE_TO_CACHE, fileName)
|
subConfiguration.put(KonanConfigKeys.FILES_TO_CACHE, listOf(fileName))
|
||||||
subConfiguration.put(KonanConfigKeys.MAKE_PER_FILE_CACHE, false)
|
|
||||||
subConfiguration.put(CLIConfigurationKeys.PHASE_CONFIG, phaseConfig.toBuilder().build())
|
subConfiguration.put(CLIConfigurationKeys.PHASE_CONFIG, phaseConfig.toBuilder().build())
|
||||||
KonanConfig(project, subConfiguration).runTopLevelPhases()
|
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)
|
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
|
||||||
} finally {
|
} finally {
|
||||||
context.disposeLlvm()
|
context.disposeLlvm()
|
||||||
|
context.disposeRuntime()
|
||||||
|
tryDisposeLLVMContext()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-18
@@ -82,8 +82,8 @@ internal fun makeKonanModuleOpPhase(
|
|||||||
actions = modulePhaseActions
|
actions = modulePhaseActions
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val specialBackendChecksPhase = konanUnitPhase(
|
internal val specialBackendChecksPhase = makeKonanModuleLoweringPhase(
|
||||||
op = { irModule!!.files.forEach { SpecialBackendChecksTraversal(this).lower(it) } },
|
::SpecialBackendChecksTraversal,
|
||||||
name = "SpecialBackendChecks",
|
name = "SpecialBackendChecks",
|
||||||
description = "Special backend checks"
|
description = "Special backend checks"
|
||||||
)
|
)
|
||||||
@@ -151,6 +151,18 @@ internal val inventNamesForLocalClasses = makeKonanFileLoweringPhase(
|
|||||||
|
|
||||||
internal val extractLocalClassesFromInlineBodies = makeKonanFileOpPhase(
|
internal val extractLocalClassesFromInlineBodies = makeKonanFileOpPhase(
|
||||||
{ context, irFile ->
|
{ 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)
|
LocalClassesInInlineLambdasLowering(context).lower(irFile)
|
||||||
LocalClassesInInlineFunctionsLowering(context).lower(irFile)
|
LocalClassesInInlineFunctionsLowering(context).lower(irFile)
|
||||||
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(irFile)
|
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(irFile)
|
||||||
@@ -168,18 +180,6 @@ internal val wrapInlineDeclarationsWithReifiedTypeParametersLowering = makeKonan
|
|||||||
|
|
||||||
internal val inlinePhase = makeKonanFileOpPhase(
|
internal val inlinePhase = makeKonanFileOpPhase(
|
||||||
{ context, irFile ->
|
{ 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)
|
FunctionInlining(context, NativeInlineFunctionResolver(context)).lower(irFile)
|
||||||
},
|
},
|
||||||
name = "Inline",
|
name = "Inline",
|
||||||
@@ -286,12 +286,10 @@ internal val rangeContainsLoweringPhase = makeKonanFileLoweringPhase(
|
|||||||
description = "Optimizes calls to contains() for ClosedRanges"
|
description = "Optimizes calls to contains() for ClosedRanges"
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val functionsWithoutBoundCheck = makeKonanModuleOpPhase(
|
internal val functionsWithoutBoundCheck = konanUnitPhase(
|
||||||
name = "FunctionsWithoutBoundCheckGenerator",
|
name = "FunctionsWithoutBoundCheckGenerator",
|
||||||
description = "Functions without bounds check generation",
|
description = "Functions without bounds check generation",
|
||||||
op = { context, _ ->
|
op = { FunctionsWithoutBoundCheckGenerator(this).generate() }
|
||||||
FunctionsWithoutBoundCheckGenerator(context).generate()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val forLoopsPhase = makeKonanFileOpPhase(
|
internal val forLoopsPhase = makeKonanFileOpPhase(
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ internal class CacheStorage(val context: Context) {
|
|||||||
context.config.outputFiles.prepareTempDirectories()
|
context.config.outputFiles.prepareTempDirectories()
|
||||||
if (!isPreliminaryCache)
|
if (!isPreliminaryCache)
|
||||||
saveCacheBitcodeDependencies()
|
saveCacheBitcodeDependencies()
|
||||||
if (isPreliminaryCache || context.configuration.get(KonanConfigKeys.FILE_TO_CACHE) == null) {
|
if (isPreliminaryCache || !context.config.producePerFileCache || context.config.produceBatchedPerFileCache) {
|
||||||
saveInlineFunctionBodies()
|
saveInlineFunctionBodies()
|
||||||
saveClassFields()
|
saveClassFields()
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -6,8 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.konanLibrary
|
import org.jetbrains.kotlin.backend.konan.ir.konanLibrary
|
||||||
|
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
|
|
||||||
@@ -41,10 +43,19 @@ internal class DefaultLlvmModuleSpecification(cachedLibraries: CachedLibraries)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class CacheLlvmModuleSpecification(
|
internal class CacheLlvmModuleSpecification(
|
||||||
|
private val context: Context,
|
||||||
cachedLibraries: CachedLibraries,
|
cachedLibraries: CachedLibraries,
|
||||||
private val libraryToCache: KotlinLibrary
|
private val libraryToCache: PartialCacheInfo
|
||||||
) : LlvmModuleSpecificationBase(cachedLibraries) {
|
) : LlvmModuleSpecificationBase(cachedLibraries) {
|
||||||
override val isFinal = false
|
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]*/)
|
outputName.substring(0, outputName.lastIndexOf(File.separatorChar) /* skip [PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME]*/)
|
||||||
else null
|
else null
|
||||||
|
|
||||||
val perFileCacheFileName = pathToPerFileCache?.let { File(it).name }
|
val perFileCacheFileName = File(pathToPerFileCache ?: outputName).absoluteFile.name
|
||||||
|
|
||||||
val cacheFileName = File((pathToPerFileCache ?: outputName).fullOutputName()).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.lower.SamSuperTypesChecker
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.*
|
import org.jetbrains.kotlin.backend.konan.serialization.*
|
||||||
|
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
@@ -67,7 +68,7 @@ internal fun fileValidationCallback(state: ActionState, irFile: IrFile, context:
|
|||||||
internal fun konanUnitPhase(
|
internal fun konanUnitPhase(
|
||||||
name: String,
|
name: String,
|
||||||
description: String,
|
description: String,
|
||||||
prerequisite: Set<AnyNamedPhase> = emptySet(),
|
prerequisite: Set<NamedCompilerPhase<Context, *>> = emptySet(),
|
||||||
op: Context.() -> Unit
|
op: Context.() -> Unit
|
||||||
) = namedOpUnitPhase(name, description, prerequisite, op)
|
) = 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>(
|
internal val dumpTestsPhase = makeCustomPhase<Context, IrModuleFragment>(
|
||||||
name = "dumpTestsPhase",
|
name = "dumpTestsPhase",
|
||||||
description = "Dump the list of all available tests",
|
description = "Dump the list of all available tests",
|
||||||
@@ -408,12 +452,10 @@ private val bitcodePostprocessingPhase = NamedCompilerPhase(
|
|||||||
rewriteExternalCallsCheckerGlobals
|
rewriteExternalCallsCheckerGlobals
|
||||||
)
|
)
|
||||||
|
|
||||||
private val backendCodegen = namedUnitPhase(
|
private val backendCodegen = NamedCompilerPhase(
|
||||||
name = "Backend codegen",
|
name = "Backend codegen",
|
||||||
description = "Backend code generation",
|
description = "Backend code generation",
|
||||||
lower = takeFromContext<Context, Unit, IrModuleFragment> { it.irModule!! } then
|
lower = entryPointPhase then
|
||||||
entryPointPhase then
|
|
||||||
functionsWithoutBoundCheck then
|
|
||||||
allLoweringsPhase then // Lower current module first.
|
allLoweringsPhase then // Lower current module first.
|
||||||
dependenciesLowerPhase then // Then lower all libraries in topological order.
|
dependenciesLowerPhase then // Then lower all libraries in topological order.
|
||||||
// With that we guarantee that inline functions are unlowered while being inlined.
|
// With that we guarantee that inline functions are unlowered while being inlined.
|
||||||
@@ -422,36 +464,53 @@ private val backendCodegen = namedUnitPhase(
|
|||||||
verifyBitcodePhase then
|
verifyBitcodePhase then
|
||||||
printBitcodePhase then
|
printBitcodePhase then
|
||||||
linkBitcodeDependenciesPhase then
|
linkBitcodeDependenciesPhase then
|
||||||
bitcodePostprocessingPhase then
|
bitcodePostprocessingPhase
|
||||||
unitSink()
|
)
|
||||||
|
|
||||||
|
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.
|
// Have to hide Context as type parameter in order to expose toplevelPhase outside of this module.
|
||||||
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 = createSymbolTablePhase then
|
lower = middleEnd then
|
||||||
objCExportPhase then
|
singleCompilation then
|
||||||
buildCExportsPhase then
|
umbrellaCompilation
|
||||||
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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
internal fun PhaseConfig.disableIf(phase: AnyNamedPhase, condition: Boolean) {
|
internal fun PhaseConfig.disableIf(phase: AnyNamedPhase, condition: Boolean) {
|
||||||
@@ -472,6 +531,9 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
|||||||
|
|
||||||
disable(localEscapeAnalysisPhase)
|
disable(localEscapeAnalysisPhase)
|
||||||
|
|
||||||
|
disableIf(singleCompilation, config.produceBatchedPerFileCache)
|
||||||
|
disableUnless(umbrellaCompilation, config.produceBatchedPerFileCache)
|
||||||
|
|
||||||
// Don't serialize anything to a final executable.
|
// Don't serialize anything to a final executable.
|
||||||
disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
|
disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
|
||||||
disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM)
|
disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM)
|
||||||
@@ -480,7 +542,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
|
|||||||
disableUnless(finalizeCachePhase, config.produce.isCache)
|
disableUnless(finalizeCachePhase, config.produce.isCache)
|
||||||
disableUnless(exportInternalAbiPhase, config.produce.isCache)
|
disableUnless(exportInternalAbiPhase, config.produce.isCache)
|
||||||
disableUnless(buildCExportsPhase, config.produce.isNativeLibrary)
|
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(checkExternalCallsPhase, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
|
||||||
disableUnless(rewriteExternalCallsCheckerGlobals, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
|
disableUnless(rewriteExternalCallsCheckerGlobals, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
|
||||||
disableUnless(stringConcatenationTypeNarrowingPhase, config.optimizationsEnabled)
|
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.
|
* All fields of the class instance.
|
||||||
* The order respects the class hierarchy, i.e. a class [fields] contains superclass [fields] as a prefix.
|
* 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 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 declaredFields = getDeclaredFields()
|
||||||
val sortedDeclaredFields = if (irClass.hasAnnotation(KonanFqNames.noReorderFields))
|
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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
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.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.konan.target.Architecture
|
import org.jetbrains.kotlin.konan.target.Architecture
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
@@ -39,7 +36,12 @@ internal val contextLLVMSetupPhase = makeKonanModuleOpPhase(
|
|||||||
// (see Llvm class in ContextUtils)
|
// (see Llvm class in ContextUtils)
|
||||||
// Which in turn is determined by the clang flags
|
// Which in turn is determined by the clang flags
|
||||||
// used to compile runtime.bc.
|
// used to compile runtime.bc.
|
||||||
|
// TODO
|
||||||
llvmContext = LLVMContextCreate()!!
|
llvmContext = LLVMContextCreate()!!
|
||||||
|
context.llvmDisposed = false
|
||||||
|
|
||||||
|
context.runtime = Runtime(context.config.distribution.compilerInterface(context.config.target))
|
||||||
|
|
||||||
val llvmModule = LLVMModuleCreateWithNameInContext("out", llvmContext)!!
|
val llvmModule = LLVMModuleCreateWithNameInContext("out", llvmContext)!!
|
||||||
context.llvmModule = llvmModule
|
context.llvmModule = llvmModule
|
||||||
context.debugInfo.builder = LLVMCreateDIBuilder(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(
|
internal val disposeLLVMPhase = namedUnitPhase(
|
||||||
name = "DisposeLLVM",
|
name = "DisposeLLVM",
|
||||||
description = "Dispose LLVM",
|
description = "Dispose LLVM",
|
||||||
lower = object : CompilerPhase<Context, Unit, Unit> {
|
lower = object : CompilerPhase<Context, Unit, Unit> {
|
||||||
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
|
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
|
||||||
context.disposeLlvm()
|
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
|
private val target = context.config.target
|
||||||
|
|
||||||
val runtimeFile = context.config.distribution.compilerInterface(target)
|
override val runtime get() = context.runtime
|
||||||
override val runtime = Runtime(runtimeFile) // TODO: dispose
|
|
||||||
|
|
||||||
val targetTriple = runtime.target
|
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 == null -> context.config.moduleId.moduleConstructorName
|
||||||
library == context.config.libraryToCache?.klib
|
library == context.config.libraryToCache?.klib
|
||||||
&& context.config.producePerFileCache ->
|
&& context.config.producePerFileCache ->
|
||||||
fileCtorName(library.uniqueName, context.config.outputFiles.perFileCacheFileName!!)
|
fileCtorName(library.uniqueName, context.config.outputFiles.perFileCacheFileName)
|
||||||
else -> library.moduleConstructorName
|
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.ClassLayoutBuilder
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
|
import org.jetbrains.kotlin.backend.konan.descriptors.isTypedIntrinsic
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
|||||||
+35
-21
@@ -22,8 +22,19 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
|
|
||||||
internal class InlineFunctionsSupport(mapping: NativeMapping) {
|
internal class InlineFunctionsSupport(mapping: NativeMapping) {
|
||||||
private val notLoweredInlineFunctions = mapping.notLoweredInlineFunctions
|
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 }
|
context.mapping.loweredInlineFunctions[function]?.let { return it.irFunction }
|
||||||
|
|
||||||
val packageFragment = function.getPackageFragment()
|
val packageFragment = function.getPackageFragment()
|
||||||
val notLoweredFunction = if (packageFragment !is IrExternalPackageFragment) {
|
val (possiblyLoweredFunction, shouldLower) = if (packageFragment !is IrExternalPackageFragment) {
|
||||||
context.inlineFunctionsSupport.getNonLoweredInlineFunction(function).also {
|
context.inlineFunctionsSupport.getNonLoweredInlineFunction(function, copy = context.config.produceBatchedPerFileCache).also {
|
||||||
context.mapping.loweredInlineFunctions[function] =
|
context.mapping.loweredInlineFunctions[function] =
|
||||||
InlineFunctionOriginInfo(it, packageFragment as IrFile, function.startOffset, function.endOffset)
|
InlineFunctionOriginInfo(it, packageFragment as IrFile, function.startOffset, function.endOffset)
|
||||||
}
|
} to true
|
||||||
} else {
|
} else {
|
||||||
// The function is from Lazy IR, get its body from the IR linker.
|
// The function is from Lazy IR, get its body from the IR linker.
|
||||||
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
||||||
@@ -48,35 +59,38 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
|
|||||||
require(context.config.cachedLibraries.isLibraryCached(moduleDeserializer.klib)) {
|
require(context.config.cachedLibraries.isLibraryCached(moduleDeserializer.klib)) {
|
||||||
"No IR and no cache for ${function.render()}"
|
"No IR and no cache for ${function.render()}"
|
||||||
}
|
}
|
||||||
context.mapping.loweredInlineFunctions[function] = moduleDeserializer.deserializeInlineFunction(function)
|
val (shouldLower, deserializedInlineFunction) = moduleDeserializer.deserializeInlineFunction(function)
|
||||||
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)
|
ArrayConstructorLowering(context).lower(body, possiblyLoweredFunction)
|
||||||
NullableFieldsDeclarationLowering(context).lowerWithLocalDeclarations(notLoweredFunction)
|
|
||||||
LateinitUsageLowering(context).lower(body, notLoweredFunction)
|
|
||||||
|
|
||||||
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.
|
// Do not extract local classes off of inline functions from cached libraries.
|
||||||
LocalClassesInInlineFunctionsLowering(context).lower(body, notLoweredFunction)
|
LocalClassesInInlineFunctionsLowering(context).lower(body, possiblyLoweredFunction)
|
||||||
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, notLoweredFunction)
|
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) {
|
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(
|
internal class KonanIrLinker(
|
||||||
private val currentModule: ModuleDescriptor,
|
private val currentModule: ModuleDescriptor,
|
||||||
override val translationPluginContext: TranslationPluginContext?,
|
override val translationPluginContext: TranslationPluginContext?,
|
||||||
@@ -387,14 +389,18 @@ internal class KonanIrLinker(
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getExternalDeclarationFileName(declaration: IrDeclaration) = with(declaration) {
|
fun getExternalDeclarationFileName(declaration: IrDeclaration) = when (val packageFragment = declaration.getPackageFragment()) {
|
||||||
val externalPackageFragment = getPackageFragment() as? IrExternalPackageFragment
|
is IrFile -> packageFragment.path
|
||||||
?: error("Expected an external package fragment for ${render()}")
|
|
||||||
val moduleDescriptor = externalPackageFragment.packageFragmentDescriptor.containingDeclaration
|
is IrExternalPackageFragment -> {
|
||||||
val moduleDeserializer = moduleDeserializers[moduleDescriptor]
|
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
||||||
?: error("No module deserializer for $moduleDescriptor")
|
val moduleDeserializer = moduleDeserializers[moduleDescriptor] ?: error("No module deserializer for $moduleDescriptor")
|
||||||
val idSig = moduleDeserializer.descriptorSignatures[descriptor] ?: error("No signature for $descriptor")
|
val descriptor = declaration.descriptor
|
||||||
idSig.topLevelSignature().fileSignature()?.fileName ?: error("No file for $idSig")
|
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
|
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
|
val packageFragment = function.getPackageFragment() as? IrExternalPackageFragment
|
||||||
?: error("Expected an external package fragment for ${function.render()}")
|
?: error("Expected an external package fragment for ${function.render()}")
|
||||||
if (function.parents.any { (it as? IrFunction)?.isInline == true }) {
|
if (function.parents.any { (it as? IrFunction)?.isInline == true }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user