[K/N] Moved llvmModuleSpecification from context to generation state

This commit is contained in:
Igor Chevdar
2022-10-14 22:14:31 +03:00
committed by Space Team
parent 945e0d9b3f
commit f8b8cbb9f2
18 changed files with 89 additions and 85 deletions
@@ -173,7 +173,7 @@ internal fun initializeCachedBoxes(context: Context) {
val rangeStart = "${cache.name}_RANGE_FROM"
val rangeEnd = "${cache.name}_RANGE_TO"
initCache(cache, context, cacheName, rangeStart, rangeEnd,
declareOnly = !context.shouldDefineCachedBoxes
declareOnly = !context.generationState.shouldDefineCachedBoxes
).also { context.generationState.llvm.boxCacheGlobals[cache] = it }
}
}
@@ -52,7 +52,7 @@ sealed class CacheDeserializationStrategy {
}
}
class PartialCacheInfo(val klib: KotlinLibrary, var strategy: CacheDeserializationStrategy)
class PartialCacheInfo(val klib: KotlinLibrary, val strategy: CacheDeserializationStrategy)
class CacheSupport(
private val configuration: CompilerConfiguration,
@@ -72,11 +72,11 @@ class CacheSupport(
?: configuration.reportCompilationError("cache directory $it is not found or not a directory")
}
internal fun tryGetImplicitOutput(): String? {
internal fun tryGetImplicitOutput(cacheDeserializationStrategy: CacheDeserializationStrategy?): String? {
val libraryToCache = libraryToCache ?: return null
// Put the resulting library in the first cache directory.
val cacheDirectory = implicitCacheDirectories.firstOrNull() ?: return null
val singleFileStrategy = libraryToCache.strategy as? CacheDeserializationStrategy.SingleFile
val singleFileStrategy = cacheDeserializationStrategy as? CacheDeserializationStrategy.SingleFile
val baseLibraryCacheDirectory = cacheDirectory.child(
if (singleFileStrategy == null)
CachedLibraries.getCachedLibraryName(libraryToCache.klib)
@@ -43,20 +43,19 @@ val CompilerOutputKind.isNativeLibrary: Boolean
val CompilerOutputKind.involvesBitcodeGeneration: Boolean
get() = this != CompilerOutputKind.LIBRARY
internal val Context.producedLlvmModuleContainsStdlib: Boolean
get() = this.llvmModuleSpecification.containsModule(this.stdlibModule)
internal val CacheDeserializationStrategy?.containsKFunctionImpl: Boolean
get() = this?.contains(KonanFqNames.internalPackageName, "KFunctionImpl.kt") != false
internal val Context.shouldDefineFunctionClasses: Boolean
get() = producedLlvmModuleContainsStdlib &&
config.libraryToCache?.strategy?.contains(KonanFqNames.internalPackageName, "KFunctionImpl.kt") != false
internal val NativeGenerationState.shouldDefineFunctionClasses: Boolean
get() = producedLlvmModuleContainsStdlib && cacheDeserializationStrategy.containsKFunctionImpl
internal val Context.shouldDefineCachedBoxes: Boolean
internal val NativeGenerationState.shouldDefineCachedBoxes: Boolean
get() = producedLlvmModuleContainsStdlib &&
config.libraryToCache?.strategy?.contains(KonanFqNames.internalPackageName, "Boxing.kt") != false
cacheDeserializationStrategy?.contains(KonanFqNames.internalPackageName, "Boxing.kt") != false
internal val Context.shouldLinkRuntimeNativeLibraries: Boolean
internal val NativeGenerationState.shouldLinkRuntimeNativeLibraries: Boolean
get() = producedLlvmModuleContainsStdlib &&
config.libraryToCache?.strategy?.contains(KonanFqNames.packageName, "Runtime.kt") != false
cacheDeserializationStrategy?.contains(KonanFqNames.packageName, "Runtime.kt") != false
val KonanConfig.involvesLinkStage: Boolean
get() = when (this.produce) {
@@ -116,7 +115,7 @@ private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<Str
val config = context.config
val (bitcodePartOfStdlib, bitcodeLibraries) = context.generationState.llvm.bitcodeToLink
.partition { it.isStdlib && context.producedLlvmModuleContainsStdlib }
.partition { it.isStdlib && context.generationState.producedLlvmModuleContainsStdlib }
.toList()
.map { libraries ->
libraries.flatMap { it.bitcodePaths }.filter { it.isBitcode }
@@ -146,7 +145,7 @@ private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<Str
val runtimeModules = parseBitcodeFiles(
(runtimeNativeLibraries + bitcodePartOfStdlib)
.takeIf { context.shouldLinkRuntimeNativeLibraries }.orEmpty()
.takeIf { context.generationState.shouldLinkRuntimeNativeLibraries }.orEmpty()
)
val additionalModules = parseBitcodeFiles(additionalBitcodeFiles)
return LlvmModules(
@@ -231,14 +231,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config), Confi
lateinit var compilerOutput: List<ObjectFile>
val llvmModuleSpecification: LlvmModuleSpecification by lazy {
when {
config.produce.isCache ->
CacheLlvmModuleSpecification(this, config.cachedLibraries, config.libraryToCache!!)
else -> DefaultLlvmModuleSpecification(config.cachedLibraries)
}
}
val declaredLocalArrays: MutableMap<String, LLVMTypeRef> = HashMap()
lateinit var irLinker: KonanIrLinker
@@ -25,11 +25,11 @@ internal object DECLARATION_ORIGIN_ENTRY_POINT : IrDeclarationOriginImpl("ENTRY_
internal fun makeEntryPoint(context: Context): IrFunction {
val actualMain = context.ir.symbols.entryPoint!!.owner
// TODO: Do we need to do something with the offsets if <main> is in a cached library?
val startOffset = if (context.llvmModuleSpecification.containsDeclaration(actualMain))
val startOffset = if (context.generationState.llvmModuleSpecification.containsDeclaration(actualMain))
actualMain.startOffset
else
SYNTHETIC_OFFSET
val endOffset = if (context.llvmModuleSpecification.containsDeclaration(actualMain))
val endOffset = if (context.generationState.llvmModuleSpecification.containsDeclaration(actualMain))
actualMain.endOffset
else
SYNTHETIC_OFFSET
@@ -236,7 +236,7 @@ private fun determineCachesToLink(context: Context): CachesToLink {
val dynamicCaches = mutableListOf<String>()
context.generationState.llvm.allCachedBitcodeDependencies.forEach { library ->
val currentBinaryContainsLibrary = context.llvmModuleSpecification.containsLibrary(library)
val currentBinaryContainsLibrary = context.generationState.llvmModuleSpecification.containsLibrary(library)
val cache = context.config.cachedLibraries.getLibraryCache(library)
?: error("Library $library is expected to be cached")
@@ -52,10 +52,10 @@ internal class CacheLlvmModuleSpecification(
override fun containsLibrary(library: KotlinLibrary): Boolean = library == libraryToCache.klib
override fun containsDeclaration(declaration: IrDeclaration): Boolean {
if (context.shouldDefineFunctionClasses && declaration.getPackageFragment().isFunctionInterfaceFile)
if (context.generationState.shouldDefineFunctionClasses && declaration.getPackageFragment().isFunctionInterfaceFile)
return true
if (!super.containsDeclaration(declaration)) return false
return (libraryToCache.strategy as? CacheDeserializationStrategy.SingleFile)
return (context.generationState.cacheDeserializationStrategy as? CacheDeserializationStrategy.SingleFile)
?.filePath.let { it == null || it == declaration.fileOrNull?.path }
}
}
@@ -40,14 +40,14 @@ internal class FileLowerState {
"$prefix${cStubCount++}"
}
internal class NativeGenerationState(private val context: Context) {
internal class NativeGenerationState(private val context: Context, val cacheDeserializationStrategy: CacheDeserializationStrategy?) {
private val config = context.config
private val outputPath = config.cacheSupport.tryGetImplicitOutput() ?: config.outputPath
private val outputPath = config.cacheSupport.tryGetImplicitOutput(cacheDeserializationStrategy) ?: config.outputPath
val outputFiles = OutputFiles(outputPath, config.target, config.produce)
val tempFiles = run {
val pathToTempDir = config.configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR)?.let {
val singleFileStrategy = config.cacheSupport.libraryToCache?.strategy as? CacheDeserializationStrategy.SingleFile
val singleFileStrategy = cacheDeserializationStrategy as? CacheDeserializationStrategy.SingleFile
if (singleFileStrategy == null)
it
else File(it, CacheSupport.cacheFileId(singleFileStrategy.fqName, singleFileStrategy.filePath)).path
@@ -73,6 +73,15 @@ internal class NativeGenerationState(private val context: Context) {
lateinit var fileLowerState: FileLowerState
val llvmModuleSpecification by lazy {
if (config.produce.isCache)
CacheLlvmModuleSpecification(context, config.cachedLibraries,
PartialCacheInfo(config.libraryToCache!!.klib, cacheDeserializationStrategy!!))
else DefaultLlvmModuleSpecification(config.cachedLibraries)
}
val producedLlvmModuleContainsStdlib get() = llvmModuleSpecification.containsModule(context.stdlibModule)
private val runtimeDelegate = lazy { Runtime(llvmContext, config.distribution.compilerInterface(config.target)) }
private val llvmDelegate = lazy { Llvm(context, LLVMModuleCreateWithNameInContext("out", llvmContext)!!) }
private val debugInfoDelegate = lazy { DebugInfo(context) }
@@ -142,7 +142,7 @@ internal fun createLTOFinalPipelineConfig(context: Context): LlvmPipelineConfig
val globalDce = true
// Since we are in a "closed world" internalization can be safely used
// to reduce size of a bitcode with global dce.
val internalize = context.llvmModuleSpecification.isFinal
val internalize = context.generationState.llvmModuleSpecification.isFinal
// Hidden visibility makes symbols internal when linking the binary.
// When producing dynamic library, this enables stripping unused symbols from binary with -dead_strip flag,
// similar to DCE enabled by internalize but later:
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.KlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
@@ -64,10 +63,15 @@ internal fun Context.psiToIr(
val forwardDeclarationsModuleDescriptor = moduleDescriptor.allDependencyModules.firstOrNull { it.isForwardDeclarationModule }
val modulesWithoutDCE = moduleDescriptor.allDependencyModules
.filter { !llvmModuleSpecification.isFinal && llvmModuleSpecification.containsModule(it) }
val libraryToCacheModule = config.libraryToCache?.klib?.let {
moduleDescriptor.allDependencyModules.single { module -> module.konanLibrary == it }
}
// Note: using [llvmModuleSpecification] since this phase produces IR for generating single LLVM module.
val stdlibIsCached = stdlibModule.konanLibrary?.let { config.cachedLibraries.isLibraryCached(it) } == true
val stdlibIsBeingCached = libraryToCacheModule == stdlibModule
require(!(stdlibIsCached && stdlibIsBeingCached)) { "The cache for stdlib is already built" }
val kFunctionImplIsBeingCached = stdlibIsBeingCached && config.libraryToCache?.strategy.containsKFunctionImpl
val shouldUseLazyFunctionClasses = (stdlibIsCached || stdlibIsBeingCached) && !kFunctionImplIsBeingCached
val stubGenerator = DeclarationStubGeneratorImpl(
moduleDescriptor, symbolTable,
@@ -77,10 +81,10 @@ internal fun Context.psiToIr(
)
val irBuiltInsOverDescriptors = generatorContext.irBuiltIns as IrBuiltInsOverDescriptors
val functionIrClassFactory: KonanIrAbstractDescriptorBasedFunctionFactory =
if (shouldDefineFunctionClasses || !config.lazyIrForCaches)
BuiltInFictitiousFunctionIrClassFactory(symbolTable, irBuiltInsOverDescriptors, reflectionTypes)
else
if (shouldUseLazyFunctionClasses && config.lazyIrForCaches)
LazyIrFunctionFactory(symbolTable, stubGenerator, irBuiltInsOverDescriptors, reflectionTypes)
else
BuiltInFictitiousFunctionIrClassFactory(symbolTable, irBuiltInsOverDescriptors, reflectionTypes)
irBuiltInsOverDescriptors.functionFactory = functionIrClassFactory
val descriptorsLookup = DescriptorsLookup(this.builtIns)
val symbols = KonanSymbols(this, descriptorsLookup, generatorContext.irBuiltIns, symbolTable, symbolTable.lazyWrapper)
@@ -98,7 +102,7 @@ internal fun Context.psiToIr(
}
}
} else {
val exportedDependencies = (getExportedDependencies() + modulesWithoutDCE).distinct()
val exportedDependencies = (getExportedDependencies() + libraryToCacheModule?.let { listOf(it) }.orEmpty()).distinct()
val irProviderForCEnumsAndCStructs =
IrProviderForCEnumAndCStructStubs(generatorContext, interopBuiltIns, symbols)
@@ -171,9 +175,8 @@ internal fun Context.psiToIr(
// We need to run `buildAllEnumsAndStructsFrom` before `generateModuleFragment` because it adds references to symbolTable
// that should be bound.
modulesWithoutDCE
.filter(ModuleDescriptor::isFromInteropLibrary)
.forEach(irProviderForCEnumsAndCStructs::referenceAllEnumsAndStructsFrom)
if (libraryToCacheModule?.isFromInteropLibrary() == true)
irProviderForCEnumsAndCStructs.referenceAllEnumsAndStructsFrom(libraryToCacheModule)
translator.addPostprocessingStep {
irProviderForCEnumsAndCStructs.generateBodies()
@@ -228,8 +231,7 @@ internal fun Context.psiToIr(
irModule = mainModule
// Note: coupled with [shouldLower] below.
irModules = modules.filterValues { llvmModuleSpecification.containsModule(it) }
irModules = modules
// IR linker deserializes files in the order they lie on the disk, which might be inconvenient,
// so to make the pipeline more deterministic, the files are to be sorted.
// This concerns in the first place global initializers order for the eager initialization strategy,
@@ -243,11 +245,11 @@ internal fun Context.psiToIr(
if (!isProducingLibrary) {
// TODO: find out what should be done in the new builtins/symbols about it
if (this.stdlibModule in modulesWithoutDCE) {
if (stdlibIsBeingCached) {
(functionIrClassFactory as? BuiltInFictitiousFunctionIrClassFactory)?.buildAllClasses()
}
(functionIrClassFactory as? BuiltInFictitiousFunctionIrClassFactory)?.module =
(modules.values + irModule!!).single { it.descriptor.isNativeStdlib() }
(modules.values + irModule!!).single { it.descriptor == this.stdlibModule }
}
mainModule.files.forEach { it.metadata = KonanFileMetadataSource(mainModule) }
@@ -129,13 +129,13 @@ internal val psiToIrPhase = konanUnitPhase(
internal val buildAdditionalCacheInfoPhase = konanUnitPhase(
op = {
irModules.values.single().let { module ->
val moduleDeserializer = irLinker.moduleDeserializers[module.descriptor]
if (moduleDeserializer == null) {
require(module.descriptor.isFromInteropLibrary()) { "No module deserializer for ${module.descriptor}" }
} else {
CacheInfoBuilder(this, moduleDeserializer).build()
}
val module = irModules[config.libraryToCache!!.klib.libraryName]
?: error("No module for the library being cached: ${config.libraryToCache!!.klib.libraryName}")
val moduleDeserializer = irLinker.moduleDeserializers[module.descriptor]
if (moduleDeserializer == null) {
require(module.descriptor.isFromInteropLibrary()) { "No module deserializer for ${module.descriptor}" }
} else {
CacheInfoBuilder(this, moduleDeserializer).build()
}
},
name = "BuildAdditionalCacheInfo",
@@ -319,7 +319,8 @@ internal val dependenciesLowerPhase = SameTypeNamedCompilerPhase(
.reversed()
.forEach {
val libModule = context.irModules[it.libraryName]
?: return@forEach
if (libModule == null || !context.generationState.llvmModuleSpecification.containsModule(libModule))
return@forEach
input.files += libModule.files
allLoweringsPhase.invoke(phaseConfig, phaserState, context, input)
@@ -332,7 +333,9 @@ internal val dependenciesLowerPhase = SameTypeNamedCompilerPhase(
context.librariesWithDependencies
.forEach {
val libModule = context.irModules[it.libraryName]
?: return@forEach
if (libModule == null || !context.generationState.llvmModuleSpecification.containsModule(libModule))
return@forEach
input.files += libModule.files
}
@@ -348,7 +351,8 @@ internal val umbrellaCompilation = SameTypeNamedCompilerPhase(
prerequisite = emptySet(),
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
val module = context.irModules.values.single()
val module = context.irModules[context.config.libraryToCache!!.klib.libraryName]
?: error("No module for the library being cached: ${context.config.libraryToCache!!.klib.libraryName}")
val files = module.files.toList()
module.files.clear()
@@ -357,12 +361,10 @@ internal val umbrellaCompilation = SameTypeNamedCompilerPhase(
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.generationState = NativeGenerationState(context, CacheDeserializationStrategy.SingleFile(file.path, file.fqName.asString()))
module.files += file
if (context.shouldDefineFunctionClasses)
if (context.generationState.shouldDefineFunctionClasses)
module.files += functionInterfaceFiles
entireBackend.invoke(phaseConfig, phaserState, context, Unit)
@@ -383,7 +385,7 @@ internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
require(context.config.produce == CompilerOutputKind.PROGRAM)
val entryPoint = context.ir.symbols.entryPoint!!.owner
val file = if (context.llvmModuleSpecification.containsDeclaration(entryPoint)) {
val file = if (context.generationState.llvmModuleSpecification.containsDeclaration(entryPoint)) {
entryPoint.file
} else {
// `main` function is compiled to other LLVM module.
@@ -447,7 +449,7 @@ internal val createGenerationStatePhase = namedUnitPhase(
description = "Create generation state",
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
context.generationState = NativeGenerationState(context)
context.generationState = NativeGenerationState(context, context.config.libraryToCache?.strategy)
}
}
)
@@ -475,8 +477,7 @@ private val phasesOverMainModule = SameTypeNamedCompilerPhase(
private val entireBackend = SameTypeNamedCompilerPhase(
name = "EntireBackend",
description = "Entire backend",
lower = createGenerationStatePhase then
buildAdditionalCacheInfoPhase then
lower = buildAdditionalCacheInfoPhase then
phasesOverMainModule then
saveAdditionalCacheInfoPhase then
produceOutputPhase then
@@ -503,7 +504,8 @@ private val middleEnd = SameTypeNamedCompilerPhase(
private val singleCompilation = SameTypeNamedCompilerPhase(
name = "SingleCompilation",
description = "Single compilation",
lower = entireBackend
lower = createGenerationStatePhase then
entireBackend
)
internal val toplevelPhase: CompilerPhase<Context, Unit, Unit> = namedUnitPhase(
@@ -163,7 +163,7 @@ internal interface ContextUtils : RuntimeAware {
* or just drop all [else] branches of corresponding conditionals.
*/
fun isExternal(declaration: IrDeclaration): Boolean {
return !context.llvmModuleSpecification.containsDeclaration(declaration)
return !context.generationState.llvmModuleSpecification.containsDeclaration(declaration)
}
/**
@@ -450,11 +450,11 @@ internal class Llvm(private val context: Context, val module: LLVMModuleRef) : R
}
private fun shouldContainBitcode(library: KonanLibrary): Boolean {
if (!context.llvmModuleSpecification.containsLibrary(library)) {
if (!context.generationState.llvmModuleSpecification.containsLibrary(library)) {
return false
}
if (!context.llvmModuleSpecification.isFinal) {
if (!context.generationState.llvmModuleSpecification.isFinal) {
return true
}
@@ -2670,7 +2670,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Globals set this way cannot be const, but are overridable when producing final executable.
private fun overrideRuntimeGlobal(name: String, value: ConstValue) {
// TODO: A similar mechanism is used in `ObjCExportCodeGenerator`. Consider merging them.
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
// When some dynamic caches are used, we consider that stdlib is in the dynamic cache as well.
// Runtime is linked into stdlib module only, so import runtime global from it.
val global = codegen.importGlobal(name, value.llvmType, context.standardLlvmSymbolsOrigin)
@@ -2687,7 +2687,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Define a strong runtime global. It'll overrule a weak global defined in a statically linked runtime.
val global = llvm.staticData.placeGlobal(name, value, true)
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
}
@@ -2789,7 +2789,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
else -> library.moduleConstructorName
}
if (library == null || context.llvmModuleSpecification.containsLibrary(library)) {
if (library == null || context.generationState.llvmModuleSpecification.containsLibrary(library)) {
val otherInitializers = llvm.otherStaticInitializers.takeIf { library == null }.orEmpty()
val ctorFunction = addCtorFunction(ctorName)
@@ -168,7 +168,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
if (!context.config.producePerFileCache)
"${MangleConstant.CLASS_PREFIX}:$internalName"
else {
val containerName = (context.config.libraryToCache!!.strategy as CacheDeserializationStrategy.SingleFile).filePath
val containerName = (context.generationState.cacheDeserializationStrategy as CacheDeserializationStrategy.SingleFile).filePath
declaration.computePrivateTypeInfoSymbolName(containerName)
}
}
@@ -341,7 +341,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
"${MangleConstant.FUN_PREFIX}:${qualifyInternalName(declaration)}"
else {
val containerName = declaration.parentClassOrNull?.fqNameForIrSerialization?.asString()
?: (context.config.libraryToCache!!.strategy as CacheDeserializationStrategy.SingleFile).filePath
?: (context.generationState.cacheDeserializationStrategy as CacheDeserializationStrategy.SingleFile).filePath
declaration.computePrivateSymbolName(containerName)
}
}
@@ -287,7 +287,7 @@ internal class ObjCExportBlockCodeGenerator(codegen: CodeGenerator) : ObjCExport
// 1. Enumerates [BuiltInFictitiousFunctionIrClassFactory] built classes, which may be incomplete otherwise.
// 2. Modifies stdlib global initializers.
// 3. Defines runtime-declared globals.
require(context.shouldDefineFunctionClasses)
require(context.generationState.shouldDefineFunctionClasses)
}
fun generate() {
@@ -499,7 +499,7 @@ internal class ObjCExportCodeGenerator(
descriptorToAdapter[adapter.objCName] = typeAdapter
if (irClass != null) {
if (!context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (!context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
setObjCExportTypeInfo(irClass, typeAdapter = typeAdapter)
} else {
// Optimization: avoid generating huge initializers;
@@ -527,7 +527,7 @@ internal class ObjCExportCodeGenerator(
emitSortedAdapters(placedClassAdapters, "Kotlin_ObjCExport_sortedClassAdapters")
emitSortedAdapters(placedInterfaceAdapters, "Kotlin_ObjCExport_sortedProtocolAdapters")
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
replaceExternalWeakOrCommonGlobal(
"Kotlin_ObjCExport_initTypeAdapters",
llvm.constInt1(true),
@@ -555,7 +555,7 @@ internal class ObjCExportCodeGenerator(
if (determineLinkerOutput(context) == LinkerOutputKind.STATIC_LIBRARY) {
// Might be affected by https://youtrack.jetbrains.com/issue/KT-42254.
// The code below generally follows [replaceExternalWeakOrCommonGlobal] implementation.
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
// So the compiler uses caches. If a user is linking two such static frameworks into a single binary,
// the linker might fail with a lot of "duplicate symbol" errors due to KT-42254.
// Adding a similar symbol that would explicitly hint to take a look at the YouTrack issue if reported.
@@ -701,14 +701,14 @@ private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(
origin: CompiledKlibModuleOrigin
) {
// TODO: A similar mechanism is used in `IrToBitcode.overrideRuntimeGlobal`. Consider merging them.
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
val global = codegen.importGlobal(name, value.llvmType, origin)
externalGlobalInitializers[global] = value
} else {
context.generationState.llvmImports.add(origin)
val global = staticData.placeGlobal(name, value, isExported = true)
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
// Note: actually this is required only if global's weak/common definition is in another object file,
// but it is simpler to do this for all globals, considering that all usages can't be removed by DCE anyway.
llvm.usedGlobals += global.llvmGlobal
@@ -872,7 +872,7 @@ private val ObjCExportBlockCodeGenerator.mappedFunctionNClasses get() =
.filter { it.descriptor.isMappedFunctionClass() }
private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
require(context.shouldDefineFunctionClasses)
require(context.generationState.shouldDefineFunctionClasses)
mappedFunctionNClasses.forEach { functionClass ->
val convertToRetained = kotlinFunctionToRetainedBlockConverter(BlockPointerBridge(functionClass.arity, returnsVoid = false))
@@ -882,7 +882,7 @@ private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
}
private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
require(context.shouldDefineFunctionClasses)
require(context.generationState.shouldDefineFunctionClasses)
val functionClassesByArity = mappedFunctionNClasses.associateBy { it.arity }
val arityLimit = (functionClassesByArity.keys.maxOrNull() ?: -1) + 1
@@ -162,7 +162,7 @@ internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPa
val property = field.correspondingPropertySymbol?.owner
return when {
context.llvmModuleSpecification.containsDeclaration(field) -> expression
context.generationState.llvmModuleSpecification.containsDeclaration(field) -> expression
irClass?.isInner == true && context.innerClassesSupport.getOuterThisField(irClass) == field -> {
val accessor = cachesAbiSupport.getOuterThisAccessor(irClass)
@@ -80,7 +80,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
LocalClassesInInlineLambdasLowering(context).lower(body, possiblyLoweredFunction)
if (context.llvmModuleSpecification.containsDeclaration(function)) {
if (context.generationState.llvmModuleSpecification.containsDeclaration(function)) {
// Do not extract local classes off of inline functions from cached libraries.
LocalClassesInInlineFunctionsLowering(context).lower(body, possiblyLoweredFunction)
LocalClassesExtractionFromInlineFunctionsLowering(context).lower(body, possiblyLoweredFunction)
@@ -68,7 +68,7 @@ internal class ObjCExport(
internal fun generate(codegen: CodeGenerator) {
if (!target.family.isAppleFamily) return
if (context.shouldDefineFunctionClasses) {
if (context.generationState.shouldDefineFunctionClasses) {
ObjCExportBlockCodeGenerator(codegen).generate()
}