[K/N][codegen] Use generationState instead of context wherever possible

This commit is contained in:
Igor Chevdar
2022-10-19 20:41:05 +03:00
committed by Space Team
parent 87abb7ea3e
commit 6a3229b9ed
42 changed files with 470 additions and 410 deletions
@@ -12,8 +12,9 @@ typealias BitcodeFile = String
typealias ObjectFile = String
typealias ExecutableFile = String
internal class BitcodeCompiler(val context: Context) {
internal class BitcodeCompiler(val generationState: NativeGenerationState) {
private val context = generationState.context
private val platform = context.config.platform
private val optimize = context.shouldOptimize()
private val debug = context.config.debug
@@ -31,7 +32,7 @@ internal class BitcodeCompiler(val context: Context) {
.execute()
private fun temporary(name: String, suffix: String): String =
context.generationState.tempFiles.create(name, suffix).absolutePath
generationState.tempFiles.create(name, suffix).absolutePath
private fun targetTool(tool: String, vararg arg: String) {
val absoluteToolName = if (platform.configurables is AppleConfigurables) {
@@ -167,26 +167,27 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
* Initialize static boxing.
* If output target is native binary then the cache is created.
*/
internal fun initializeCachedBoxes(context: Context) {
internal fun initializeCachedBoxes(generationState: NativeGenerationState) {
BoxCache.values().forEach { cache ->
val cacheName = "${cache.name}_CACHE"
val rangeStart = "${cache.name}_RANGE_FROM"
val rangeEnd = "${cache.name}_RANGE_TO"
initCache(cache, context, cacheName, rangeStart, rangeEnd,
declareOnly = !context.generationState.shouldDefineCachedBoxes
).also { context.generationState.llvm.boxCacheGlobals[cache] = it }
initCache(cache, generationState, cacheName, rangeStart, rangeEnd,
declareOnly = !generationState.shouldDefineCachedBoxes
).also { generationState.llvm.boxCacheGlobals[cache] = it }
}
}
/**
* Adds global that refers to the cache.
*/
private fun initCache(cache: BoxCache, context: Context, cacheName: String,
private fun initCache(cache: BoxCache, generationState: NativeGenerationState, cacheName: String,
rangeStartName: String, rangeEndName: String, declareOnly: Boolean) : StaticData.Global {
val context = generationState.context
val kotlinType = context.irBuiltIns.getKotlinClass(cache)
val staticData = context.generationState.llvm.staticData
val llvm = context.generationState.llvm
val staticData = generationState.llvm.staticData
val llvm = generationState.llvm
val llvmType = kotlinType.defaultType.toLLVMType(llvm)
val llvmBoxType = llvm.structType(llvm.runtime.objHeaderType, llvmType)
val (start, end) = context.config.target.getBoxCacheRange(cache)
@@ -207,14 +208,15 @@ private fun initCache(cache: BoxCache, context: Context, cacheName: String,
}
}
internal fun IrConstantPrimitive.toBoxCacheValue(context: Context): ConstValue? {
internal fun IrConstantPrimitive.toBoxCacheValue(generationState: NativeGenerationState): ConstValue? {
val irBuiltIns = generationState.context.irBuiltIns
val cacheType = when (value.type) {
context.irBuiltIns.booleanType -> BoxCache.BOOLEAN
context.irBuiltIns.byteType -> BoxCache.BYTE
context.irBuiltIns.shortType -> BoxCache.SHORT
context.irBuiltIns.charType -> BoxCache.CHAR
context.irBuiltIns.intType -> BoxCache.INT
context.irBuiltIns.longType -> BoxCache.LONG
irBuiltIns.booleanType -> BoxCache.BOOLEAN
irBuiltIns.byteType -> BoxCache.BYTE
irBuiltIns.shortType -> BoxCache.SHORT
irBuiltIns.charType -> BoxCache.CHAR
irBuiltIns.intType -> BoxCache.INT
irBuiltIns.longType -> BoxCache.LONG
else -> return null
}
val value = when (value.kind) {
@@ -226,9 +228,9 @@ internal fun IrConstantPrimitive.toBoxCacheValue(context: Context): ConstValue?
IrConstKind.Long -> value.value as Long
else -> throw IllegalArgumentException("IrConst of kind ${value.kind} can't be converted to box cache")
}
val (start, end) = context.config.target.getBoxCacheRange(cacheType)
val (start, end) = generationState.context.config.target.getBoxCacheRange(cacheType)
return if (value in start..end) {
context.generationState.llvm.let { llvm ->
generationState.llvm.let { llvm ->
llvm.boxCacheGlobals[cacheType]?.pointer?.getElementPtr(llvm, value.toInt() - start)?.getElementPtr(llvm, 0)
}
} else {
@@ -719,7 +719,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
fun generateBindings(codegen: CodeGenerator) = BindingsBuilder(codegen).build()
inner class BindingsBuilder(val codegen: CodeGenerator) : ContextUtils {
override val context = this@CAdapterGenerator.context
override val generationState = codegen.generationState
internal val prefix = context.config.fullExportedNamePrefix.replace("-|\\.".toRegex(), "_")
private lateinit var outputStreamWriter: PrintWriter
@@ -929,7 +929,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
val exportedSymbols = mutableListOf<String>()
private fun makeGlobalStruct(top: ExportedElementScope) {
val headerFile = context.generationState.outputFiles.cAdapterHeader
val headerFile = generationState.outputFiles.cAdapterHeader
outputStreamWriter = headerFile.printWriter()
val exportedSymbol = "${prefix}_symbols"
@@ -1014,7 +1014,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
outputStreamWriter.close()
println("Produced library API in ${prefix}_api.h")
outputStreamWriter = context.generationState.tempFiles
outputStreamWriter = generationState.tempFiles
.cAdapterCpp
.printWriter()
@@ -1154,7 +1154,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
outputStreamWriter.close()
if (context.config.target.family == Family.MINGW) {
outputStreamWriter = context.generationState.outputFiles
outputStreamWriter = generationState.outputFiles
.cAdapterDef
.printWriter()
output("EXPORTS")
@@ -20,8 +20,9 @@ private fun LLVMValueRef.isLLVMBuiltin(): Boolean {
}
private class CallsChecker(context: Context, goodFunctions: List<String>) {
private val llvm = context.generationState.llvm
private class CallsChecker(generationState: NativeGenerationState, goodFunctions: List<String>) {
private val llvm = generationState.llvm
private val context = generationState.context
private val goodFunctionsExact = goodFunctions.filterNot { it.endsWith("*") }.toSet()
private val goodFunctionsByPrefix = goodFunctions.filter { it.endsWith("*") }.map { it.substring(0, it.length - 1) }.sorted()
@@ -164,8 +165,8 @@ private class CallsChecker(context: Context, goodFunctions: List<String>) {
private const val functionListGlobal = "Kotlin_callsCheckerKnownFunctions"
private const val functionListSizeGlobal = "Kotlin_callsCheckerKnownFunctionsCount"
internal fun checkLlvmModuleExternalCalls(context: Context) {
val llvm = context.generationState.llvm
internal fun checkLlvmModuleExternalCalls(generationState: NativeGenerationState) {
val llvm = generationState.llvm
val staticData = llvm.staticData
@@ -177,19 +178,19 @@ internal fun checkLlvmModuleExternalCalls(context: Context) {
}.toList()
} ?: emptyList()
val checker = CallsChecker(context, goodFunctions)
val checker = CallsChecker(generationState, goodFunctions)
getFunctions(llvm.module)
.filter { !it.isExternalFunction() && it !in ignoredFunctions }
.forEach(checker::processFunction)
// otherwise optimiser can inline it
staticData.getGlobal(functionListGlobal)?.setExternallyInitialized(true);
staticData.getGlobal(functionListSizeGlobal)?.setExternallyInitialized(true);
context.verifyBitCode()
generationState.verifyBitCode()
}
// this should be a separate pass, to handle DCE correctly
internal fun addFunctionsListSymbolForChecker(context: Context) {
val llvm = context.generationState.llvm
internal fun addFunctionsListSymbolForChecker(generationState: NativeGenerationState) {
val llvm = generationState.llvm
val staticData = llvm.staticData
val functions = getFunctions(llvm.module)
@@ -203,5 +204,5 @@ internal fun addFunctionsListSymbolForChecker(context: Context) {
staticData.getGlobal(functionListSizeGlobal)
?.setInitializer(llvm.constInt32(functions.size))
?: throw IllegalStateException("$functionListSizeGlobal global not found")
context.verifyBitCode()
generationState.verifyBitCode()
}
@@ -87,13 +87,14 @@ internal fun llvmIrDumpCallback(state: ActionState, module: IrModuleFragment, co
}
}
internal fun produceCStubs(context: Context) {
context.generationState.cStubsManager.compile(
internal fun produceCStubs(generationState: NativeGenerationState) {
val context = generationState.context
generationState.cStubsManager.compile(
context.config.clang,
context.messageCollector,
context.inVerbosePhase
).forEach {
parseAndLinkBitcodeFile(context, context.generationState.llvm.module, it.absolutePath)
parseAndLinkBitcodeFile(generationState, generationState.llvm.module, it.absolutePath)
}
}
@@ -111,11 +112,11 @@ private data class LlvmModules(
* - Runtime modules. These may be used as an input for a separate LTO (e.g. for debug builds).
* - Everything else.
*/
private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<String>): LlvmModules {
val config = context.config
private fun collectLlvmModules(generationState: NativeGenerationState, generatedBitcodeFiles: List<String>): LlvmModules {
val config = generationState.context.config
val (bitcodePartOfStdlib, bitcodeLibraries) = context.generationState.llvm.bitcodeToLink
.partition { it.isStdlib && context.generationState.producedLlvmModuleContainsStdlib }
val (bitcodePartOfStdlib, bitcodeLibraries) = generationState.llvm.bitcodeToLink
.partition { it.isStdlib && generationState.producedLlvmModuleContainsStdlib }
.toList()
.map { libraries ->
libraries.flatMap { it.bitcodePaths }.filter { it.isBitcode }
@@ -123,7 +124,7 @@ private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<Str
val nativeLibraries = config.nativeLibraries + config.launcherNativeLibraries
.takeIf { config.produce == CompilerOutputKind.PROGRAM }.orEmpty()
val additionalBitcodeFilesToLink = context.generationState.llvm.additionalProducedBitcodeFiles
val additionalBitcodeFilesToLink = generationState.llvm.additionalProducedBitcodeFiles
val exceptionsSupportNativeLibrary = listOf(config.exceptionsSupportNativeLibrary)
.takeIf { config.produce == CompilerOutputKind.DYNAMIC_CACHE }.orEmpty()
val additionalBitcodeFiles = nativeLibraries +
@@ -132,12 +133,12 @@ private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<Str
bitcodeLibraries +
exceptionsSupportNativeLibrary
val runtimeNativeLibraries = context.config.runtimeNativeLibraries
val runtimeNativeLibraries = config.runtimeNativeLibraries
fun parseBitcodeFiles(files: List<String>): List<LLVMModuleRef> = files.map { bitcodeFile ->
val parsedModule = parseBitcodeFile(context.generationState.llvmContext, bitcodeFile)
if (!context.shouldUseDebugInfoFromNativeLibs()) {
val parsedModule = parseBitcodeFile(generationState.llvmContext, bitcodeFile)
if (!generationState.context.shouldUseDebugInfoFromNativeLibs()) {
LLVMStripModuleDebugInfo(parsedModule)
}
parsedModule
@@ -145,67 +146,68 @@ private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<Str
val runtimeModules = parseBitcodeFiles(
(runtimeNativeLibraries + bitcodePartOfStdlib)
.takeIf { context.generationState.shouldLinkRuntimeNativeLibraries }.orEmpty()
.takeIf { generationState.shouldLinkRuntimeNativeLibraries }.orEmpty()
)
val additionalModules = parseBitcodeFiles(additionalBitcodeFiles)
return LlvmModules(
runtimeModules.ifNotEmpty { this + context.generateRuntimeConstantsModule() } ?: emptyList(),
additionalModules + listOfNotNull(patchObjCRuntimeModule(context))
runtimeModules.ifNotEmpty { this + generationState.generateRuntimeConstantsModule() } ?: emptyList(),
additionalModules + listOfNotNull(patchObjCRuntimeModule(generationState))
)
}
private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List<String>) {
val (runtimeModules, additionalModules) = collectLlvmModules(context, generatedBitcodeFiles)
private fun linkAllDependencies(generationState: NativeGenerationState, generatedBitcodeFiles: List<String>) {
val (runtimeModules, additionalModules) = collectLlvmModules(generationState, generatedBitcodeFiles)
// TODO: Possibly slow, maybe to a separate phase?
val optimizedRuntimeModules = RuntimeLinkageStrategy.pick(context, runtimeModules).run()
val optimizedRuntimeModules = RuntimeLinkageStrategy.pick(generationState, runtimeModules).run()
(optimizedRuntimeModules + additionalModules).forEach {
val failed = llvmLinkModules2(context, context.generationState.llvm.module, it)
val failed = llvmLinkModules2(generationState, generationState.llvm.module, it)
if (failed != 0) {
error("Failed to link ${it.getName()}")
}
}
}
private fun insertAliasToEntryPoint(context: Context) {
val nomain = context.config.configuration.get(KonanConfigKeys.NOMAIN) ?: false
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
private fun insertAliasToEntryPoint(generationState: NativeGenerationState) {
val config = generationState.context.config
val nomain = config.configuration.get(KonanConfigKeys.NOMAIN) ?: false
if (config.produce != CompilerOutputKind.PROGRAM || nomain)
return
val module = context.generationState.llvm.module
val entryPointName = context.config.entryPointName
val module = generationState.llvm.module
val entryPointName = config.entryPointName
val entryPoint = LLVMGetNamedFunction(module, entryPointName)
?: error("Module doesn't contain `$entryPointName`")
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
}
internal fun linkBitcodeDependencies(context: Context) {
val config = context.config.configuration
val tempFiles = context.generationState.tempFiles
val produce = config.get(KonanConfigKeys.PRODUCE)
internal fun linkBitcodeDependencies(generationState: NativeGenerationState) {
val config = generationState.context.config
val tempFiles = generationState.tempFiles
val produce = config.produce
val generatedBitcodeFiles =
if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) {
produceCAdapterBitcode(
context.config.clang,
config.clang,
tempFiles.cAdapterCppName,
tempFiles.cAdapterBitcodeName)
listOf(tempFiles.cAdapterBitcodeName)
} else emptyList()
if (produce == CompilerOutputKind.FRAMEWORK && context.config.produceStaticFramework) {
embedAppleLinkerOptionsToBitcode(context.generationState.llvm, context.config)
if (produce == CompilerOutputKind.FRAMEWORK && config.produceStaticFramework) {
embedAppleLinkerOptionsToBitcode(generationState.llvm, config)
}
linkAllDependencies(context, generatedBitcodeFiles)
linkAllDependencies(generationState, generatedBitcodeFiles)
}
internal fun produceOutput(context: Context) {
val config = context.config.configuration
val tempFiles = context.generationState.tempFiles
val produce = context.config.produce
internal fun produceOutput(generationState: NativeGenerationState) {
val context = generationState.context
val config = context.config
val tempFiles = generationState.tempFiles
val produce = config.produce
if (produce == CompilerOutputKind.FRAMEWORK) {
context.objCExport.produceFrameworkInterface()
if (context.config.omitFrameworkBinary) {
generationState.objCExport.produceFrameworkInterface()
if (config.omitFrameworkBinary) {
// Compiler does not compile anything in this mode, so return early.
return
}
@@ -218,21 +220,21 @@ internal fun produceOutput(context: Context) {
CompilerOutputKind.STATIC_CACHE,
CompilerOutputKind.PROGRAM -> {
val output = tempFiles.nativeBinaryFileName
context.bitcodeFileName = output
generationState.bitcodeFileName = output
// Insert `_main` after pipeline so we won't worry about optimizations
// corrupting entry point.
insertAliasToEntryPoint(context)
LLVMWriteBitcodeToFile(context.generationState.llvm.module, output)
insertAliasToEntryPoint(generationState)
LLVMWriteBitcodeToFile(generationState.llvm.module, output)
}
CompilerOutputKind.LIBRARY -> {
val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
val output = context.generationState.outputFiles.klibOutputFileName(!nopack)
val libraryName = context.config.moduleId
val shortLibraryName = context.config.shortModuleName
val nopack = config.configuration.getBoolean(KonanConfigKeys.NOPACK)
val output = generationState.outputFiles.klibOutputFileName(!nopack)
val libraryName = config.moduleId
val shortLibraryName = config.shortModuleName
val neededLibraries = context.librariesWithDependencies
val abiVersion = KotlinAbiVersion.CURRENT
val compilerVersion = CompilerVersion.CURRENT.toString()
val libraryVersion = config.get(KonanConfigKeys.LIBRARY_VERSION)
val libraryVersion = config.configuration.get(KonanConfigKeys.LIBRARY_VERSION)
val metadataVersion = KlibMetadataVersion.INSTANCE.toString()
val irVersion = KlibIrVersion.INSTANCE.toString()
val versions = KotlinLibraryVersioning(
@@ -242,19 +244,19 @@ internal fun produceOutput(context: Context) {
metadataVersion = metadataVersion,
irVersion = irVersion
)
val target = context.config.target
val manifestProperties = context.config.manifestProperties
val target = config.target
val manifestProperties = config.manifestProperties
if (!nopack) {
val suffix = context.config.produce.suffix(target)
val suffix = config.produce.suffix(target)
if (!output.endsWith(suffix)) {
error("please specify correct output: packed: ${!nopack}, $output$suffix")
}
}
val library = buildLibrary(
context.config.nativeLibraries,
context.config.includeBinaries,
config.nativeLibraries,
config.includeBinaries,
neededLibraries,
context.serializedMetadata!!,
context.serializedIr,
@@ -267,23 +269,23 @@ internal fun produceOutput(context: Context) {
manifestProperties,
context.dataFlowGraph)
context.bitcodeFileName = library.mainBitcodeFileName
generationState.bitcodeFileName = library.mainBitcodeFileName
}
CompilerOutputKind.BITCODE -> {
val output = context.generationState.outputFile
context.bitcodeFileName = output
LLVMWriteBitcodeToFile(context.generationState.llvm.module, output)
val output = generationState.outputFile
generationState.bitcodeFileName = output
LLVMWriteBitcodeToFile(generationState.llvm.module, output)
}
else -> error("not supported: $produce")
}
}
internal fun parseAndLinkBitcodeFile(context: Context, llvmModule: LLVMModuleRef, path: String) {
val parsedModule = parseBitcodeFile(context.generationState.llvmContext, path)
if (!context.shouldUseDebugInfoFromNativeLibs()) {
private fun parseAndLinkBitcodeFile(generationState: NativeGenerationState, llvmModule: LLVMModuleRef, path: String) {
val parsedModule = parseBitcodeFile(generationState.llvmContext, path)
if (!generationState.context.shouldUseDebugInfoFromNativeLibs()) {
LLVMStripModuleDebugInfo(parsedModule)
}
val failed = llvmLinkModules2(context, llvmModule, parsedModule)
val failed = llvmLinkModules2(generationState, llvmModule, parsedModule)
if (failed != 0) {
throw Error("failed to link $path")
}
@@ -15,9 +15,10 @@ import org.jetbrains.kotlin.backend.konan.descriptors.GlobalHierarchyAnalysisRes
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.llvm.CodegenClassMetadata
import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportCodeSpec
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportedInterface
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis
import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
@@ -65,8 +66,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config), Confi
lateinit var moduleDescriptor: ModuleDescriptor
lateinit var objCExport: ObjCExport
lateinit var cAdapterGenerator: CAdapterGenerator
lateinit var expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>
@@ -190,10 +189,10 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config), Confi
InteropBuiltIns(this.builtIns)
}
lateinit var bitcodeFileName: String
lateinit var library: KonanLibraryLayout
var objCExportedInterface: ObjCExportedInterface? = null
var objCExportCodeSpec: ObjCExportCodeSpec? = null
val coverage by lazy { CoverageManager(this) }
lateinit var library: KonanLibraryLayout
fun separator(title: String) {
println("\n\n--- ${title} ----------------------\n")
@@ -229,8 +228,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config), Confi
internal val stdlibModule
get() = this.builtIns.any.module
lateinit var compilerOutput: List<ObjectFile>
val declaredLocalArrays: MutableMap<String, LLVMTypeRef> = HashMap()
lateinit var irLinker: KonanIrLinker
@@ -22,14 +22,15 @@ import org.jetbrains.kotlin.name.Name
internal object DECLARATION_ORIGIN_ENTRY_POINT : IrDeclarationOriginImpl("ENTRY_POINT")
internal fun makeEntryPoint(context: Context): IrFunction {
internal fun makeEntryPoint(generationState: NativeGenerationState): IrFunction {
val context = generationState.context
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.generationState.llvmModuleSpecification.containsDeclaration(actualMain))
val startOffset = if (generationState.llvmModuleSpecification.containsDeclaration(actualMain))
actualMain.startOffset
else
SYNTHETIC_OFFSET
val endOffset = if (context.generationState.llvmModuleSpecification.containsDeclaration(actualMain))
val endOffset = if (generationState.llvmModuleSpecification.containsDeclaration(actualMain))
actualMain.endOffset
else
SYNTHETIC_OFFSET
@@ -150,7 +150,7 @@ internal val sharedVariablesPhase = makeKonanFileLoweringPhase(
)
internal val inventNamesForLocalClasses = makeKonanFileLoweringPhase(
{ NativeInventNamesForLocalClasses(it) },
{ NativeInventNamesForLocalClasses(it.generationState) },
name = "InventNamesForLocalClasses",
description = "Invent names for local classes and anonymous objects"
)
@@ -186,7 +186,7 @@ internal val wrapInlineDeclarationsWithReifiedTypeParametersLowering = makeKonan
internal val inlinePhase = makeKonanFileOpPhase(
{ context, irFile ->
FunctionInlining(context, NativeInlineFunctionResolver(context)).lower(irFile)
FunctionInlining(context, NativeInlineFunctionResolver(context, context.generationState)).lower(irFile)
},
name = "Inline",
description = "Functions inlining",
@@ -250,10 +250,10 @@ internal val initializersPhase = makeKonanFileLoweringPhase(
prerequisite = setOf(enumConstructorsPhase)
)
internal val objectClassesPhase = makeKonanFileLoweringPhase(
::ObjectClassLowering,
internal val objectClassesPhase = makeKonanFileOpPhase(
op = { context, irFile -> ObjectClassLowering(context.generationState).lower(irFile) },
name = "ObjectClasses",
description = "Enum constructors lowering"
description = "Object classes lowering"
)
internal val localFunctionsPhase = makeKonanFileOpPhase(
@@ -333,13 +333,13 @@ internal val testProcessorPhase = makeKonanFileOpPhase(
)
internal val delegationPhase = makeKonanFileLoweringPhase(
::PropertyDelegationLowering,
{ PropertyDelegationLowering(it.generationState) },
name = "Delegation",
description = "Delegation lowering"
)
internal val functionReferencePhase = makeKonanFileLoweringPhase(
::FunctionReferenceLowering,
{ FunctionReferenceLowering(it.generationState) },
name = "FunctionReference",
description = "Function references lowering",
prerequisite = setOf(delegationPhase, localFunctionsPhase) // TODO: make weak dependency on `testProcessorPhase`
@@ -382,7 +382,7 @@ internal val builtinOperatorPhase = makeKonanFileLoweringPhase(
)
internal val interopPhase = makeKonanFileLoweringPhase(
::InteropLowering,
{ InteropLowering(it.generationState) },
name = "Interop",
description = "Interop lowering",
prerequisite = setOf(inlinePhase, localFunctionsPhase, functionReferencePhase)
@@ -397,7 +397,7 @@ internal val varargPhase = makeKonanFileLoweringPhase(
internal val coroutinesPhase = makeKonanFileOpPhase(
{ context, irFile ->
NativeSuspendFunctionsLowering(context).lower(irFile)
NativeSuspendFunctionsLowering(context.generationState).lower(irFile)
AddContinuationToNonLocalSuspendFunctionsLowering(context).lower(irFile)
NativeAddContinuationToFunctionCallsLowering(context).lower(irFile)
AddFunctionSupertypeToSuspendFunctionLowering(context).lower(irFile)
@@ -483,7 +483,7 @@ internal val exportInternalAbiPhase = makeKonanFileLoweringPhase(
)
internal val useInternalAbiPhase = makeKonanFileLoweringPhase(
::ImportCachesAbiTransformer,
{ ImportCachesAbiTransformer(it.generationState) },
name = "UseInternalAbi",
description = "Use internal ABI functions to access private entities"
)
@@ -33,8 +33,9 @@ internal fun determineLinkerOutput(context: Context): LinkerOutputKind =
else -> TODO("${context.config.produce} should not reach native linker stage")
}
internal class CacheStorage(val context: Context) {
private val outputFiles = context.generationState.outputFiles
internal class CacheStorage(val generationState: NativeGenerationState) {
private val config = generationState.context.config
private val outputFiles = generationState.outputFiles
fun renameOutput() {
// For caches the output file is a directory. It might be created by someone else,
@@ -53,30 +54,30 @@ internal class CacheStorage(val context: Context) {
}
private fun saveCacheBitcodeDependencies() {
val bitcodeDependencies = context.config.resolvedLibraries
val bitcodeDependencies = config.resolvedLibraries
.getFullList(TopologicalLibraryOrder)
.map { it as KonanLibrary }
.filter {
context.generationState.llvmImports.bitcodeIsUsed(it)
&& it != context.config.cacheSupport.libraryToCache?.klib // Skip loops.
generationState.llvmImports.bitcodeIsUsed(it)
&& it != config.cacheSupport.libraryToCache?.klib // Skip loops.
}
outputFiles.bitcodeDependenciesFile!!.writeLines(bitcodeDependencies.map { it.uniqueName })
}
private fun saveInlineFunctionBodies() {
outputFiles.inlineFunctionBodiesFile!!.writeBytes(
InlineFunctionBodyReferenceSerializer.serialize(context.generationState.inlineFunctionBodies))
InlineFunctionBodyReferenceSerializer.serialize(generationState.inlineFunctionBodies))
}
private fun saveClassFields() {
outputFiles.classFieldsFile!!.writeBytes(
ClassFieldsSerializer.serialize(context.generationState.classFields))
ClassFieldsSerializer.serialize(generationState.classFields))
}
}
// TODO: We have a Linker.kt file in the shared module.
internal class Linker(val context: Context) {
internal class Linker(val generationState: NativeGenerationState) {
private val context = generationState.context
private val platform = context.config.platform
private val config = context.config.configuration
private val linkerOutput = determineLinkerOutput(context)
@@ -86,13 +87,13 @@ internal class Linker(val context: Context) {
private val debug = context.config.debug || context.config.lightDebug
fun link(objectFiles: List<ObjectFile>) {
val nativeDependencies = context.generationState.llvm.nativeDependenciesToLink
val nativeDependencies = generationState.llvm.nativeDependenciesToLink
val includedBinariesLibraries = context.config.libraryToCache?.let { listOf(it.klib) }
?: nativeDependencies.filterNot { context.config.cachedLibraries.isLibraryCached(it) }
val includedBinaries = includedBinariesLibraries.map { (it as? KonanLibrary)?.includedPaths.orEmpty() }.flatten()
val libraryProvidedLinkerFlags = context.generationState.llvm.allNativeDependencies.map { it.linkerOpts }.flatten()
val libraryProvidedLinkerFlags = generationState.llvm.allNativeDependencies.map { it.linkerOpts }.flatten()
runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
}
@@ -117,7 +118,7 @@ internal class Linker(val context: Context) {
private fun runLinker(objectFiles: List<ObjectFile>,
includedBinaries: List<String>,
libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
val outputFiles = context.generationState.outputFiles
val outputFiles = generationState.outputFiles
val additionalLinkerArgs: List<String>
val executable: String
@@ -134,7 +135,7 @@ internal class Linker(val context: Context) {
}
executable = outputFiles.nativeBinaryFile
} else {
val framework = File(context.generationState.outputFile)
val framework = File(generationState.outputFile)
val dylibName = framework.name.removeSuffix(".framework")
val dylibRelativePath = when (target.family) {
Family.IOS,
@@ -149,7 +150,7 @@ internal class Linker(val context: Context) {
executable = dylibPath.absolutePath
}
val needsProfileLibrary = context.coverage.enabled
val needsProfileLibrary = generationState.coverage.enabled
val mimallocEnabled = context.config.allocationMode == AllocationMode.MIMALLOC
val linkerInput = determineLinkerInput(objectFiles, linkerOutput)
@@ -203,7 +204,7 @@ internal class Linker(val context: Context) {
}
private fun determineLinkerInput(objectFiles: List<ObjectFile>, linkerOutputKind: LinkerOutputKind): LinkerInput {
val caches = determineCachesToLink(context)
val caches = determineCachesToLink(generationState)
// Since we have several linker stages that involve caching,
// we should detect cache usage early to report errors correctly.
val cachingInvolved = caches.static.isNotEmpty() || caches.dynamic.isNotEmpty()
@@ -213,7 +214,7 @@ internal class Linker(val context: Context) {
LinkerInput(objectFiles, CachesToLink(emptyList(), caches.dynamic), emptyList(), cachingInvolved)
}
shouldPerformPreLink(caches, linkerOutputKind) -> {
val preLinkResult = context.generationState.tempFiles.create("withStaticCaches", ".o").absolutePath
val preLinkResult = generationState.tempFiles.create("withStaticCaches", ".o").absolutePath
val preLinkCommands = linker.preLinkCommands(objectFiles + caches.static, preLinkResult)
LinkerInput(listOf(preLinkResult), CachesToLink(emptyList(), caches.dynamic), preLinkCommands, cachingInvolved)
}
@@ -231,13 +232,13 @@ private class LinkerInput(
private class CachesToLink(val static: List<String>, val dynamic: List<String>)
private fun determineCachesToLink(context: Context): CachesToLink {
private fun determineCachesToLink(generationState: NativeGenerationState): CachesToLink {
val staticCaches = mutableListOf<String>()
val dynamicCaches = mutableListOf<String>()
context.generationState.llvm.allCachedBitcodeDependencies.forEach { library ->
val currentBinaryContainsLibrary = context.generationState.llvmModuleSpecification.containsLibrary(library)
val cache = context.config.cachedLibraries.getLibraryCache(library)
generationState.llvm.allCachedBitcodeDependencies.forEach { library ->
val currentBinaryContainsLibrary = generationState.llvmModuleSpecification.containsLibrary(library)
val cache = generationState.context.config.cachedLibraries.getLibraryCache(library)
?: error("Library $library is expected to be cached")
// Consistency check. Generally guaranteed by implementation.
@@ -43,7 +43,7 @@ internal class DefaultLlvmModuleSpecification(cachedLibraries: CachedLibraries)
}
internal class CacheLlvmModuleSpecification(
private val context: Context,
private val generationState: NativeGenerationState,
cachedLibraries: CachedLibraries,
private val libraryToCache: PartialCacheInfo
) : LlvmModuleSpecificationBase(cachedLibraries) {
@@ -52,10 +52,10 @@ internal class CacheLlvmModuleSpecification(
override fun containsLibrary(library: KotlinLibrary): Boolean = library == libraryToCache.klib
override fun containsDeclaration(declaration: IrDeclaration): Boolean {
if (context.generationState.shouldDefineFunctionClasses && declaration.getPackageFragment().isFunctionInterfaceFile)
if (generationState.shouldDefineFunctionClasses && declaration.getPackageFragment().isFunctionInterfaceFile)
return true
if (!super.containsDeclaration(declaration)) return false
return (context.generationState.cacheDeserializationStrategy as? CacheDeserializationStrategy.SingleFile)
return (generationState.cacheDeserializationStrategy as? CacheDeserializationStrategy.SingleFile)
?.filePath.let { it == null || it == declaration.fileOrNull?.path }
}
}
@@ -10,7 +10,9 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.DebugInfo
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.backend.konan.llvm.verifyModule
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer
@@ -40,7 +42,7 @@ internal class FileLowerState {
"$prefix${cStubCount++}"
}
internal class NativeGenerationState(private val context: Context, val cacheDeserializationStrategy: CacheDeserializationStrategy?) {
internal class NativeGenerationState(val context: Context, val cacheDeserializationStrategy: CacheDeserializationStrategy?) {
private val config = context.config
private val outputPath = config.cacheSupport.tryGetImplicitOutput(cacheDeserializationStrategy) ?: config.outputPath
@@ -75,7 +77,7 @@ internal class NativeGenerationState(private val context: Context, val cacheDese
val llvmModuleSpecification by lazy {
if (config.produce.isCache)
CacheLlvmModuleSpecification(context, config.cachedLibraries,
CacheLlvmModuleSpecification(this, config.cachedLibraries,
PartialCacheInfo(config.libraryToCache!!.klib, cacheDeserializationStrategy!!))
else DefaultLlvmModuleSpecification(config.cachedLibraries)
}
@@ -83,8 +85,8 @@ internal class NativeGenerationState(private val context: Context, val cacheDese
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) }
private val llvmDelegate = lazy { Llvm(this, LLVMModuleCreateWithNameInContext("out", llvmContext)!!) }
private val debugInfoDelegate = lazy { DebugInfo(this) }
val llvmContext = LLVMContextCreate()!!
val llvmImports = Llvm.ImportsImpl(context)
@@ -94,6 +96,14 @@ internal class NativeGenerationState(private val context: Context, val cacheDese
val cStubsManager = CStubsManager(config.target, this)
lateinit var llvmDeclarations: LlvmDeclarations
lateinit var bitcodeFileName: String
lateinit var compilerOutput: List<ObjectFile>
val coverage by lazy { CoverageManager(this) }
lateinit var objCExport: ObjCExport
fun hasDebugInfo() = debugInfoDelegate.isInitialized()
fun verifyBitCode() {
@@ -86,10 +86,11 @@ private fun tryGetInlineThreshold(context: Context): Int? {
* Still, runtime is not intended to be debugged by user, and we can optimize it pretty aggressively
* even in debug compilation.
*/
internal fun createLTOPipelineConfigForRuntime(context: Context): LlvmPipelineConfig {
internal fun createLTOPipelineConfigForRuntime(generationState: NativeGenerationState): LlvmPipelineConfig {
val context = generationState.context
val configurables: Configurables = context.config.platform.configurables
return LlvmPipelineConfig(
context.generationState.llvm.targetTriple,
generationState.llvm.targetTriple,
getCpuModel(context),
getCpuFeatures(context),
LlvmOptimizationLevel.AGGRESSIVE,
@@ -114,7 +115,8 @@ internal fun createLTOPipelineConfigForRuntime(context: Context): LlvmPipelineCo
* In case of debug we do almost nothing (that's why we need [createLTOPipelineConfigForRuntime]),
* but for release binaries we rely on "closed" world and enable a lot of optimizations.
*/
internal fun createLTOFinalPipelineConfig(context: Context): LlvmPipelineConfig {
internal fun createLTOFinalPipelineConfig(generationState: NativeGenerationState): LlvmPipelineConfig {
val context = generationState.context
val target = context.config.target
val configurables: Configurables = context.config.platform.configurables
val cpuModel = getCpuModel(context)
@@ -142,7 +144,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.generationState.llvmModuleSpecification.isFinal
val internalize = 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:
@@ -160,7 +162,7 @@ internal fun createLTOFinalPipelineConfig(context: Context): LlvmPipelineConfig
}
return LlvmPipelineConfig(
context.generationState.llvm.targetTriple,
generationState.llvm.targetTriple,
cpuModel,
cpuFeatures,
optimizationLevel,
@@ -36,7 +36,7 @@ internal sealed class RuntimeLinkageStrategy {
* Links all runtime modules into a single one and optimizes it.
*/
class LinkAndOptimize(
private val context: Context,
private val generationState: NativeGenerationState,
private val runtimeNativeLibraries: List<LLVMModuleRef>
) : RuntimeLinkageStrategy() {
@@ -44,15 +44,15 @@ internal sealed class RuntimeLinkageStrategy {
if (runtimeNativeLibraries.isEmpty()) {
return emptyList()
}
val runtimeModule = LLVMModuleCreateWithNameInContext("runtime", context.generationState.llvmContext)!!
val runtimeModule = LLVMModuleCreateWithNameInContext("runtime", generationState.llvmContext)!!
runtimeNativeLibraries.forEach {
val failed = llvmLinkModules2(context, runtimeModule, it)
val failed = llvmLinkModules2(generationState, runtimeModule, it)
if (failed != 0) {
throw Error("Failed to link ${it.getName()}")
}
}
val config = createLTOPipelineConfigForRuntime(context)
LlvmOptimizationPipeline(config, runtimeModule, context).use {
val config = createLTOPipelineConfigForRuntime(generationState)
LlvmOptimizationPipeline(config, runtimeModule, generationState.context).use {
it.run()
}
return listOf(runtimeModule)
@@ -63,12 +63,13 @@ internal sealed class RuntimeLinkageStrategy {
/**
* Choose runtime linkage strategy based on current compiler configuration and [BinaryOptions.linkRuntime].
*/
internal fun pick(context: Context, runtimeLlvmModules: List<LLVMModuleRef>): RuntimeLinkageStrategy {
val binaryOption = context.config.configuration.get(BinaryOptions.linkRuntime)
internal fun pick(generationState: NativeGenerationState, runtimeLlvmModules: List<LLVMModuleRef>): RuntimeLinkageStrategy {
val config = generationState.context.config
val binaryOption = config.configuration.get(BinaryOptions.linkRuntime)
return when {
binaryOption == RuntimeLinkageStrategyBinaryOption.Raw -> Raw(runtimeLlvmModules)
binaryOption == RuntimeLinkageStrategyBinaryOption.Optimize -> LinkAndOptimize(context, runtimeLlvmModules)
context.config.debug -> LinkAndOptimize(context, runtimeLlvmModules)
binaryOption == RuntimeLinkageStrategyBinaryOption.Optimize -> LinkAndOptimize(generationState, runtimeLlvmModules)
config.debug -> LinkAndOptimize(generationState, runtimeLlvmModules)
else -> Raw(runtimeLlvmModules)
}
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.CacheInfoBuilder
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.objcexport.createCodeSpec
import org.jetbrains.kotlin.backend.konan.objcexport.produceObjCExportInterface
import org.jetbrains.kotlin.backend.konan.serialization.KonanIdSignaturer
@@ -92,13 +91,12 @@ internal val createSymbolTablePhase = konanUnitPhase(
internal val objCExportPhase = konanUnitPhase(
op = {
val objcInterface = when {
objCExportedInterface = when {
!config.target.family.isAppleFamily -> null
config.produce != CompilerOutputKind.FRAMEWORK -> null
else -> produceObjCExportInterface(this)
}
val codeSpec = objcInterface?.createCodeSpec(symbolTable!!)
objCExport = ObjCExport(this, objcInterface, codeSpec)
objCExportCodeSpec = objCExportedInterface?.createCodeSpec(symbolTable!!)
},
name = "ObjCExport",
description = "Objective-C header generation",
@@ -135,7 +133,7 @@ internal val buildAdditionalCacheInfoPhase = konanUnitPhase(
if (moduleDeserializer == null) {
require(module.descriptor.isFromInteropLibrary()) { "No module deserializer for ${module.descriptor}" }
} else {
CacheInfoBuilder(this, moduleDeserializer).build()
CacheInfoBuilder(this.generationState, moduleDeserializer, module).build()
}
},
name = "BuildAdditionalCacheInfo",
@@ -216,25 +214,25 @@ internal val serializerPhase = konanUnitPhase(
)
internal val saveAdditionalCacheInfoPhase = konanUnitPhase(
op = { CacheStorage(this).saveAdditionalCacheInfo() },
op = { CacheStorage(generationState).saveAdditionalCacheInfo() },
name = "SaveAdditionalCacheInfo",
description = "Save additional cache info (inline functions bodies and fields of classes)"
)
internal val objectFilesPhase = konanUnitPhase(
op = { compilerOutput = BitcodeCompiler(this).makeObjectFiles(bitcodeFileName) },
op = { this.generationState.compilerOutput = BitcodeCompiler(this.generationState).makeObjectFiles(this.generationState.bitcodeFileName) },
name = "ObjectFiles",
description = "Bitcode to object file"
)
internal val linkerPhase = konanUnitPhase(
op = { Linker(this).link(compilerOutput) },
op = { Linker(this.generationState).link(this.generationState.compilerOutput) },
name = "Linker",
description = "Linker"
)
internal val finalizeCachePhase = konanUnitPhase(
op = { CacheStorage(this).renameOutput() },
op = { CacheStorage(this.generationState).renameOutput() },
name = "FinalizeCache",
description = "Finalize cache (rename temp to the final dist)"
)
@@ -393,7 +391,7 @@ internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
context.irModule!!.addFile(NaiveSourceBasedFileEntryImpl("entryPointOwner"), FqName("kotlin.native.internal.abi"))
}
file.addChild(makeEntryPoint(context))
file.addChild(makeEntryPoint(context.generationState))
}
)
@@ -9,6 +9,7 @@ import llvm.LLVMStoreSizeOfType
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
import org.jetbrains.kotlin.backend.konan.llvm.computeFunctionName
import org.jetbrains.kotlin.backend.konan.llvm.toLLVMType
import org.jetbrains.kotlin.backend.konan.llvm.localHash
@@ -407,31 +408,34 @@ 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>
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 }
}
fun getFields(llvm: Llvm): List<FieldInfo> = getFieldsInternal(llvm).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 var fields: List<FieldInfo>? = null
private fun getFieldsInternal(llvm: Llvm): List<FieldInfo> {
fields?.let { return it }
private val fieldsInternal: List<FieldInfo> by lazy {
val superClass = irClass.getSuperClassNotAny()
val superFields = if (superClass != null) context.getLayoutBuilder(superClass).fieldsInternal else emptyList()
val superFields = if (superClass != null) context.getLayoutBuilder(superClass).getFieldsInternal(llvm) else emptyList()
val declaredFields = getDeclaredFields()
val sortedDeclaredFields = if (irClass.hasAnnotation(KonanFqNames.noReorderFields))
declaredFields
else
declaredFields.sortedByDescending {
with(context.generationState.llvm) { LLVMStoreSizeOfType(runtime.targetData, it.type.toLLVMType(this)) }
with(llvm) { LLVMStoreSizeOfType(runtime.targetData, it.type.toLLVMType(this)) }
}
val superFieldsCount = 1 /* First field is ObjHeader */ + superFields.size
sortedDeclaredFields.forEachIndexed { index, field -> field.index = superFieldsCount + index }
superFields + sortedDeclaredFields
return (superFields + sortedDeclaredFields).also { fields = it }
}
val associatedObjects by lazy {
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.coverage.runCoveragePass
import org.jetbrains.kotlin.backend.konan.lower.InlineClassPropertyAccessorsLowering
import org.jetbrains.kotlin.backend.konan.lower.RedundantCoercionsCleaner
import org.jetbrains.kotlin.backend.konan.lower.ReturnsInsertionLowering
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
@@ -24,14 +25,14 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
internal val createLLVMDeclarationsPhase = makeKonanModuleOpPhase(
name = "CreateLLVMDeclarations",
description = "Map IR declarations to LLVM",
op = { context, _ -> context.generationState.llvmDeclarations = createLlvmDeclarations(context) }
op = { context, _ -> context.generationState.llvmDeclarations = createLlvmDeclarations(context.generationState, context.ir.irModule) }
)
internal val RTTIPhase = makeKonanModuleOpPhase(
name = "RTTI",
description = "RTTI generation",
op = { context, irModule ->
val visitor = RTTIGeneratorVisitor(context)
val visitor = RTTIGeneratorVisitor(context.generationState)
irModule.acceptVoid(visitor)
visitor.dispose()
}
@@ -245,7 +246,9 @@ internal val codegenPhase = makeKonanModuleOpPhase(
name = "Codegen",
description = "Code generation",
op = { context, irModule ->
irModule.acceptVoid(CodeGeneratorVisitor(context, context.lifetimes))
context.generationState.objCExport = ObjCExport(context.generationState, context.objCExportedInterface, context.objCExportCodeSpec)
irModule.acceptVoid(CodeGeneratorVisitor(context.generationState, context.lifetimes))
if (context.generationState.hasDebugInfo())
DIFinalize(context.generationState.debugInfo.builder)
@@ -255,25 +258,25 @@ internal val codegenPhase = makeKonanModuleOpPhase(
internal val cStubsPhase = makeKonanModuleOpPhase(
name = "CStubs",
description = "C stubs compilation",
op = { context, _ -> produceCStubs(context) }
op = { context, _ -> produceCStubs(context.generationState) }
)
internal val linkBitcodeDependenciesPhase = makeKonanModuleOpPhase(
name = "LinkBitcodeDependencies",
description = "Link bitcode dependencies",
op = { context, _ -> linkBitcodeDependencies(context) }
op = { context, _ -> linkBitcodeDependencies(context.generationState) }
)
internal val checkExternalCallsPhase = makeKonanModuleOpPhase(
name = "CheckExternalCalls",
description = "Check external calls",
op = { context, _ -> checkLlvmModuleExternalCalls(context) }
op = { context, _ -> checkLlvmModuleExternalCalls(context.generationState) }
)
internal val rewriteExternalCallsCheckerGlobals = makeKonanModuleOpPhase(
name = "RewriteExternalCallsCheckerGlobals",
description = "Rewrite globals for external calls checker after optimizer run",
op = { context, _ -> addFunctionsListSymbolForChecker(context) }
op = { context, _ -> addFunctionsListSymbolForChecker(context.generationState) }
)
@@ -282,7 +285,7 @@ internal val bitcodeOptimizationPhase = makeKonanModuleOpPhase(
name = "BitcodeOptimization",
description = "Optimize bitcode",
op = { context, _ ->
val config = createLTOFinalPipelineConfig(context)
val config = createLTOFinalPipelineConfig(context.generationState)
LlvmOptimizationPipeline(config, context.generationState.llvm.module, context).use {
it.run()
}
@@ -292,13 +295,13 @@ internal val bitcodeOptimizationPhase = makeKonanModuleOpPhase(
internal val coveragePhase = makeKonanModuleOpPhase(
name = "Coverage",
description = "Produce coverage information",
op = { context, _ -> runCoveragePass(context) }
op = { context, _ -> runCoveragePass(context.generationState) }
)
internal val optimizeTLSDataLoadsPhase = makeKonanModuleOpPhase(
name = "OptimizeTLSDataLoads",
description = "Optimize multiple loads of thread data",
op = { context, _ -> removeMultipleThreadDataLoads(context) }
op = { context, _ -> removeMultipleThreadDataLoads(context.generationState) }
)
internal val produceOutputPhase = namedUnitPhase(
@@ -306,7 +309,7 @@ internal val produceOutputPhase = namedUnitPhase(
description = "Produce output",
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfigurationService, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
produceOutput(context)
produceOutput(context.generationState)
}
}
)
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.konan.ForeignExceptionMode
internal class CodeGenerator(override val context: Context) : ContextUtils {
internal class CodeGenerator(override val generationState: NativeGenerationState) : ContextUtils {
fun llvmFunction(function: IrFunction): LlvmCallable =
llvmFunctionOrNull(function)
?: error("no function ${function.name} in ${function.file.fqName}")
@@ -32,7 +32,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun llvmFunctionOrNull(function: IrFunction): LlvmCallable? =
function.llvmFunctionOrNull
val llvmDeclarations = context.generationState.llvmDeclarations
val llvmDeclarations = generationState.llvmDeclarations
val intPtrType = LLVMIntPtrTypeInContext(llvm.llvmContext, llvmTargetData)!!
internal val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!!
internal val immThreeIntPtrType = LLVMConstInt(intPtrType, 3, 1)!!
@@ -350,7 +350,7 @@ internal class StackLocalsManagerImpl(
call(llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
} else {
val type = llvmDeclarations.forClass(stackLocal.irClass).bodyType
for (field in context.getLayoutBuilder(stackLocal.irClass).fields) {
for (field in context.getLayoutBuilder(stackLocal.irClass).getFields(llvm)) {
val fieldIndex = field.index
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
@@ -427,8 +427,8 @@ internal abstract class FunctionGenerationContext(
irFunction = builder.irFunction
)
override val context = codegen.context
val llvmDeclarations = codegen.llvmDeclarations
override val generationState = codegen.generationState
val llvmDeclarations = generationState.llvmDeclarations
val vars = VariableManager(this)
private val basicBlockToLastLocation = mutableMapOf<LLVMBasicBlockRef, LocationInfoRange>()
@@ -496,7 +496,7 @@ internal abstract class FunctionGenerationContext(
init {
irFunction?.let {
if (!irFunction.isExported()) {
if (!context.config.producePerFileCache || irFunction !in context.generationState.calledFromExportedInlineFunctions)
if (!context.config.producePerFileCache || irFunction !in generationState.calledFromExportedInlineFunctions)
LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage) // (Cannot do this before the function body is created)
}
}
@@ -544,7 +544,7 @@ internal abstract class FunctionGenerationContext(
val slotAddress = LLVMBuildAlloca(builder, type, name)!!
variableLocation?.let {
DIInsertDeclaration(
builder = codegen.context.generationState.debugInfo.builder,
builder = generationState.debugInfo.builder,
value = slotAddress,
localVariable = it.localVariable,
location = it.location,
@@ -1354,7 +1354,7 @@ internal abstract class FunctionGenerationContext(
val expr = longArrayOf(DwarfOp.DW_OP_plus_uconst.value,
runtime.pointerSize * slot.toLong()).toCValues()
DIInsertDeclaration(
builder = codegen.context.generationState.debugInfo.builder,
builder = generationState.debugInfo.builder,
value = slots,
localVariable = variable.localVariable,
location = variable.location,
@@ -136,10 +136,13 @@ internal sealed class Lifetime(val slotType: SlotType) {
* Provides utility methods to the implementer.
*/
internal interface ContextUtils : RuntimeAware {
val generationState: NativeGenerationState
val context: Context
get() = generationState.context
override val runtime: Runtime
get() = context.generationState.llvm.runtime
get() = generationState.llvm.runtime
val argumentAbiInfo: TargetAbiInfo
get() = context.targetAbiInfo
@@ -153,17 +156,17 @@ internal interface ContextUtils : RuntimeAware {
get() = runtime.targetData
val llvm: Llvm
get() = context.generationState.llvm
get() = generationState.llvm
val staticData: KotlinStaticData
get() = context.generationState.llvm.staticData
get() = generationState.llvm.staticData
/**
* TODO: maybe it'd be better to replace with [IrDeclaration::isEffectivelyExternal()],
* or just drop all [else] branches of corresponding conditionals.
*/
fun isExternal(declaration: IrDeclaration): Boolean {
return !context.generationState.llvmModuleSpecification.containsDeclaration(declaration)
return !generationState.llvmModuleSpecification.containsDeclaration(declaration)
}
/**
@@ -192,7 +195,7 @@ internal interface ContextUtils : RuntimeAware {
llvm.externalFunction(proto)
}
} else {
context.generationState.llvmDeclarations.forFunctionOrNull(this)
generationState.llvmDeclarations.forFunctionOrNull(this)
}
}
@@ -217,7 +220,7 @@ internal interface ContextUtils : RuntimeAware {
constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType,
origin = this.llvmSymbolOrigin))
} else {
context.generationState.llvmDeclarations.forClass(this).typeInfo
generationState.llvmDeclarations.forClass(this).typeInfo
}
}
@@ -294,8 +297,9 @@ internal class ConstFloat64(llvm: Llvm, val value: Double) : ConstValue {
}
@Suppress("FunctionName", "PropertyName", "PrivatePropertyName")
internal class Llvm(private val context: Context, val module: LLVMModuleRef) : RuntimeAware {
val llvmContext = context.generationState.llvmContext
internal class Llvm(private val generationState: NativeGenerationState, val module: LLVMModuleRef) : RuntimeAware {
private val context = generationState.context
val llvmContext = generationState.llvmContext
private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable {
if (LLVMGetNamedFunction(module, name) != null) {
@@ -357,7 +361,7 @@ internal class Llvm(private val context: Context, val module: LLVMModuleRef) : R
}
}
val imports get() = context.generationState.llvmImports
val imports get() = generationState.llvmImports
class ImportsImpl(private val context: Context) : LlvmImports {
@@ -450,11 +454,11 @@ internal class Llvm(private val context: Context, val module: LLVMModuleRef) : R
}
private fun shouldContainBitcode(library: KonanLibrary): Boolean {
if (!context.generationState.llvmModuleSpecification.containsLibrary(library)) {
if (!generationState.llvmModuleSpecification.containsLibrary(library)) {
return false
}
if (!context.generationState.llvmModuleSpecification.isFinal) {
if (!generationState.llvmModuleSpecification.isFinal) {
return true
}
@@ -464,11 +468,11 @@ internal class Llvm(private val context: Context, val module: LLVMModuleRef) : R
val additionalProducedBitcodeFiles = mutableListOf<String>()
val staticData = KotlinStaticData(context, this, module)
val staticData = KotlinStaticData(generationState, this, module)
private val target = context.config.target
override val runtime get() = context.generationState.runtime
override val runtime get() = generationState.runtime
val targetTriple = runtime.target
@@ -57,7 +57,7 @@ internal object DWARF {
fun KonanConfig.debugInfoVersion(): Int = configuration[KonanConfigKeys.DEBUG_INFO_VERSION] ?: 1
internal class DebugInfo(override val context: Context) : ContextUtils {
internal class DebugInfo(override val generationState: NativeGenerationState) : ContextUtils {
private val config = context.config
val builder: DIBuilderRef = LLVMCreateDIBuilder(llvm.module)!!
@@ -66,7 +66,7 @@ internal class DebugInfo(override val context: Context) : ContextUtils {
val objHeaderPointerType: DITypeOpaqueRef
init {
val path = context.generationState.outputFile.toFileAndFolder(config)
val path = generationState.outputFile.toFileAndFolder(config)
compilationUnit = DICreateCompilationUnit(
builder = builder,
lang = DWARF.language(config),
@@ -266,12 +266,12 @@ internal fun String?.toFileAndFolder(config: KonanConfig): FileAndFolder {
internal fun alignTo(value: Long, align: Long): Long = (value + align - 1) / align * align
internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): LocationInfo? {
if (!context.shouldContainLocationDebugInfo()) {
internal fun setupBridgeDebugInfo(generationState: NativeGenerationState, function: LLVMValueRef): LocationInfo? {
if (!generationState.context.shouldContainLocationDebugInfo()) {
return null
}
val debugInfo = context.generationState.debugInfo
val debugInfo = generationState.debugInfo
val file = debugInfo.compilerGeneratedFile
// TODO: can we share the scope among all bridges?
@@ -282,7 +282,7 @@ internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): Loc
linkageName = function.name,
file = file,
lineNo = 0,
type = debugInfo.subroutineType(context.generationState.runtime.targetData, emptyList()), // TODO: use proper type.
type = debugInfo.subroutineType(generationState.runtime.targetData, emptyList()), // TODO: use proper type.
isLocal = 0,
isDefinition = 1,
scopeLine = 0
@@ -81,10 +81,10 @@ internal fun IrField.isGlobalNonPrimitive(context: Context) = when {
internal fun IrField.shouldBeFrozen(context: Context): Boolean =
this.storageKind(context) == FieldStorageKind.SHARED_FROZEN
internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
val generator = RTTIGenerator(context)
internal class RTTIGeneratorVisitor(generationState: NativeGenerationState) : IrElementVisitorVoid {
val generator = RTTIGenerator(generationState)
val kotlinObjCClassInfoGenerator = KotlinObjCClassInfoGenerator(context)
val kotlinObjCClassInfoGenerator = KotlinObjCClassInfoGenerator(generationState)
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
@@ -191,12 +191,13 @@ private interface CodeContext {
//-------------------------------------------------------------------------//
internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrElement, Lifetime>) : IrElementVisitorVoid {
private val llvm = context.generationState.llvm
internal class CodeGeneratorVisitor(val generationState: NativeGenerationState, val lifetimes: Map<IrElement, Lifetime>) : IrElementVisitorVoid {
private val context = generationState.context
private val llvm = generationState.llvm
private val debugInfo: DebugInfo
get() = context.generationState.debugInfo
get() = generationState.debugInfo
val codegen = CodeGenerator(context)
val codegen = CodeGenerator(generationState)
// TODO: consider eliminating mutable state
private var currentCodeContext: CodeContext = TopLevelCodeContext
@@ -330,12 +331,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) {
val initializer = irField.initializer ?: return
val address = context.generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val address = generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
storeAny(evaluateExpression(initializer.expression), address, false)
}
private fun FunctionGenerationContext.initGlobalField(irField: IrField) {
val address = context.generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val address = generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val initialValue = if (irField.hasNonConstInitializer) {
val initialization = evaluateExpression(irField.initializer!!.expression)
if (irField.shouldBeFrozen(context))
@@ -409,18 +410,18 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitModuleFragment(declaration: IrModuleFragment) {
context.log{"visitModule : ${ir2string(declaration)}"}
context.coverage.collectRegions(declaration)
generationState.coverage.collectRegions(declaration)
initializeCachedBoxes(context)
initializeCachedBoxes(generationState)
declaration.acceptChildrenVoid(this)
runAndProcessInitializers(null) {
// Note: it is here because it also generates some bitcode.
context.objCExport.generate(codegen)
generationState.objCExport.generate(codegen)
codegen.objCDataGenerator?.finishModule()
context.coverage.writeRegionInfo()
generationState.coverage.writeRegionInfo()
overrideRuntimeGlobals()
appendLlvmUsed("llvm.used", llvm.usedFunctions + llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", llvm.compilerUsedGlobals)
@@ -505,7 +506,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Only if a subject for memory management.
.forEach { irField ->
if (irField.type.binaryTypeIsReference() && irField.storageKind(context) != FieldStorageKind.THREAD_LOCAL) {
val address = context.generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
val address = generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
functionGenerationContext
)
storeHeapRef(codegen.kNullObjHeaderPtr, address)
@@ -695,7 +696,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
this(functionGenerationContext, null, llvmFunction)
val coverageInstrumentation: LLVMCoverageInstrumentation? =
context.coverage.tryGetInstrumentation(declaration) { function, args -> functionGenerationContext.call(function, args) }
generationState.coverage.tryGetInstrumentation(declaration) { function, args -> functionGenerationContext.call(function, args) }
override fun genReturn(target: IrSymbolOwner, value: LLVMValueRef?) {
if (declaration == null || target == declaration) {
@@ -886,7 +887,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
debugFieldDeclaration(declaration)
if (context.needGlobalInit(declaration)) {
val type = declaration.type.toLLVMType(llvm)
val globalPropertyAccess = context.generationState.llvmDeclarations.forStaticField(declaration).storageAddressAccess
val globalPropertyAccess = generationState.llvmDeclarations.forStaticField(declaration).storageAddressAccess
val initializer = declaration.initializer?.expression
val globalProperty = (globalPropertyAccess as? GlobalAddressAccess)?.getAddress(null)
if (globalProperty != null) {
@@ -1669,7 +1670,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (context.config.threadsAreAllowed && value.symbol.owner.isGlobalNonPrimitive(context)) {
functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler)
}
val ptr = context.generationState.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
val ptr = generationState.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext
)
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal, resultSlot)
@@ -1738,7 +1739,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner), false)
} else {
assert(value.receiver == null)
val globalAddress = context.generationState.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
val globalAddress = generationState.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext
)
if (context.config.threadsAreAllowed && value.symbol.owner.storageKind(context) == FieldStorageKind.GLOBAL)
@@ -1759,7 +1760,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
val fieldInfo = context.generationState.llvmDeclarations.forField(value)
val fieldInfo = generationState.llvmDeclarations.forField(value)
val typePtr = pointerType(fieldInfo.classBodyType)
@@ -1822,7 +1823,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
require(value.type.toLLVMType(llvm) == codegen.kObjHeaderPtr) {
"Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}"
}
value.toBoxCacheValue(context) ?: llvm.staticData.createConstKotlinObject(
value.toBoxCacheValue(generationState) ?: llvm.staticData.createConstKotlinObject(
constructedType.getClass()!!,
evaluateConst(value.value)
)
@@ -1854,7 +1855,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val fields = if (value.constructor.owner.isConstantConstructorIntrinsic) {
intrinsicGenerator.evaluateConstantConstructorFields(value, value.valueArguments.map { evaluateConstantValue(it) })
} else {
val fields = context.getLayoutBuilder(constructedClass).fields
val fields = context.getLayoutBuilder(constructedClass).getFields(llvm)
val valueParameters = value.constructor.owner.valueParameters.associateBy { it.name.toString() }
fields.map { field ->
if (field.isConst) {
@@ -1905,7 +1906,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock, val resultSlot: LLVMValueRef?) :
FileScope(returnableBlock.inlineFunctionSymbol?.owner?.let {
context.generationState.loweredInlineFunctions[it]?.irFile ?: it.fileOrNull
generationState.loweredInlineFunctions[it]?.irFile ?: it.fileOrNull
}
?: (currentCodeContext.fileScope() as? FileScope)?.file
?: error("returnable block should belong to current file at least")) {
@@ -1914,13 +1915,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
var resultPhi : LLVMValueRef? = null
private val functionScope by lazy {
returnableBlock.inlineFunctionSymbol?.owner?.let {
it.scope(file().fileEntry.line(context.generationState.loweredInlineFunctions[it]?.startOffset ?: it.startOffset))
it.scope(file().fileEntry.line(generationState.loweredInlineFunctions[it]?.startOffset ?: it.startOffset))
}
}
private fun getExit(): LLVMBasicBlockRef {
val location = returnableBlock.inlineFunctionSymbol?.owner?.let {
location(context.generationState.loweredInlineFunctions[it]?.endOffset ?: it.endOffset)
location(generationState.loweredInlineFunctions[it]?.endOffset ?: it.endOffset)
} ?: returnableBlock.statements.lastOrNull()?.let {
location(it.endOffset)
}
@@ -2670,7 +2671,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.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (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)
@@ -2683,11 +2684,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
llvm.otherStaticInitializers += initializer
} else {
context.generationState.llvmImports.add(context.standardLlvmSymbolsOrigin)
generationState.llvmImports.add(context.standardLlvmSymbolsOrigin)
// 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.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
}
@@ -2782,14 +2783,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val ctorName = when {
// TODO: Try to not use moduleId.
library == null -> (if (context.config.produce.isCache) context.generationState.outputFiles.cacheFileName else context.config.moduleId).moduleConstructorName
library == null -> (if (context.config.produce.isCache) generationState.outputFiles.cacheFileName else context.config.moduleId).moduleConstructorName
library == context.config.libraryToCache?.klib
&& context.config.producePerFileCache ->
fileCtorName(library.uniqueName, context.generationState.outputFiles.perFileCacheFileName)
fileCtorName(library.uniqueName, generationState.outputFiles.perFileCacheFileName)
else -> library.moduleConstructorName
}
if (library == null || context.generationState.llvmModuleSpecification.containsLibrary(library)) {
if (library == null || generationState.llvmModuleSpecification.containsLibrary(library)) {
val otherInitializers = llvm.otherStaticInitializers.takeIf { library == null }.orEmpty()
val ctorFunction = addCtorFunction(ctorName)
@@ -2906,10 +2907,9 @@ internal class LocationInfo(val scope: DIScopeOpaqueRef,
val column: Int,
val inlinedAt: LocationInfo? = null)
internal fun Context.generateRuntimeConstantsModule() : LLVMModuleRef {
val llvm = generationState.llvm
val llvmModule = LLVMModuleCreateWithNameInContext("constants", generationState.llvmContext)!!
LLVMSetDataLayout(llvmModule, generationState.runtime.dataLayout)
internal fun NativeGenerationState.generateRuntimeConstantsModule() : LLVMModuleRef {
val llvmModule = LLVMModuleCreateWithNameInContext("constants", llvmContext)!!
LLVMSetDataLayout(llvmModule, runtime.dataLayout)
val static = StaticData(llvmModule, llvm)
fun setRuntimeConstGlobal(name: String, value: ConstValue) {
@@ -2918,7 +2918,8 @@ internal fun Context.generateRuntimeConstantsModule() : LLVMModuleRef {
global.setLinkage(LLVMLinkage.LLVMExternalLinkage)
}
setRuntimeConstGlobal("Kotlin_needDebugInfo", llvm.constInt32(if (shouldContainDebugInfo()) 1 else 0))
val config = context.config
setRuntimeConstGlobal("Kotlin_needDebugInfo", llvm.constInt32(if (context.shouldContainDebugInfo()) 1 else 0))
setRuntimeConstGlobal("Kotlin_runtimeAssertsMode", llvm.constInt32(config.runtimeAssertsMode.value))
val runtimeLogs = config.runtimeLogs?.let {
static.cStringLiteral(it)
@@ -16,11 +16,11 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
internal class KotlinObjCClassInfoGenerator(override val context: Context) : ContextUtils {
internal class KotlinObjCClassInfoGenerator(override val generationState: NativeGenerationState) : ContextUtils {
fun generate(irClass: IrClass) {
assert(irClass.isFinalClass)
val objCLLvmDeclarations = context.generationState.llvmDeclarations.forClass(irClass).objCDeclarations!!
val objCLLvmDeclarations = generationState.llvmDeclarations.forClass(irClass).objCDeclarations!!
val instanceMethods = generateInstanceMethodDescs(irClass)
@@ -148,7 +148,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
return constPointer(function)
}
private val codegen = CodeGenerator(context)
private val codegen = CodeGenerator(generationState)
companion object {
const val createdClassFieldIndex = 11
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.cValuesOf
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.expressions.IrConst
@@ -16,7 +17,7 @@ private fun ConstPointer.add(index: LLVMValueRef): ConstPointer {
return constPointer(LLVMConstGEP(llvm, cValuesOf(index), 1)!!)
}
internal class KotlinStaticData(override val context: Context, override val llvm: Llvm, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) {
internal class KotlinStaticData(override val generationState: NativeGenerationState, override val llvm: Llvm, module: LLVMModuleRef) : ContextUtils, StaticData(module, llvm) {
private val stringLiterals = mutableMapOf<String, ConstPointer>()
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
@@ -107,7 +108,7 @@ internal class KotlinStaticData(override val context: Context, override val llvm
kind.llvmName, runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
))
} else {
context.generationState.llvmDeclarations.forUnique(kind).pointer
generationState.llvmDeclarations.forUnique(kind).pointer
}
}
@@ -22,9 +22,9 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import kotlin.collections.set
internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
val generator = DeclarationsGeneratorVisitor(context)
context.ir.irModule.acceptChildrenVoid(generator)
internal fun createLlvmDeclarations(generationState: NativeGenerationState, irModule: IrModuleFragment): LlvmDeclarations {
val generator = DeclarationsGeneratorVisitor(generationState)
irModule.acceptChildrenVoid(generator)
return LlvmDeclarations(generator.uniques)
}
@@ -89,8 +89,8 @@ private fun ContextUtils.createClassBodyType(name: String, fields: List<ClassLay
return classType
}
private class DeclarationsGeneratorVisitor(override val context: Context) :
IrElementVisitorVoid, ContextUtils {
private class DeclarationsGeneratorVisitor(override val generationState: NativeGenerationState)
: IrElementVisitorVoid, ContextUtils {
val uniques = mutableMapOf<UniqueKind, UniqueLlvmDeclarations>()
@@ -156,7 +156,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
private fun createClassDeclarations(declaration: IrClass): ClassLlvmDeclarations {
val internalName = qualifyInternalName(declaration)
val fields = context.getLayoutBuilder(declaration).fields
val fields = context.getLayoutBuilder(declaration).getFields(llvm)
val bodyType = createClassBodyType("kclassbody:$internalName", fields)
val typeInfoPtr: ConstPointer
@@ -168,7 +168,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
if (!context.config.producePerFileCache)
"${MangleConstant.CLASS_PREFIX}:$internalName"
else {
val containerName = (context.generationState.cacheDeserializationStrategy as CacheDeserializationStrategy.SingleFile).filePath
val containerName = (generationState.cacheDeserializationStrategy as CacheDeserializationStrategy.SingleFile).filePath
declaration.computePrivateTypeInfoSymbolName(containerName)
}
}
@@ -196,7 +196,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists")
}
} else {
if (!context.config.producePerFileCache || declaration !in context.generationState.constructedFromExportedInlineFunctions)
if (!context.config.producePerFileCache || declaration !in generationState.constructedFromExportedInlineFunctions)
LLVMSetLinkage(llvmTypeInfoPtr, LLVMLinkage.LLVMInternalLinkage)
}
@@ -281,7 +281,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
if (!containingClass.requiresRtti()) return
val classDeclarations = (containingClass.metadata as? CodegenClassMetadata)?.llvm
?: error(containingClass.descriptor.toString())
val allFields = context.getLayoutBuilder(containingClass).fields
val allFields = context.getLayoutBuilder(containingClass).getFields(llvm)
val fieldInfo = allFields.firstOrNull { it.irField == declaration } ?: error("Field ${declaration.render()} is not found")
declaration.metadata = CodegenInstanceFieldMetadata(
declaration.metadata?.name,
@@ -341,7 +341,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
"${MangleConstant.FUN_PREFIX}:${qualifyInternalName(declaration)}"
else {
val containerName = declaration.parentClassOrNull?.fqNameForIrSerialization?.asString()
?: (context.generationState.cacheDeserializationStrategy as CacheDeserializationStrategy.SingleFile).filePath
?: (generationState.cacheDeserializationStrategy as CacheDeserializationStrategy.SingleFile).filePath
declaration.computePrivateSymbolName(containerName)
}
}
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
internal class RTTIGenerator(override val context: Context) : ContextUtils {
internal class RTTIGenerator(override val generationState: NativeGenerationState) : ContextUtils {
private val acyclicCache = mutableMapOf<IrType, Boolean>()
private val safeAcyclicFieldTypes = setOf(
@@ -26,7 +26,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
context.irBuiltIns.booleanClass, context.irBuiltIns.charClass,
context.irBuiltIns.byteClass, context.irBuiltIns.shortClass, context.irBuiltIns.intClass,
context.irBuiltIns.longClass,
context.irBuiltIns.floatClass,context.irBuiltIns.doubleClass) +
context.irBuiltIns.floatClass, context.irBuiltIns.doubleClass) +
context.ir.symbols.primitiveTypesToPrimitiveArrays.values +
context.ir.symbols.unsignedTypesToUnsignedArrays.values
@@ -45,7 +45,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun checkAcyclicClass(irClass: IrClass): Boolean = when {
irClass.symbol == context.ir.symbols.array -> false
irClass.isArray -> true
context.getLayoutBuilder(irClass).fields.all { checkAcyclicFieldType(it.type) } -> true
context.getLayoutBuilder(irClass).getFields(llvm).all { checkAcyclicFieldType(it.type) } -> true
else -> false
}
@@ -204,7 +204,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val className = irClass.fqNameForIrSerialization
val llvmDeclarations = context.generationState.llvmDeclarations.forClass(irClass)
val llvmDeclarations = generationState.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType
@@ -422,7 +422,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return NullPointer(runtime.extendedTypeInfoType)
val className = irClass.fqNameForIrSerialization.toString()
val llvmDeclarations = context.generationState.llvmDeclarations.forClass(irClass)
val llvmDeclarations = generationState.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType
val elementType = getElementType(irClass)
@@ -435,7 +435,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
debugOperationsSize, debugOperations)
} else {
class FieldRecord(val offset: Int, val type: Int, val name: String)
val fields = context.getLayoutBuilder(irClass).fields.map {
val fields = context.getLayoutBuilder(irClass).getFields(llvm).map {
FieldRecord(
LLVMOffsetOfElement(llvmTargetData, bodyType, it.index).toInt(),
mapRuntimeType(LLVMStructGetTypeAtIndex(bodyType, it.index)!!),
@@ -450,8 +451,8 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
Struct(runtime.extendedTypeInfoType, llvm.constInt32(fields.size), offsetsPtr, typesPtr, namesPtr,
debugOperationsSize, debugOperations)
}
val result = staticData.placeGlobal("", value)
result.setConstant(true)
return result.pointer
@@ -465,7 +466,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val associatedObjectTableRecords = associatedObjects.map { (key, value) ->
val function = context.getObjectClassInstanceFunction(value)
val llvmFunction = context.generationState.llvmDeclarations.forFunction(function).llvmValue
val llvmFunction = generationState.llvmDeclarations.forFunction(function).llvmValue
Struct(runtime.associatedObjectTableRecordType, key.typeInfoPtr, constPointer(llvmFunction))
}
@@ -596,16 +597,16 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
when {
irClass.isAnonymousObject -> {
relativeName = context.generationState.getLocalClassName(irClass)
relativeName = generationState.getLocalClassName(irClass)
flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName].
}
irClass.isLocal -> {
relativeName = context.generationState.getLocalClassName(irClass)
relativeName = generationState.getLocalClassName(irClass)
flags = TF_REFLECTION_SHOW_REL_NAME // Only allow relative name to be used in KClass.simpleName.
}
isLoweredFunctionReference(irClass) -> {
// TODO: might return null so use fallback here, to be fixed in KT-47194
relativeName = context.generationState.getLocalClassName(irClass) ?: generateDefaultRelativeName(irClass)
relativeName = generationState.getLocalClassName(irClass) ?: generateDefaultRelativeName(irClass)
flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName].
}
else -> {
@@ -19,22 +19,24 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
/**
* "Umbrella" class of all the of the code coverage related logic.
*/
internal class CoverageManager(val context: Context) {
internal class CoverageManager(val generationState: NativeGenerationState) {
private val context = generationState.context
private val config = context.config
private val shouldCoverSources: Boolean =
context.config.shouldCoverSources
config.shouldCoverSources
private val librariesToCover: Set<String> =
context.config.resolve.coveredLibraries.map { it.libraryName }.toSet()
config.resolve.coveredLibraries.map { it.libraryName }.toSet()
private val llvmProfileFilenameGlobal = "__llvm_profile_filename"
private val defaultOutputFilePath: String by lazy {
"${context.generationState.outputFile}.profraw"
"${generationState.outputFile}.profraw"
}
private val outputFileName: String =
context.config.configuration.get(KonanConfigKeys.PROFRAW_PATH)
config.configuration.get(KonanConfigKeys.PROFRAW_PATH)
?.let { File(it).absolutePath }
?: defaultOutputFilePath
@@ -43,13 +45,13 @@ internal class CoverageManager(val context: Context) {
init {
if (enabled && !checkRestrictions()) {
context.reportCompilationError("Coverage is not supported for ${context.config.target}.")
context.reportCompilationError("Coverage is not supported for ${config.target}.")
}
}
private fun checkRestrictions(): Boolean {
val isKindAllowed = context.config.produce.involvesBitcodeGeneration
val target = context.config.target
val isKindAllowed = config.produce.involvesBitcodeGeneration
val target = config.target
val isTargetAllowed = target.supportsCodeCoverage()
return isKindAllowed && isTargetAllowed
}
@@ -85,7 +87,7 @@ internal class CoverageManager(val context: Context) {
*/
fun tryGetInstrumentation(irFunction: IrFunction?, callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit) =
if (enabled && irFunction != null) {
getFunctionRegions(irFunction)?.let { LLVMCoverageInstrumentation(context, it, callSitePlacer) }
getFunctionRegions(irFunction)?.let { LLVMCoverageInstrumentation(generationState, it, callSitePlacer) }
} else {
null
}
@@ -95,7 +97,7 @@ internal class CoverageManager(val context: Context) {
*/
fun writeRegionInfo() {
if (enabled) {
LLVMCoverageWriter(context, filesRegionsInfo).write()
LLVMCoverageWriter(generationState, filesRegionsInfo).write()
}
}
@@ -121,11 +123,11 @@ internal class CoverageManager(val context: Context) {
}
}
internal fun runCoveragePass(context: Context) {
if (!context.coverage.enabled) return
internal fun runCoveragePass(generationState: NativeGenerationState) {
if (!generationState.coverage.enabled) return
val passManager = LLVMCreatePassManager()!!
LLVMKotlinAddTargetLibraryInfoWrapperPass(passManager, context.generationState.llvm.targetTriple)
context.coverage.addLateLlvmPasses(passManager)
LLVMRunPassManager(passManager, context.generationState.llvm.module)
LLVMKotlinAddTargetLibraryInfoWrapperPass(passManager, generationState.llvm.targetTriple)
generationState.coverage.addLateLlvmPasses(passManager)
LLVMRunPassManager(passManager, generationState.llvm.module)
LLVMDisposePassManager(passManager)
}
@@ -9,6 +9,7 @@ import llvm.LLVMCreatePGOFunctionNameVar
import llvm.LLVMInstrProfIncrement
import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -18,7 +19,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
* region in [functionRegions].
*/
internal class LLVMCoverageInstrumentation(
override val context: Context,
override val generationState: NativeGenerationState,
private val functionRegions: FunctionRegions,
private val callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit
) : ContextUtils {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm.coverage
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.llvm.name
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.path
@@ -34,13 +35,13 @@ private fun LLVMCoverageRegion.populateFrom(region: Region, regionId: Int, files
* See http://llvm.org/docs/CoverageMappingFormat.html for the format description.
*/
internal class LLVMCoverageWriter(
private val context: Context,
private val generationState: NativeGenerationState,
private val filesRegionsInfo: List<FileRegionInfo>
) {
fun write() {
if (filesRegionsInfo.isEmpty()) return
val module = context.generationState.llvm.module
val module = generationState.llvm.module
val filesIndex = filesRegionsInfo.mapIndexed { index, fileRegionInfo -> fileRegionInfo.file to index }.toMap()
val coverageGlobal = memScoped {
@@ -53,8 +54,8 @@ internal class LLVMCoverageWriter(
fileIds.toCValues(), fileIds.size.signExtend(),
regions.toCValues(), regions.size.signExtend())
val functionName = context.generationState.llvmDeclarations.forFunction(functionRegions.function).llvmValue.name
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(context.generationState.llvm.module),
val functionName = generationState.llvmDeclarations.forFunction(functionRegions.function).llvmValue.name
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(generationState.llvm.module),
functionName, functionRegions.structuralHash, functionCoverage)!!
Pair(functionMappingRecord, functionCoverage)
@@ -69,6 +70,6 @@ internal class LLVMCoverageWriter(
retval
}
context.generationState.llvm.usedGlobals.add(coverageGlobal)
generationState.llvm.usedGlobals.add(coverageGlobal)
}
}
@@ -7,9 +7,10 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
internal fun llvmLinkModules2(context: Context, dest: LLVMModuleRef, src: LLVMModuleRef): LLVMBool {
val diagnosticHandler = DefaultLlvmDiagnosticHandler(context, object : DefaultLlvmDiagnosticHandler.Policy {
internal fun llvmLinkModules2(generationState: NativeGenerationState, dest: LLVMModuleRef, src: LLVMModuleRef): LLVMBool {
val diagnosticHandler = DefaultLlvmDiagnosticHandler(generationState.context, object : DefaultLlvmDiagnosticHandler.Policy {
override fun suppressWarning(diagnostic: LlvmDiagnostic): Boolean {
if (super.suppressWarning(diagnostic)) return true
@@ -24,7 +25,7 @@ internal fun llvmLinkModules2(context: Context, dest: LLVMModuleRef, src: LLVMMo
}
})
return withLlvmDiagnosticHandler(context.generationState.llvmContext, diagnosticHandler) {
return withLlvmDiagnosticHandler(generationState.llvmContext, diagnosticHandler) {
LLVMLinkModules2(dest, src)
}
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.backend.konan.getARCRetainAutoreleasedReturnValueMar
import org.jetbrains.kotlin.backend.konan.llvm.*
internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
val generationState = codegen.generationState
val context = codegen.context
val llvm = codegen.llvm
@@ -8,26 +8,27 @@ package org.jetbrains.kotlin.backend.konan.llvm.objc
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.isFinalBinary
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.objcexport.NSNumberKind
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer
internal fun patchObjCRuntimeModule(context: Context): LLVMModuleRef? {
val config = context.config
internal fun patchObjCRuntimeModule(generationState: NativeGenerationState): LLVMModuleRef? {
val config = generationState.context.config
if (!(config.isFinalBinary && config.target.family.isAppleFamily)) return null
val patchBuilder = PatchBuilder(context)
val patchBuilder = PatchBuilder(generationState.objCExport.namer)
patchBuilder.addObjCPatches()
val bitcodeFile = config.objCNativeLibrary
val parsedModule = parseBitcodeFile(context.generationState.llvmContext, bitcodeFile)
val parsedModule = parseBitcodeFile(generationState.llvmContext, bitcodeFile)
patchBuilder.buildAndApply(parsedModule, context.generationState.llvm)
patchBuilder.buildAndApply(parsedModule, generationState.llvm)
return parsedModule
}
private class PatchBuilder(val context: Context) {
private class PatchBuilder(val objCExportNamer: ObjCExportNamer) {
enum class GlobalKind(val prefix: String) {
OBJC_CLASS("OBJC_CLASS_\$_"),
OBJC_METACLASS("OBJC_METACLASS_\$_"),
@@ -51,8 +52,6 @@ private class PatchBuilder(val context: Context) {
val globalPatches = mutableListOf<GlobalPatch>()
val literalPatches = mutableListOf<LiteralPatch>()
val objCExportNamer = context.objCExport.namer
// Note: exported classes anyway use the same prefix,
// so using more unique private prefix wouldn't help to prevent any clashes.
private val privatePrefix = objCExportNamer.topLevelNamePrefix
@@ -215,7 +215,7 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
val runtime get() = codegen.runtime
val staticData get() = codegen.staticData
val rttiGenerator = RTTIGenerator(context)
val rttiGenerator = RTTIGenerator(generationState)
private val objcTerminate: LlvmCallable by lazy {
llvm.externalFunction(LlvmFunctionProto(
@@ -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.generationState.shouldDefineFunctionClasses)
require(generationState.shouldDefineFunctionClasses)
}
fun generate() {
@@ -499,7 +499,7 @@ internal class ObjCExportCodeGenerator(
descriptorToAdapter[adapter.objCName] = typeAdapter
if (irClass != null) {
if (!context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (!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.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (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.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
if (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.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
val global = codegen.importGlobal(name, value.llvmType, origin)
externalGlobalInitializers[global] = value
} else {
context.generationState.llvmImports.add(origin)
generationState.llvmImports.add(origin)
val global = staticData.placeGlobal(name, value, isExported = true)
if (context.generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
if (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
@@ -745,7 +745,7 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
private fun ObjCExportCodeGeneratorBase.setOwnWritableTypeInfo(irClass: IrClass, writableTypeInfoValue: Struct) {
require(!codegen.isExternal(irClass))
val writeableTypeInfoGlobal = context.generationState.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!
val writeableTypeInfoGlobal = generationState.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!
writeableTypeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage)
writeableTypeInfoGlobal.setInitializer(writableTypeInfoValue)
}
@@ -872,7 +872,7 @@ private val ObjCExportBlockCodeGenerator.mappedFunctionNClasses get() =
.filter { it.descriptor.isMappedFunctionClass() }
private fun ObjCExportBlockCodeGenerator.emitFunctionConverters() {
require(context.generationState.shouldDefineFunctionClasses)
require(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.generationState.shouldDefineFunctionClasses)
require(generationState.shouldDefineFunctionClasses)
val functionClassesByArity = mappedFunctionNClasses.associateBy { it.arity }
val arityLimit = (functionClassesByArity.keys.maxOrNull() ?: -1) + 1
@@ -956,7 +956,7 @@ private fun ObjCExportCodeGenerator.emitCollectionConverters() {
}
private fun ObjCExportFunctionGenerationContextBuilder.setupBridgeDebugInfo() {
val location = setupBridgeDebugInfo(this.objCExportCodegen.context, function)
val location = setupBridgeDebugInfo(this.objCExportCodegen.generationState, function)
startLocation = location
endLocation = location
}
@@ -967,7 +967,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
suffix: String,
genBody: ObjCExportFunctionGenerationContext.() -> Unit
): LLVMValueRef {
val functionType = objCFunctionType(context, methodBridge)
val functionType = objCFunctionType(generationState, methodBridge)
val functionName = "objc2kotlin_$suffix"
val result = functionGenerator(functionType, functionName) {
if (debugInfo) {
@@ -1107,7 +1107,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
// Release init receiver, as required by convention.
objcReleaseFromRunnableThreadState(param(0))
}
Zero(returnType.toLlvmRetType(context).llvmType).llvm
Zero(returnType.toLlvmRetType(generationState).llvmType).llvm
}
}
@@ -1138,7 +1138,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
MethodBridge.ReturnValue.Void -> null
MethodBridge.ReturnValue.HashCode -> {
val kotlinHashCode = targetResult!!
if (codegen.context.is64BitNSInteger()) zext(kotlinHashCode, llvm.int64Type) else kotlinHashCode
if (generationState.is64BitNSInteger()) zext(kotlinHashCode, llvm.int64Type) else kotlinHashCode
}
is MethodBridge.ReturnValue.Mapped -> if (LLVMTypeOf(targetResult!!) == llvm.voidType) {
returnBridge.bridge.makeNothing(llvm)
@@ -1332,7 +1332,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
val retainAutoreleasedTargetResult = methodBridge.returnBridge.isAutoreleasedObjCReference()
val objCFunctionType = objCFunctionType(context, methodBridge)
val objCFunctionType = objCFunctionType(generationState, methodBridge)
val objcMsgSend = msgSender(objCFunctionType)
// Using terminatingExceptionHandler, so any exception thrown by the method will lead to the termination,
@@ -1370,7 +1370,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
MethodBridge.ReturnValue.Void -> null
MethodBridge.ReturnValue.HashCode -> {
if (codegen.context.is64BitNSInteger()) {
if (generationState.is64BitNSInteger()) {
val low = trunc(targetResult, llvm.int32Type)
val high = trunc(shr(targetResult, 32, signed = false), llvm.int32Type)
xor(low, high)
@@ -1877,7 +1877,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCToKotlinSyntheticGetter(
MethodBridgeReceiver.Static, valueParameters = emptyList()
)
val functionType = objCFunctionType(context, methodBridge)
val functionType = objCFunctionType(generationState, methodBridge)
val functionName = "objc2kotlin_$suffix"
val imp = functionGenerator(functionType, functionName) {
switchToRunnable = true
@@ -1975,9 +1975,9 @@ private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportC
return objCToKotlinMethodAdapter(selector, methodBridge, imp)
}
private fun objCFunctionType(context: Context, methodBridge: MethodBridge): LlvmFunctionSignature {
val paramTypes = methodBridge.paramBridges.map { it.toLlvmParamType(context.generationState.llvm) }
val returnType = methodBridge.returnBridge.toLlvmRetType(context)
private fun objCFunctionType(generationState: NativeGenerationState, methodBridge: MethodBridge): LlvmFunctionSignature {
val paramTypes = methodBridge.paramBridges.map { it.toLlvmParamType(generationState.llvm) }
val returnType = methodBridge.returnBridge.toLlvmRetType(generationState)
return LlvmFunctionSignature(returnType, paramTypes, isVararg = false)
}
@@ -2006,21 +2006,21 @@ private fun MethodBridgeParameter.toLlvmParamType(llvm: Llvm): LlvmParamType = w
}
private fun MethodBridge.ReturnValue.toLlvmRetType(
context: Context
generationState: NativeGenerationState
): LlvmRetType {
val llvm = context.generationState.llvm
val llvm = generationState.llvm
return when (this) {
MethodBridge.ReturnValue.Suspend,
MethodBridge.ReturnValue.Void -> LlvmRetType(llvm.voidType)
MethodBridge.ReturnValue.HashCode -> LlvmRetType(if (context.is64BitNSInteger()) llvm.int64Type else llvm.int32Type)
MethodBridge.ReturnValue.HashCode -> LlvmRetType(if (generationState.is64BitNSInteger()) llvm.int64Type else llvm.int32Type)
is MethodBridge.ReturnValue.Mapped -> this.bridge.toLlvmParamType(llvm)
MethodBridge.ReturnValue.WithError.Success -> ValueTypeBridge(ObjCValueType.BOOL).toLlvmParamType(llvm)
MethodBridge.ReturnValue.Instance.InitResult,
MethodBridge.ReturnValue.Instance.FactoryResult -> ReferenceBridge.toLlvmParamType(llvm)
is MethodBridge.ReturnValue.WithError.ZeroForError -> this.successBridge.toLlvmRetType(context)
is MethodBridge.ReturnValue.WithError.ZeroForError -> this.successBridge.toLlvmRetType(generationState)
}
}
@@ -2040,22 +2040,22 @@ internal fun ObjCExportCodeGenerator.getEncoding(methodBridge: MethodBridge): St
}
}
val returnTypeEncoding = methodBridge.returnBridge.getObjCEncoding(context)
val returnTypeEncoding = methodBridge.returnBridge.getObjCEncoding(generationState)
val paramSize = paramOffset
return "$returnTypeEncoding$paramSize$params"
}
private fun MethodBridge.ReturnValue.getObjCEncoding(context: Context): String = when (this) {
private fun MethodBridge.ReturnValue.getObjCEncoding(generationState: NativeGenerationState): String = when (this) {
MethodBridge.ReturnValue.Suspend,
MethodBridge.ReturnValue.Void -> "v"
MethodBridge.ReturnValue.HashCode -> if (context.is64BitNSInteger()) "Q" else "I"
MethodBridge.ReturnValue.HashCode -> if (generationState.is64BitNSInteger()) "Q" else "I"
is MethodBridge.ReturnValue.Mapped -> this.bridge.objCEncoding
MethodBridge.ReturnValue.WithError.Success -> ObjCValueType.BOOL.encoding
MethodBridge.ReturnValue.Instance.InitResult,
MethodBridge.ReturnValue.Instance.FactoryResult -> ReferenceBridge.objCEncoding
is MethodBridge.ReturnValue.WithError.ZeroForError -> this.successBridge.getObjCEncoding(context)
is MethodBridge.ReturnValue.WithError.ZeroForError -> this.successBridge.getObjCEncoding(generationState)
}
private val MethodBridgeParameter.objCEncoding: String get() = when (this) {
@@ -2071,10 +2071,10 @@ private val TypeBridge.objCEncoding: String get() = when (this) {
is ValueTypeBridge -> this.objCValueType.encoding
}
private fun Context.is64BitNSInteger(): Boolean {
val configurables = this.config.platform.configurables
private fun NativeGenerationState.is64BitNSInteger(): Boolean {
val configurables = context.config.platform.configurables
require(configurables is AppleConfigurables) {
"Target ${configurables.target} has no support for NSInteger type."
}
return generationState.llvm.nsIntegerTypeWidth == 64L
return llvm.nsIntegerTypeWidth == 64L
}
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_FUNCTION_CLASS
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr
import org.jetbrains.kotlin.ir.IrElement
@@ -16,34 +16,37 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
internal class CacheInfoBuilder(private val context: Context, private val moduleDeserializer: KonanIrLinker.KonanPartialModuleDeserializer) {
fun build() = with(moduleDeserializer) {
moduleFragment.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
internal class CacheInfoBuilder(
private val generationState: NativeGenerationState,
private val moduleDeserializer: KonanIrLinker.KonanPartialModuleDeserializer,
private val irModule: IrModuleFragment
) {
fun build() = irModule.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
if (!declaration.isInterface && !declaration.isLocal
&& declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS
) {
val declaredFields = generationState.context.getLayoutBuilder(declaration).getDeclaredFields()
generationState.classFields.add(moduleDeserializer.buildClassFields(declaration, declaredFields))
}
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
override fun visitFunction(declaration: IrFunction) {
// Don't need to visit the children here: classes would be all local and wouldn't be handled anyway,
// as for functions - both their callees will be handled and inline bodies will be built for the top function.
if (!declaration.isInterface && !declaration.isLocal
&& declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS
) {
context.generationState.classFields.add(buildClassFields(declaration, context.getLayoutBuilder(declaration).getDeclaredFields()))
}
if (!declaration.isFakeOverride && declaration.isInline && declaration.isExported) {
generationState.inlineFunctionBodies.add(moduleDeserializer.buildInlineFunctionReference(declaration))
trackCallees(declaration)
}
override fun visitFunction(declaration: IrFunction) {
// Don't need to visit the children here: classes would be all local and wouldn't be handled anyway,
// as for functions - both their callees will be handled and inline bodies will be built for the top function.
if (!declaration.isFakeOverride && declaration.isInline && declaration.isExported) {
context.generationState.inlineFunctionBodies.add(buildInlineFunctionReference(declaration))
trackCallees(declaration)
}
}
})
}
}
})
private val IrDeclaration.isExported
get() = with(KonanManglerIr) { isExported(compatibleMode = moduleDeserializer.compatibilityMode.oldSignatures) }
@@ -61,9 +64,9 @@ internal class CacheInfoBuilder(private val context: Context, private val module
private fun processFunction(function: IrFunction) {
if (function.getPackageFragment() !is IrExternalPackageFragment) {
context.generationState.calledFromExportedInlineFunctions.add(function)
generationState.calledFromExportedInlineFunctions.add(function)
(function as? IrConstructor)?.constructedClass?.let {
context.generationState.constructedFromExportedInlineFunctions.add(it)
generationState.constructedFromExportedInlineFunctions.add(it)
}
if (function.isInline && !function.isExported) {
// An exported inline function calls a non-exported inline function:
@@ -76,13 +79,13 @@ internal class CacheInfoBuilder(private val context: Context, private val module
override fun visitGetObjectValue(expression: IrGetObjectValue) {
expression.acceptChildrenVoid(this)
processFunction(context.getObjectClassInstanceFunction(expression.symbol.owner))
processFunction(generationState.context.getObjectClassInstanceFunction(expression.symbol.owner))
}
override fun visitGetEnumValue(expression: IrGetEnumValue) {
expression.acceptChildrenVoid(this)
processFunction(context.enumsSupport.getValueGetter(expression.symbol.owner.parentAsClass))
processFunction(generationState.context.enumsSupport.getValueGetter(expression.symbol.owner.parentAsClass))
}
override fun visitCall(expression: IrCall) {
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.getOrPut
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.NativeMapping
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
@@ -145,9 +146,10 @@ internal class ExportCachesAbiVisitor(val context: Context) : FileLoweringPass,
}
}
internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPass, IrElementTransformerVoid() {
private val cachesAbiSupport = context.cachesAbiSupport
private val llvmImports = context.generationState.llvmImports
internal class ImportCachesAbiTransformer(val generationState: NativeGenerationState) : FileLoweringPass, IrElementTransformerVoid() {
private val cachesAbiSupport = generationState.context.cachesAbiSupport
private val innerClassesSupport = generationState.context.innerClassesSupport
private val llvmImports = generationState.llvmImports
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(this)
@@ -162,9 +164,9 @@ internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPa
val property = field.correspondingPropertySymbol?.owner
return when {
context.generationState.llvmModuleSpecification.containsDeclaration(field) -> expression
generationState.llvmModuleSpecification.containsDeclaration(field) -> expression
irClass?.isInner == true && context.innerClassesSupport.getOuterThisField(irClass) == field -> {
irClass?.isInner == true && innerClassesSupport.getOuterThisField(irClass) == field -> {
val accessor = cachesAbiSupport.getOuterThisAccessor(irClass)
llvmImports.add(irClass.llvmSymbolOrigin)
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.buildSimpleAnnotation
import org.jetbrains.kotlin.descriptors.*
@@ -24,7 +25,8 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
internal class PropertyDelegationLowering(val generationState: NativeGenerationState) : FileLoweringPass {
private val context = generationState.context
private var tempIndex = 0
private fun getKPropertyImpl(receiverTypes: List<IrType>,
@@ -234,7 +236,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
irFile,
irFile,
this,
this@PropertyDelegationLowering.context,
generationState,
irBuilder,
)
val (newClass, newExpression) = builder.build()
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.llvm.computeFullName
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -28,7 +29,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
internal class FunctionReferenceLowering(val context: Context) : FileLoweringPass {
internal class FunctionReferenceLowering(val generationState: NativeGenerationState) : FileLoweringPass {
private object DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL : IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL")
companion object {
@@ -136,9 +137,9 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
fun transformFunctionReference(expression: IrFunctionReference, samSuperType: IrType? = null): IrExpression {
val parent: IrDeclarationContainer = (currentClass?.irElement as? IrClass) ?: irFile
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol,
val irBuilder = generationState.context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol,
expression.startOffset, expression.endOffset)
val (clazz, newExpression) = FunctionReferenceBuilder(irFile, parent, expression, context, irBuilder, samSuperType).build()
val (clazz, newExpression) = FunctionReferenceBuilder(irFile, parent, expression, generationState, irBuilder, samSuperType).build()
generatedClasses.add(clazz)
return newExpression
}
@@ -153,16 +154,17 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
val irFile: IrFile,
val parent: IrDeclarationParent,
val functionReference: IrFunctionReference,
val context: Context,
val generationState: NativeGenerationState,
val irBuilder: IrBuilderWithScope,
val samSuperType: IrType? = null,
) {
data class BuiltFunctionReference(val functionReferenceClass: IrClass, val functionReferenceExpression: IrExpression)
private val context = generationState.context
private val irBuiltIns = context.irBuiltIns
private val symbols = context.ir.symbols
private val irFactory = context.irFactory
private val fileLowerState = context.generationState.fileLowerState
private val fileLowerState = generationState.fileLowerState
private val startOffset = functionReference.startOffset
private val endOffset = functionReference.endOffset
@@ -202,7 +204,7 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
createParameterDeclarations()
// copy the generated name for IrClass, partially solves KT-47194
context.generationState.copyLocalClassName(functionReference, this)
generationState.copyLocalClassName(functionReference, this)
}
private val functionReferenceThis = functionReferenceClass.thisReceiver!!
@@ -46,10 +46,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.konan.ForeignExceptionMode
import org.jetbrains.kotlin.konan.library.KonanLibrary
internal class InteropLowering(context: Context) : FileLoweringPass {
internal class InteropLowering(generationState: NativeGenerationState) : FileLoweringPass {
// TODO: merge these lowerings.
private val part1 = InteropLoweringPart1(context)
private val part2 = InteropLoweringPart2(context)
private val part1 = InteropLoweringPart1(generationState)
private val part2 = InteropLoweringPart2(generationState)
override fun lower(irFile: IrFile) {
part1.lower(irFile)
@@ -57,7 +57,9 @@ internal class InteropLowering(context: Context) : FileLoweringPass {
}
}
private abstract class BaseInteropIrTransformer(private val context: Context) : IrBuildingTransformer(context) {
private abstract class BaseInteropIrTransformer(
private val generationState: NativeGenerationState
) : IrBuildingTransformer(generationState.context) {
protected inline fun <T> generateWithStubs(element: IrElement? = null, block: KotlinStubs.() -> T): T =
createKotlinStubs(element).block()
@@ -81,7 +83,8 @@ private abstract class BaseInteropIrTransformer(private val context: Context) :
}
return object : KotlinStubs {
private val cStubsManager = context.generationState.cStubsManager
private val context = generationState.context
private val cStubsManager = generationState.cStubsManager
override val irBuiltIns get() = context.irBuiltIns
override val symbols get() = context.ir.symbols
@@ -106,7 +109,7 @@ private abstract class BaseInteropIrTransformer(private val context: Context) :
"$uniquePrefix${cStubsManager.getUniqueName(prefix)}"
override fun getUniqueKotlinFunctionReferenceClassName(prefix: String) =
context.generationState.fileLowerState.getFunctionReferenceImplUniqueName(prefix)
generationState.fileLowerState.getFunctionReferenceImplUniqueName(prefix)
override val target get() = context.config.target
@@ -126,7 +129,8 @@ private abstract class BaseInteropIrTransformer(private val context: Context) :
protected abstract fun addTopLevel(declaration: IrDeclaration)
}
private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransformer(context), FileLoweringPass {
private class InteropLoweringPart1(val generationState: NativeGenerationState) : BaseInteropIrTransformer(generationState), FileLoweringPass {
private val context = generationState.context
private val symbols get() = context.ir.symbols
@@ -539,7 +543,7 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
): IrExpression = generateWithStubs(call) {
if (method.parent !is IrClass) {
// Category-provided.
this@InteropLoweringPart1.context.generationState.llvmImports.add(method.llvmSymbolOrigin)
generationState.llvmImports.add(method.llvmSymbolOrigin)
}
this.generateObjCCall(
@@ -746,9 +750,9 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
/**
* Lowers some interop intrinsic calls.
*/
private class InteropLoweringPart2(val context: Context) : FileLoweringPass {
private class InteropLoweringPart2(val generationState: NativeGenerationState) : FileLoweringPass {
override fun lower(irFile: IrFile) {
val transformer = InteropTransformer(context, irFile)
val transformer = InteropTransformer(generationState, irFile)
irFile.transformChildrenVoid(transformer)
while (transformer.newTopLevelDeclarations.isNotEmpty()) {
@@ -765,7 +769,11 @@ private class InteropLoweringPart2(val context: Context) : FileLoweringPass {
}
}
private class InteropTransformer(val context: Context, override val irFile: IrFile) : BaseInteropIrTransformer(context) {
private class InteropTransformer(
val generationState: NativeGenerationState,
override val irFile: IrFile
) : BaseInteropIrTransformer(generationState) {
private val context = generationState.context
val newTopLevelDeclarations = mutableListOf<IrDeclaration>()
@@ -1003,7 +1011,7 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
private fun generateCCall(expression: IrCall): IrExpression {
val function = expression.symbol.owner
context.generationState.llvmImports.add(function.llvmSymbolOrigin)
generationState.llvmImports.add(function.llvmSymbolOrigin)
val exceptionMode = ForeignExceptionMode.byValue(
function.konanLibrary?.manifestProperties?.getProperty(ForeignExceptionMode.manifestKey)
)
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.inline.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.InlineFunctionOriginInfo
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.NativeMapping
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -37,16 +38,16 @@ internal class InlineFunctionsSupport(mapping: NativeMapping) {
}
// TODO: This is a bit hacky. Think about adopting persistent IR ideas.
internal class NativeInlineFunctionResolver(override val context: Context) : DefaultInlineFunctionResolver(context) {
internal class NativeInlineFunctionResolver(override val context: Context, val generationState: NativeGenerationState) : DefaultInlineFunctionResolver(context) {
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val function = super.getFunctionDeclaration(symbol)
context.generationState.loweredInlineFunctions[function]?.let { return it.irFunction }
generationState.loweredInlineFunctions[function]?.let { return it.irFunction }
val packageFragment = function.getPackageFragment()
val (possiblyLoweredFunction, shouldLower) = if (packageFragment !is IrExternalPackageFragment) {
context.inlineFunctionsSupport.getNonLoweredInlineFunction(function, copy = context.config.producePerFileCache).also {
context.generationState.loweredInlineFunctions[function] =
generationState.loweredInlineFunctions[function] =
InlineFunctionOriginInfo(it, packageFragment as IrFile, function.startOffset, function.endOffset)
} to true
} else {
@@ -58,7 +59,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
"No IR and no cache for ${function.render()}"
}
val (shouldLower, deserializedInlineFunction) = moduleDeserializer.deserializeInlineFunction(function)
context.generationState.loweredInlineFunctions[function] = deserializedInlineFunction
generationState.loweredInlineFunctions[function] = deserializedInlineFunction
function to shouldLower
}
@@ -66,7 +67,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
val body = possiblyLoweredFunction.body ?: return possiblyLoweredFunction
PreInlineLowering(context).lower(body, possiblyLoweredFunction, context.generationState.loweredInlineFunctions[function]!!.irFile)
PreInlineLowering(context).lower(body, possiblyLoweredFunction, generationState.loweredInlineFunctions[function]!!.irFile)
ArrayConstructorLowering(context).lower(body, possiblyLoweredFunction)
@@ -80,7 +81,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
LocalClassesInInlineLambdasLowering(context).lower(body, possiblyLoweredFunction)
if (context.generationState.llvmModuleSpecification.containsDeclaration(function)) {
if (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)
@@ -7,15 +7,16 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.lower.InventNamesForLocalClasses
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer
import org.jetbrains.kotlin.ir.declarations.IrClass
// TODO: consider replacing '$' by another delimeter that can't be used in class name specified with backticks (``)
internal class NativeInventNamesForLocalClasses(val context: Context) : InventNamesForLocalClasses(allowTopLevelCallables = true) {
internal class NativeInventNamesForLocalClasses(val generationState: NativeGenerationState) : InventNamesForLocalClasses(allowTopLevelCallables = true) {
override fun computeTopLevelClassName(clazz: IrClass): String = clazz.name.asString()
override fun sanitizeNameIfNeeded(name: String) = name
override fun putLocalClassName(declaration: IrAttributeContainer, localClassName: String) {
context.generationState.putLocalClassName(declaration, localClassName)
generationState.putLocalClassName(declaration, localClassName)
}
}
@@ -4,6 +4,7 @@ import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.coroutines.getOrCreateFunctionWithContinuationStub
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.ir.IrElement
@@ -29,9 +30,11 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
internal class NativeSuspendFunctionsLowering(ctx: Context) : AbstractSuspendFunctionsLowering<Context>(ctx) {
internal class NativeSuspendFunctionsLowering(
generationState: NativeGenerationState
) : AbstractSuspendFunctionsLowering<Context>(generationState.context) {
private val symbols = context.ir.symbols
private val fileLowerState = context.generationState.fileLowerState
private val fileLowerState = generationState.fileLowerState
override val stateMachineMethodName = Name.identifier("invokeSuspend")
@@ -62,7 +62,8 @@ internal fun Context.getObjectClassInstanceFunction(clazz: IrClass) = mapping.ob
}
}
internal class ObjectClassLowering(val context: Context) : FileLoweringPass {
internal class ObjectClassLowering(val generationState: NativeGenerationState) : FileLoweringPass {
val context = generationState.context
val symbols = context.ir.symbols
override fun lower(irFile: IrFile) {
@@ -166,7 +167,7 @@ internal class ObjectClassLowering(val context: Context) : FileLoweringPass {
private fun IrClass.hasConstStateAndNoSideEffects(): Boolean {
if (this.hasAnnotation(KonanFqNames.canBePrecreated)) return true
val fields = context.getLayoutBuilder(this).fields
val fields = context.getLayoutBuilder(this).getFields(generationState.llvm)
return fields.all { it.isConst } && this.constructors.all { it.isAutogeneratedSimpleConstructor() }
}
@@ -56,10 +56,11 @@ internal fun produceObjCExportInterface(context: Context): ObjCExportedInterface
}
internal class ObjCExport(
val context: Context,
val generationState: NativeGenerationState,
private val exportedInterface: ObjCExportedInterface?,
private val codeSpec: ObjCExportCodeSpec?
) {
private val context = generationState.context
private val target get() = context.config.target
private val topLevelNamePrefix get() = context.objCExportTopLevelNamePrefix
@@ -68,7 +69,7 @@ internal class ObjCExport(
internal fun generate(codegen: CodeGenerator) {
if (!target.family.isAppleFamily) return
if (context.generationState.shouldDefineFunctionClasses) {
if (generationState.shouldDefineFunctionClasses) {
ObjCExportBlockCodeGenerator(codegen).generate()
}
@@ -101,7 +102,7 @@ internal class ObjCExport(
}
private fun produceFrameworkSpecific(headerLines: List<String>) {
val frameworkDirectory = File(context.generationState.outputFile)
val frameworkDirectory = File(generationState.outputFile)
val frameworkName = frameworkDirectory.name.removeSuffix(".framework")
val frameworkBuilder = FrameworkBuilder(
context.config,
@@ -154,7 +155,7 @@ internal class ObjCExport(
val result = Command(clangCommand).getResult(withErrors = true)
if (result.exitCode == 0) {
context.generationState.llvm.additionalProducedBitcodeFiles += bitcode.absolutePath
generationState.llvm.additionalProducedBitcodeFiles += bitcode.absolutePath
} else {
// Note: ignoring compile errors intentionally.
// In this case resulting framework will likely be unusable due to compile errors when importing it.
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.optimizations
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
import org.jetbrains.kotlin.backend.konan.llvm.getBasicBlocks
import org.jetbrains.kotlin.backend.konan.llvm.getFunctions
import org.jetbrains.kotlin.backend.konan.llvm.getInstructions
@@ -31,10 +32,10 @@ private fun process(function: LLVMValueRef, currentThreadTLV: LLVMValueRef) {
}
}
internal fun removeMultipleThreadDataLoads(context: Context) {
val currentThreadTLV = context.generationState.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return
internal fun removeMultipleThreadDataLoads(generationState: NativeGenerationState) {
val currentThreadTLV = generationState.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return
getFunctions(context.generationState.llvm.module)
getFunctions(generationState.llvm.module)
.filter { it.name?.startsWith("kfun:") == true }
.filterNot { LLVMIsDeclaration(it) == 1 }
.forEach { process(it, currentThreadTLV) }