[K/N][IR][codegen] Introduced NativeGenerationState

This commit is contained in:
Igor Chevdar
2022-08-17 17:36:42 +03:00
committed by Space
parent 77f24a22dd
commit 9250de42a5
42 changed files with 663 additions and 674 deletions
@@ -31,7 +31,7 @@ internal class BitcodeCompiler(val context: Context) {
.execute() .execute()
private fun temporary(name: String, suffix: String): String = private fun temporary(name: String, suffix: String): String =
context.config.tempFiles.create(name, suffix).absolutePath context.generationState.tempFiles.create(name, suffix).absolutePath
private fun targetTool(tool: String, vararg arg: String) { private fun targetTool(tool: String, vararg arg: String) {
val absoluteToolName = if (platform.configurables is AppleConfigurables) { val absoluteToolName = if (platform.configurables is AppleConfigurables) {
@@ -174,7 +174,7 @@ internal fun initializeCachedBoxes(context: Context) {
val rangeEnd = "${cache.name}_RANGE_TO" val rangeEnd = "${cache.name}_RANGE_TO"
initCache(cache, context, cacheName, rangeStart, rangeEnd, initCache(cache, context, cacheName, rangeStart, rangeEnd,
declareOnly = !context.shouldDefineCachedBoxes declareOnly = !context.shouldDefineCachedBoxes
).also { context.llvm.boxCacheGlobals[cache] = it } ).also { context.generationState.llvm.boxCacheGlobals[cache] = it }
} }
} }
@@ -185,9 +185,9 @@ private fun initCache(cache: BoxCache, context: Context, cacheName: String,
rangeStartName: String, rangeEndName: String, declareOnly: Boolean) : StaticData.Global { rangeStartName: String, rangeEndName: String, declareOnly: Boolean) : StaticData.Global {
val kotlinType = context.irBuiltIns.getKotlinClass(cache) val kotlinType = context.irBuiltIns.getKotlinClass(cache)
val staticData = context.llvm.staticData val staticData = context.generationState.llvm.staticData
val llvmType = staticData.getLLVMType(kotlinType.defaultType) val llvmType = staticData.getLLVMType(kotlinType.defaultType)
val llvmBoxType = structType(context.llvm.runtime.objHeaderType, llvmType) val llvmBoxType = structType(context.generationState.llvm.runtime.objHeaderType, llvmType)
val (start, end) = context.config.target.getBoxCacheRange(cache) val (start, end) = context.config.target.getBoxCacheRange(cache)
return if (declareOnly) { return if (declareOnly) {
@@ -227,7 +227,7 @@ internal fun IrConstantPrimitive.toBoxCacheValue(context: Context): ConstValue?
} }
val (start, end) = context.config.target.getBoxCacheRange(cacheType) val (start, end) = context.config.target.getBoxCacheRange(cacheType)
return if (value in start..end) { return if (value in start..end) {
context.llvm.boxCacheGlobals[cacheType]?.pointer?.getElementPtr(value.toInt() - start)?.getElementPtr(0) context.generationState.llvm.boxCacheGlobals[cacheType]?.pointer?.getElementPtr(value.toInt() - start)?.getElementPtr(0)
} else { } else {
null null
} }
@@ -245,7 +245,7 @@ private class ExportedElement(val kind: ElementKind,
// Produce type getter. // Produce type getter.
val getTypeFunction = addLlvmFunctionWithDefaultAttributes( val getTypeFunction = addLlvmFunctionWithDefaultAttributes(
context, context,
context.llvmModule!!, llvm.module,
"${cname}_type", "${cname}_type",
owner.kGetTypeFuncType owner.kGetTypeFuncType
) )
@@ -830,7 +830,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
val exportedSymbols = mutableListOf<String>() val exportedSymbols = mutableListOf<String>()
private fun makeGlobalStruct(top: ExportedElementScope) { private fun makeGlobalStruct(top: ExportedElementScope) {
val headerFile = context.config.outputFiles.cAdapterHeader val headerFile = context.generationState.outputFiles.cAdapterHeader
outputStreamWriter = headerFile.printWriter() outputStreamWriter = headerFile.printWriter()
val exportedSymbol = "${prefix}_symbols" val exportedSymbol = "${prefix}_symbols"
@@ -915,7 +915,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
outputStreamWriter.close() outputStreamWriter.close()
println("Produced library API in ${prefix}_api.h") println("Produced library API in ${prefix}_api.h")
outputStreamWriter = context.config.tempFiles outputStreamWriter = context.generationState.tempFiles
.cAdapterCpp .cAdapterCpp
.printWriter() .printWriter()
@@ -1055,7 +1055,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
outputStreamWriter.close() outputStreamWriter.close()
if (context.config.target.family == Family.MINGW) { if (context.config.target.family == Family.MINGW) {
outputStreamWriter = context.config.outputFiles outputStreamWriter = context.generationState.outputFiles
.cAdapterDef .cAdapterDef
.printWriter() .printWriter()
output("EXPORTS") output("EXPORTS")
@@ -21,6 +21,7 @@ private fun LLVMValueRef.isLLVMBuiltin(): Boolean {
private class CallsChecker(val context: Context, goodFunctions: List<String>) { private class CallsChecker(val context: Context, goodFunctions: List<String>) {
private val llvm = context.generationState.llvm
private val goodFunctionsExact = goodFunctions.filterNot { it.endsWith("*") }.toSet() private val goodFunctionsExact = goodFunctions.filterNot { it.endsWith("*") }.toSet()
private val goodFunctionsByPrefix = goodFunctions.filter { it.endsWith("*") }.map { it.substring(0, it.length - 1) }.sorted() private val goodFunctionsByPrefix = goodFunctions.filter { it.endsWith("*") }.map { it.substring(0, it.length - 1) }.sorted()
@@ -33,23 +34,23 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
} }
private fun moduleFunction(name: String) = private fun moduleFunction(name: String) =
LLVMGetNamedFunction(context.llvmModule, name) ?: throw IllegalStateException("$name function is not available") LLVMGetNamedFunction(llvm.module, name) ?: throw IllegalStateException("$name function is not available")
val getMethodImpl = context.llvm.externalFunction(LlvmFunctionProto( val getMethodImpl = llvm.externalFunction(LlvmFunctionProto(
"class_getMethodImplementation", "class_getMethodImplementation",
LlvmRetType(pointerType(functionType(voidType, false))), LlvmRetType(pointerType(functionType(voidType, false))),
listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)),
origin = context.stdlibModule.llvmSymbolOrigin) origin = context.stdlibModule.llvmSymbolOrigin)
) )
val getClass = context.llvm.externalFunction(LlvmFunctionProto( val getClass = llvm.externalFunction(LlvmFunctionProto(
"object_getClass", "object_getClass",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
origin = context.stdlibModule.llvmSymbolOrigin) origin = context.stdlibModule.llvmSymbolOrigin)
) )
val getSuperClass = context.llvm.externalFunction(LlvmFunctionProto( val getSuperClass = llvm.externalFunction(LlvmFunctionProto(
"class_getSuperclass", "class_getSuperclass",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
@@ -140,8 +141,8 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
} }
} }
} }
val callSiteDescriptionLlvm = context.llvm.staticData.cStringLiteral(callSiteDescription).llvm val callSiteDescriptionLlvm = llvm.staticData.cStringLiteral(callSiteDescription).llvm
val calledNameLlvm = if (calledName == null) LLVMConstNull(int8TypePtr) else context.llvm.staticData.cStringLiteral(calledName).llvm val calledNameLlvm = if (calledName == null) LLVMConstNull(int8TypePtr) else llvm.staticData.cStringLiteral(calledName).llvm
LLVMBuildCall(builder, checkerFunction, listOf(callSiteDescriptionLlvm, calledNameLlvm, calledPtrLlvm).toCValues(), 3, "") LLVMBuildCall(builder, checkerFunction, listOf(callSiteDescriptionLlvm, calledNameLlvm, calledPtrLlvm).toCValues(), 3, "")
} }
LLVMDisposeBuilder(builder) LLVMDisposeBuilder(builder)
@@ -164,10 +165,11 @@ private const val functionListGlobal = "Kotlin_callsCheckerKnownFunctions"
private const val functionListSizeGlobal = "Kotlin_callsCheckerKnownFunctionsCount" private const val functionListSizeGlobal = "Kotlin_callsCheckerKnownFunctionsCount"
internal fun checkLlvmModuleExternalCalls(context: Context) { internal fun checkLlvmModuleExternalCalls(context: Context) {
val staticData = context.llvm.staticData val llvm = context.generationState.llvm
val staticData = llvm.staticData
val ignoredFunctions = (context.llvm.runtimeAnnotationMap["no_external_calls_check"] ?: emptyList()) val ignoredFunctions = (llvm.runtimeAnnotationMap["no_external_calls_check"] ?: emptyList())
val goodFunctions = staticData.getGlobal("Kotlin_callsCheckerGoodFunctionNames")?.getInitializer()?.run { val goodFunctions = staticData.getGlobal("Kotlin_callsCheckerGoodFunctionNames")?.getInitializer()?.run {
getOperands(this).map { getOperands(this).map {
@@ -176,7 +178,7 @@ internal fun checkLlvmModuleExternalCalls(context: Context) {
} ?: emptyList() } ?: emptyList()
val checker = CallsChecker(context, goodFunctions) val checker = CallsChecker(context, goodFunctions)
getFunctions(context.llvmModule!!) getFunctions(llvm.module)
.filter { !it.isExternalFunction() && it !in ignoredFunctions } .filter { !it.isExternalFunction() && it !in ignoredFunctions }
.forEach(checker::processFunction) .forEach(checker::processFunction)
// otherwise optimiser can inline it // otherwise optimiser can inline it
@@ -187,9 +189,10 @@ internal fun checkLlvmModuleExternalCalls(context: Context) {
// this should be a separate pass, to handle DCE correctly // this should be a separate pass, to handle DCE correctly
internal fun addFunctionsListSymbolForChecker(context: Context) { internal fun addFunctionsListSymbolForChecker(context: Context) {
val staticData = context.llvm.staticData val llvm = context.generationState.llvm
val staticData = llvm.staticData
val functions = getFunctions(context.llvmModule!!) val functions = getFunctions(llvm.module)
.filter { !it.isExternalFunction() } .filter { !it.isExternalFunction() }
.map { constPointer(it).bitcast(int8TypePtr) } .map { constPointer(it).bitcast(int8TypePtr) }
.toList() .toList()
@@ -78,23 +78,22 @@ internal fun llvmIrDumpCallback(state: ActionState, module: IrModuleFragment, co
if (state.beforeOrAfter == BeforeOrAfter.AFTER && state.phase.name in context.configuration.getList(KonanConfigKeys.SAVE_LLVM_IR)) { if (state.beforeOrAfter == BeforeOrAfter.AFTER && state.phase.name in context.configuration.getList(KonanConfigKeys.SAVE_LLVM_IR)) {
val moduleName: String = memScoped { val moduleName: String = memScoped {
val sizeVar = alloc<size_tVar>() val sizeVar = alloc<size_tVar>()
LLVMGetModuleIdentifier(context.llvmModule, sizeVar.ptr)!!.toKStringFromUtf8() LLVMGetModuleIdentifier(context.generationState.llvm.module, sizeVar.ptr)!!.toKStringFromUtf8()
} }
val output = context.config.tempFiles.create("$moduleName.${state.phase.name}", ".ll") val output = context.generationState.tempFiles.create("$moduleName.${state.phase.name}", ".ll")
if (LLVMPrintModuleToFile(context.llvmModule, output.absolutePath, null) != 0) { if (LLVMPrintModuleToFile(context.generationState.llvm.module, output.absolutePath, null) != 0) {
error("Can't dump LLVM IR to ${output.absolutePath}") error("Can't dump LLVM IR to ${output.absolutePath}")
} }
} }
} }
internal fun produceCStubs(context: Context) { internal fun produceCStubs(context: Context) {
val llvmModule = context.llvmModule!! context.generationState.cStubsManager.compile(
context.cStubsManager.compile(
context.config.clang, context.config.clang,
context.messageCollector, context.messageCollector,
context.inVerbosePhase context.inVerbosePhase
).forEach { ).forEach {
parseAndLinkBitcodeFile(context, llvmModule, it.absolutePath) parseAndLinkBitcodeFile(context, context.generationState.llvm.module, it.absolutePath)
} }
} }
@@ -115,7 +114,7 @@ private data class LlvmModules(
private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<String>): LlvmModules { private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<String>): LlvmModules {
val config = context.config val config = context.config
val (bitcodePartOfStdlib, bitcodeLibraries) = context.llvm.bitcodeToLink val (bitcodePartOfStdlib, bitcodeLibraries) = context.generationState.llvm.bitcodeToLink
.partition { it.isStdlib && context.producedLlvmModuleContainsStdlib } .partition { it.isStdlib && context.producedLlvmModuleContainsStdlib }
.toList() .toList()
.map { libraries -> .map { libraries ->
@@ -124,7 +123,7 @@ private fun collectLlvmModules(context: Context, generatedBitcodeFiles: List<Str
val nativeLibraries = config.nativeLibraries + config.launcherNativeLibraries val nativeLibraries = config.nativeLibraries + config.launcherNativeLibraries
.takeIf { config.produce == CompilerOutputKind.PROGRAM }.orEmpty() .takeIf { config.produce == CompilerOutputKind.PROGRAM }.orEmpty()
val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles val additionalBitcodeFilesToLink = context.generationState.llvm.additionalProducedBitcodeFiles
val exceptionsSupportNativeLibrary = listOf(config.exceptionsSupportNativeLibrary) val exceptionsSupportNativeLibrary = listOf(config.exceptionsSupportNativeLibrary)
.takeIf { config.produce == CompilerOutputKind.DYNAMIC_CACHE }.orEmpty() .takeIf { config.produce == CompilerOutputKind.DYNAMIC_CACHE }.orEmpty()
val additionalBitcodeFiles = nativeLibraries + val additionalBitcodeFiles = nativeLibraries +
@@ -160,9 +159,8 @@ private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List<St
// TODO: Possibly slow, maybe to a separate phase? // TODO: Possibly slow, maybe to a separate phase?
val optimizedRuntimeModules = RuntimeLinkageStrategy.pick(context, runtimeModules).run() val optimizedRuntimeModules = RuntimeLinkageStrategy.pick(context, runtimeModules).run()
val llvmModule = context.llvmModule!!
(optimizedRuntimeModules + additionalModules).forEach { (optimizedRuntimeModules + additionalModules).forEach {
val failed = llvmLinkModules2(context, llvmModule, it) val failed = llvmLinkModules2(context, context.generationState.llvm.module, it)
if (failed != 0) { if (failed != 0) {
error("Failed to link ${it.getName()}") error("Failed to link ${it.getName()}")
} }
@@ -173,7 +171,7 @@ private fun insertAliasToEntryPoint(context: Context) {
val nomain = context.config.configuration.get(KonanConfigKeys.NOMAIN) ?: false val nomain = context.config.configuration.get(KonanConfigKeys.NOMAIN) ?: false
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain) if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
return return
val module = context.llvmModule val module = context.generationState.llvm.module
val entryPointName = context.config.entryPointName val entryPointName = context.config.entryPointName
val entryPoint = LLVMGetNamedFunction(module, entryPointName) val entryPoint = LLVMGetNamedFunction(module, entryPointName)
?: error("Module doesn't contain `$entryPointName`") ?: error("Module doesn't contain `$entryPointName`")
@@ -182,7 +180,7 @@ private fun insertAliasToEntryPoint(context: Context) {
internal fun linkBitcodeDependencies(context: Context) { internal fun linkBitcodeDependencies(context: Context) {
val config = context.config.configuration val config = context.config.configuration
val tempFiles = context.config.tempFiles val tempFiles = context.generationState.tempFiles
val produce = config.get(KonanConfigKeys.PRODUCE) val produce = config.get(KonanConfigKeys.PRODUCE)
val generatedBitcodeFiles = val generatedBitcodeFiles =
@@ -194,7 +192,7 @@ internal fun linkBitcodeDependencies(context: Context) {
listOf(tempFiles.cAdapterBitcodeName) listOf(tempFiles.cAdapterBitcodeName)
} else emptyList() } else emptyList()
if (produce == CompilerOutputKind.FRAMEWORK && context.config.produceStaticFramework) { if (produce == CompilerOutputKind.FRAMEWORK && context.config.produceStaticFramework) {
embedAppleLinkerOptionsToBitcode(context.llvm, context.config) embedAppleLinkerOptionsToBitcode(context.generationState.llvm, context.config)
} }
linkAllDependencies(context, generatedBitcodeFiles) linkAllDependencies(context, generatedBitcodeFiles)
@@ -203,7 +201,7 @@ internal fun linkBitcodeDependencies(context: Context) {
internal fun produceOutput(context: Context) { internal fun produceOutput(context: Context) {
val config = context.config.configuration val config = context.config.configuration
val tempFiles = context.config.tempFiles val tempFiles = context.generationState.tempFiles
val produce = context.config.produce val produce = context.config.produce
if (produce == CompilerOutputKind.FRAMEWORK) { if (produce == CompilerOutputKind.FRAMEWORK) {
context.objCExport.produceFrameworkInterface() context.objCExport.produceFrameworkInterface()
@@ -224,11 +222,11 @@ internal fun produceOutput(context: Context) {
// Insert `_main` after pipeline so we won't worry about optimizations // Insert `_main` after pipeline so we won't worry about optimizations
// corrupting entry point. // corrupting entry point.
insertAliasToEntryPoint(context) insertAliasToEntryPoint(context)
LLVMWriteBitcodeToFile(context.llvmModule!!, output) LLVMWriteBitcodeToFile(context.generationState.llvm.module, output)
} }
CompilerOutputKind.LIBRARY -> { CompilerOutputKind.LIBRARY -> {
val nopack = config.getBoolean(KonanConfigKeys.NOPACK) val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
val output = context.config.outputFiles.klibOutputFileName(!nopack) val output = context.generationState.outputFiles.klibOutputFileName(!nopack)
val libraryName = context.config.moduleId val libraryName = context.config.moduleId
val shortLibraryName = context.config.shortModuleName val shortLibraryName = context.config.shortModuleName
val neededLibraries = context.librariesWithDependencies val neededLibraries = context.librariesWithDependencies
@@ -248,7 +246,7 @@ internal fun produceOutput(context: Context) {
val manifestProperties = context.config.manifestProperties val manifestProperties = context.config.manifestProperties
if (!nopack) { if (!nopack) {
val suffix = context.config.outputFiles.produce.suffix(target) val suffix = context.config.produce.suffix(target)
if (!output.endsWith(suffix)) { if (!output.endsWith(suffix)) {
error("please specify correct output: packed: ${!nopack}, $output$suffix") error("please specify correct output: packed: ${!nopack}, $output$suffix")
} }
@@ -272,9 +270,9 @@ internal fun produceOutput(context: Context) {
context.bitcodeFileName = library.mainBitcodeFileName context.bitcodeFileName = library.mainBitcodeFileName
} }
CompilerOutputKind.BITCODE -> { CompilerOutputKind.BITCODE -> {
val output = context.config.outputFile val output = context.generationState.outputFile
context.bitcodeFileName = output context.bitcodeFileName = output
LLVMWriteBitcodeToFile(context.llvmModule!!, output) LLVMWriteBitcodeToFile(context.generationState.llvm.module, output)
} }
CompilerOutputKind.PRELIMINARY_CACHE -> {} CompilerOutputKind.PRELIMINARY_CACHE -> {}
} }
@@ -309,5 +307,5 @@ private fun embedAppleLinkerOptionsToBitcode(llvm: Llvm, config: KonanConfig) {
val optionsToEmbed = findEmbeddableOptions(config.platform.configurables.linkerKonanFlags) + val optionsToEmbed = findEmbeddableOptions(config.platform.configurables.linkerKonanFlags) +
llvm.allNativeDependencies.flatMap { findEmbeddableOptions(it.linkerOpts) } llvm.allNativeDependencies.flatMap { findEmbeddableOptions(it.linkerOpts) }
embedLlvmLinkOptions(llvm.llvmModule, optionsToEmbed) embedLlvmLinkOptions(llvm.module, optionsToEmbed)
} }
@@ -5,29 +5,30 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import llvm.* import llvm.LLVMTypeRef
import org.jetbrains.kotlin.backend.common.DefaultDelegateFactory import org.jetbrains.kotlin.backend.common.DefaultDelegateFactory
import org.jetbrains.kotlin.backend.common.DefaultMapping import org.jetbrains.kotlin.backend.common.DefaultMapping
import org.jetbrains.kotlin.backend.common.LoggingContext import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.BridgeDirections
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
import org.jetbrains.kotlin.backend.konan.descriptors.GlobalHierarchyAnalysisResult
import org.jetbrains.kotlin.backend.konan.descriptors.deepPrint
import org.jetbrains.kotlin.backend.konan.ir.KonanIr import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.llvm.* 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.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.backend.konan.lower.* import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.backend.konan.lower.BridgesSupport
import org.jetbrains.kotlin.backend.konan.lower.EnumsSupport
import org.jetbrains.kotlin.backend.konan.lower.InlineFunctionsSupport
import org.jetbrains.kotlin.backend.konan.lower.InnerClassesSupport
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis import org.jetbrains.kotlin.backend.konan.optimizations.DevirtualizationAnalysis
import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG import org.jetbrains.kotlin.backend.konan.optimizations.ExternalModulesDFG
import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG import org.jetbrains.kotlin.backend.konan.optimizations.ModuleDFG
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -36,15 +37,13 @@ import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
import org.jetbrains.kotlin.konan.target.Architecture import org.jetbrains.kotlin.konan.target.Architecture
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.needSmallBinary import org.jetbrains.kotlin.konan.target.needSmallBinary
import org.jetbrains.kotlin.library.SerializedIrModule import org.jetbrains.kotlin.library.SerializedIrModule
import org.jetbrains.kotlin.library.SerializedMetadata import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -54,8 +53,6 @@ import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
internal class NativeMapping : DefaultMapping() { internal class NativeMapping : DefaultMapping() {
data class BridgeKey(val target: IrSimpleFunction, val bridgeDirections: BridgeDirections) data class BridgeKey(val target: IrSimpleFunction, val bridgeDirections: BridgeDirections)
@@ -65,7 +62,6 @@ internal class NativeMapping : DefaultMapping() {
val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>() val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>()
val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>() val bridges = mutableMapOf<BridgeKey, IrSimpleFunction>()
val notLoweredInlineFunctions = mutableMapOf<IrFunctionSymbol, IrFunction>() val notLoweredInlineFunctions = mutableMapOf<IrFunctionSymbol, IrFunction>()
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
val companionObjectCacheAccessors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>() val companionObjectCacheAccessors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>()
val outerThisCacheAccessors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>() val outerThisCacheAccessors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>()
val lateinitPropertyCacheAccessors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrProperty, IrSimpleFunction>() val lateinitPropertyCacheAccessors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrProperty, IrSimpleFunction>()
@@ -95,6 +91,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
override val optimizeLoopsOverUnsignedArrays = true override val optimizeLoopsOverUnsignedArrays = true
lateinit var generationState: NativeGenerationState
fun disposeGenerationState() {
if (::generationState.isInitialized) generationState.dispose()
}
val phaseConfig = config.phaseConfig val phaseConfig = config.phaseConfig
private val packageScope by lazy { builtIns.builtInsModule.getPackage(KonanFqNames.internalPackageName).memberScope } private val packageScope by lazy { builtIns.builtInsModule.getPackage(KonanFqNames.internalPackageName).memberScope }
@@ -143,21 +145,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
lazyValues[member] = newValue lazyValues[member] = newValue
} }
val localClassNames = mutableMapOf<IrAttributeContainer, String>()
fun getLocalClassName(container: IrAttributeContainer): String? = localClassNames[container.attributeOwnerId]
fun putLocalClassName(container: IrAttributeContainer, name: String) {
localClassNames[container.attributeOwnerId] = name
}
fun copyLocalClassName(source: IrAttributeContainer, destination: IrAttributeContainer) {
getLocalClassName(source)?.let { name -> putLocalClassName(destination, name) }
}
/* test suite class -> test function names */
val testCasesToDump = mutableMapOf<ClassId, MutableCollection<String>>()
val reflectionTypes: KonanReflectionTypes by lazy(PUBLICATION) { val reflectionTypes: KonanReflectionTypes by lazy(PUBLICATION) {
KonanReflectionTypes(moduleDescriptor) KonanReflectionTypes(moduleDescriptor)
} }
@@ -225,49 +212,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
InteropBuiltIns(this.builtIns) InteropBuiltIns(this.builtIns)
} }
var llvmModule: LLVMModuleRef? = null
set(module) {
field = module!!
llvm = Llvm(this, module)
debugInfo = DebugInfo(this)
}
lateinit var runtime: Runtime
private var runtimeDisposed = false
fun disposeRuntime() {
if (runtimeDisposed) return
if (::runtime.isInitialized) {
LLVMDisposeTargetData(runtime.targetData)
LLVMDisposeModule(runtime.llvmModule)
}
runtimeDisposed = true
}
lateinit var llvmImports: LlvmImports
lateinit var llvm: Llvm
lateinit var llvmDeclarations: LlvmDeclarations
lateinit var bitcodeFileName: String lateinit var bitcodeFileName: String
lateinit var library: KonanLibraryLayout lateinit var library: KonanLibraryLayout
var llvmDisposed = false val coverage by lazy { CoverageManager(this) }
fun disposeLlvm() { fun separator(title: String) {
if (llvmDisposed) return
if (::debugInfo.isInitialized)
LLVMDisposeDIBuilder(debugInfo.builder)
if (llvmModule != null)
LLVMDisposeModule(llvmModule)
llvmDisposed = true
}
var cStubsManager = CStubsManager(config.target)
val coverage = CoverageManager(this)
protected fun separator(title: String) {
println("\n\n--- ${title} ----------------------\n") println("\n\n--- ${title} ----------------------\n")
} }
@@ -290,14 +240,13 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
} }
fun verifyBitCode() { fun verifyBitCode() {
if (llvmModule == null) return if (::generationState.isInitialized)
verifyModule(llvmModule!!) generationState.verifyBitCode()
} }
fun printBitCode() { fun printBitCode() {
if (llvmModule == null) return if (::generationState.isInitialized)
separator("BitCode:") generationState.printBitCode()
LLVMDumpModule(llvmModule!!)
} }
fun verify() { fun verify() {
@@ -342,11 +291,9 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
} }
} }
lateinit var debugInfo: DebugInfo
var moduleDFG: ModuleDFG? = null var moduleDFG: ModuleDFG? = null
var externalModulesDFG: ExternalModulesDFG? = null var externalModulesDFG: ExternalModulesDFG? = null
lateinit var lifetimes: MutableMap<IrElement, Lifetime> val lifetimes = mutableMapOf<IrElement, Lifetime>()
lateinit var codegenVisitor: CodeGeneratorVisitor
var devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult? = null var devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult? = null
var referencedFunctions: Set<IrFunction>? = null var referencedFunctions: Set<IrFunction>? = null
@@ -368,15 +315,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
lateinit var irLinker: KonanIrLinker lateinit var irLinker: KonanIrLinker
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
val classFields = mutableListOf<SerializedClassFields>()
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
val enumEntriesMaps = mutableMapOf<IrClass, Map<Name, LoweredEnumEntryDescription>>()
val targetAbiInfo: TargetAbiInfo by lazy { val targetAbiInfo: TargetAbiInfo by lazy {
when { when {
config.target == KonanTarget.MINGW_X64 -> { config.target == KonanTarget.MINGW_X64 -> {
@@ -23,16 +23,14 @@ import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.properties.loadProperties import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.KonanHomeProvider import org.jetbrains.kotlin.konan.util.KonanHomeProvider
import org.jetbrains.kotlin.konan.util.visibleName
import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder
import org.jetbrains.kotlin.util.removeSuffixIfPresent
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
class KonanConfig(val project: Project, val configuration: CompilerConfiguration) { class KonanConfig(val project: Project, val configuration: CompilerConfiguration) {
fun dispose() {
tempFiles.dispose()
}
internal val distribution = run { internal val distribution = run {
val overridenProperties = mutableMapOf<String, String>().apply { val overridenProperties = mutableMapOf<String, String>().apply {
configuration.get(KonanConfigKeys.OVERRIDE_KONAN_PROPERTIES)?.let(this::putAll) configuration.get(KonanConfigKeys.OVERRIDE_KONAN_PROPERTIES)?.let(this::putAll)
@@ -417,32 +415,21 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
get() = configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) == true get() = configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) == true
&& configuration.get(KonanConfigKeys.BATCHED_PER_FILE_CACHE_BUILD) != false && configuration.get(KonanConfigKeys.BATCHED_PER_FILE_CACHE_BUILD) != false
lateinit var outputFiles: OutputFiles val outputPath get() = configuration.get(KonanConfigKeys.OUTPUT)?.removeSuffixIfPresent(produce.suffix(target)) ?: produce.visibleName
lateinit var tempFiles: TempFiles
init {
recreateOutputFiles(producePerFileCache)
}
fun recreateOutputFiles(explicitlyProducePerFileCache: Boolean) {
val outputPath = configuration.get(KonanConfigKeys.OUTPUT) ?: cacheSupport.tryGetImplicitOutput(explicitlyProducePerFileCache)
outputFiles = OutputFiles(outputPath, target, produce, explicitlyProducePerFileCache)
tempFiles = TempFiles(outputFiles.outputName, configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR))
println("ZZZ: ${outputFiles.outputName}")
}
val outputFile get() = outputFiles.mainFileName
private val implicitModuleName: String private val implicitModuleName: String
get() = if (produce.isCache) outputFiles.cacheFileName else File(outputFiles.outputName).name get() = cacheSupport.libraryToCache?.let {
if (configuration.get(KonanConfigKeys.MAKE_PER_FILE_CACHE) == true)
CachedLibraries.getPerFileCachedLibraryName(it.klib)
else
CachedLibraries.getCachedLibraryName(it.klib)
}
?: File(outputPath).name
val infoArgsOnly = (configuration.kotlinSourceRoots.isEmpty() val infoArgsOnly = (configuration.kotlinSourceRoots.isEmpty()
&& configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty() && configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty()
&& configuration[KonanConfigKeys.EXPORTED_LIBRARIES].isNullOrEmpty() && configuration[KonanConfigKeys.EXPORTED_LIBRARIES].isNullOrEmpty()
&& libraryToCache == null) && libraryToCache == null)
|| (producePerFileCache && outputFiles.mainFile.exists)
/** /**
* Do not compile binary when compiling framework. * Do not compile binary when compiling framework.
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.backend.common.serialization.codedInputStream import org.jetbrains.kotlin.backend.common.serialization.codedInputStream
import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile import org.jetbrains.kotlin.backend.common.serialization.proto.IrFile
import org.jetbrains.kotlin.backend.konan.llvm.tryDisposeLLVMContext
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
@@ -64,12 +63,8 @@ class KonanDriver(val project: Project, val environment: KotlinCoreEnvironment,
} }
private fun KonanConfig.runTopLevelPhases() { private fun KonanConfig.runTopLevelPhases() {
try { ensureModuleName(this)
ensureModuleName(this) runTopLevelPhases(this, environment)
runTopLevelPhases(this, environment)
} finally {
dispose()
}
} }
private fun ensureModuleName(config: KonanConfig) { private fun ensureModuleName(config: KonanConfig) {
@@ -107,9 +102,7 @@ private fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreE
try { try {
toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit) toplevelPhase.cast<CompilerPhase<Context, Unit, Unit>>().invokeToplevel(context.phaseConfig, context, Unit)
} finally { } finally {
context.disposeLlvm() context.disposeGenerationState()
context.disposeRuntime()
tryDisposeLLVMContext()
} }
} }
} }
@@ -36,9 +36,9 @@ internal fun determineLinkerOutput(context: Context): LinkerOutputKind =
internal class CacheStorage(val context: Context) { internal class CacheStorage(val context: Context) {
private val isPreliminaryCache = context.config.produce == CompilerOutputKind.PRELIMINARY_CACHE private val isPreliminaryCache = context.config.produce == CompilerOutputKind.PRELIMINARY_CACHE
private val outputFiles = context.generationState.outputFiles
fun renameOutput() { fun renameOutput() {
val outputFiles = context.config.outputFiles
// For caches the output file is a directory. It might be created by someone else, // For caches the output file is a directory. It might be created by someone else,
// we have to delete it in order for the next renaming operation to succeed. // we have to delete it in order for the next renaming operation to succeed.
// TODO: what if the directory is not empty? // TODO: what if the directory is not empty?
@@ -48,7 +48,7 @@ internal class CacheStorage(val context: Context) {
} }
fun saveAdditionalCacheInfo() { fun saveAdditionalCacheInfo() {
context.config.outputFiles.prepareTempDirectories() outputFiles.prepareTempDirectories()
if (!isPreliminaryCache) if (!isPreliminaryCache)
saveCacheBitcodeDependencies() saveCacheBitcodeDependencies()
if (isPreliminaryCache || !context.config.producePerFileCache || context.config.produceBatchedPerFileCache) { if (isPreliminaryCache || !context.config.producePerFileCache || context.config.produceBatchedPerFileCache) {
@@ -62,20 +62,20 @@ internal class CacheStorage(val context: Context) {
.getFullList(TopologicalLibraryOrder) .getFullList(TopologicalLibraryOrder)
.filter { .filter {
require(it is KonanLibrary) require(it is KonanLibrary)
context.llvmImports.bitcodeIsUsed(it) context.generationState.llvmImports.bitcodeIsUsed(it)
&& it != context.config.cacheSupport.libraryToCache?.klib // Skip loops. && it != context.config.cacheSupport.libraryToCache?.klib // Skip loops.
}.cast<List<KonanLibrary>>() }.cast<List<KonanLibrary>>()
context.config.outputFiles.bitcodeDependenciesFile!!.writeLines(bitcodeDependencies.map { it.uniqueName }) outputFiles.bitcodeDependenciesFile!!.writeLines(bitcodeDependencies.map { it.uniqueName })
} }
private fun saveInlineFunctionBodies() { private fun saveInlineFunctionBodies() {
context.config.outputFiles.inlineFunctionBodiesFile!!.writeBytes( outputFiles.inlineFunctionBodiesFile!!.writeBytes(
InlineFunctionBodyReferenceSerializer.serialize(context.inlineFunctionBodies)) InlineFunctionBodyReferenceSerializer.serialize(context.generationState.inlineFunctionBodies))
} }
private fun saveClassFields() { private fun saveClassFields() {
context.config.outputFiles.classFieldsFile!!.writeBytes( outputFiles.classFieldsFile!!.writeBytes(
ClassFieldsSerializer.serialize(context.classFields)) ClassFieldsSerializer.serialize(context.generationState.classFields))
} }
} }
@@ -91,13 +91,13 @@ internal class Linker(val context: Context) {
private val debug = context.config.debug || context.config.lightDebug private val debug = context.config.debug || context.config.lightDebug
fun link(objectFiles: List<ObjectFile>) { fun link(objectFiles: List<ObjectFile>) {
val nativeDependencies = context.llvm.nativeDependenciesToLink val nativeDependencies = context.generationState.llvm.nativeDependenciesToLink
val includedBinariesLibraries = context.config.libraryToCache?.let { listOf(it.klib) } val includedBinariesLibraries = context.config.libraryToCache?.let { listOf(it.klib) }
?: nativeDependencies.filterNot { context.config.cachedLibraries.isLibraryCached(it) } ?: nativeDependencies.filterNot { context.config.cachedLibraries.isLibraryCached(it) }
val includedBinaries = includedBinariesLibraries.map { (it as? KonanLibrary)?.includedPaths.orEmpty() }.flatten() val includedBinaries = includedBinariesLibraries.map { (it as? KonanLibrary)?.includedPaths.orEmpty() }.flatten()
val libraryProvidedLinkerFlags = context.llvm.allNativeDependencies.map { it.linkerOpts }.flatten() val libraryProvidedLinkerFlags = context.generationState.llvm.allNativeDependencies.map { it.linkerOpts }.flatten()
runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags) runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
} }
@@ -122,6 +122,8 @@ internal class Linker(val context: Context) {
private fun runLinker(objectFiles: List<ObjectFile>, private fun runLinker(objectFiles: List<ObjectFile>,
includedBinaries: List<String>, includedBinaries: List<String>,
libraryProvidedLinkerFlags: List<String>): ExecutableFile? { libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
val outputFiles = context.generationState.outputFiles
val additionalLinkerArgs: List<String> val additionalLinkerArgs: List<String>
val executable: String val executable: String
@@ -129,15 +131,15 @@ internal class Linker(val context: Context) {
additionalLinkerArgs = if (target.family.isAppleFamily) { additionalLinkerArgs = if (target.family.isAppleFamily) {
when (context.config.produce) { when (context.config.produce) {
CompilerOutputKind.DYNAMIC_CACHE -> CompilerOutputKind.DYNAMIC_CACHE ->
listOf("-install_name", context.config.outputFiles.dynamicCacheInstallName) listOf("-install_name", outputFiles.dynamicCacheInstallName)
else -> listOf("-dead_strip") else -> listOf("-dead_strip")
} }
} else { } else {
emptyList() emptyList()
} }
executable = context.config.outputFiles.nativeBinaryFile executable = outputFiles.nativeBinaryFile
} else { } else {
val framework = File(context.config.outputFile) val framework = File(context.generationState.outputFile)
val dylibName = framework.name.removeSuffix(".framework") val dylibName = framework.name.removeSuffix(".framework")
val dylibRelativePath = when (target.family) { val dylibRelativePath = when (target.family) {
Family.IOS, Family.IOS,
@@ -171,7 +173,7 @@ internal class Linker(val context: Context) {
optimize = optimize, optimize = optimize,
debug = debug, debug = debug,
kind = linkerOutput, kind = linkerOutput,
outputDsymBundle = context.config.outputFiles.symbolicInfoFile, outputDsymBundle = outputFiles.symbolicInfoFile,
needsProfileLibrary = needsProfileLibrary, needsProfileLibrary = needsProfileLibrary,
mimallocEnabled = mimallocEnabled, mimallocEnabled = mimallocEnabled,
sanitizer = context.config.sanitizer sanitizer = context.config.sanitizer
@@ -216,7 +218,7 @@ internal class Linker(val context: Context) {
LinkerInput(objectFiles, CachesToLink(emptyList(), caches.dynamic), emptyList(), cachingInvolved) LinkerInput(objectFiles, CachesToLink(emptyList(), caches.dynamic), emptyList(), cachingInvolved)
} }
shouldPerformPreLink(caches, linkerOutputKind) -> { shouldPerformPreLink(caches, linkerOutputKind) -> {
val preLinkResult = context.config.tempFiles.create("withStaticCaches", ".o").absolutePath val preLinkResult = context.generationState.tempFiles.create("withStaticCaches", ".o").absolutePath
val preLinkCommands = linker.preLinkCommands(objectFiles + caches.static, preLinkResult) val preLinkCommands = linker.preLinkCommands(objectFiles + caches.static, preLinkResult)
LinkerInput(listOf(preLinkResult), CachesToLink(emptyList(), caches.dynamic), preLinkCommands, cachingInvolved) LinkerInput(listOf(preLinkResult), CachesToLink(emptyList(), caches.dynamic), preLinkCommands, cachingInvolved)
} }
@@ -238,7 +240,7 @@ private fun determineCachesToLink(context: Context): CachesToLink {
val staticCaches = mutableListOf<String>() val staticCaches = mutableListOf<String>()
val dynamicCaches = mutableListOf<String>() val dynamicCaches = mutableListOf<String>()
context.llvm.allCachedBitcodeDependencies.forEach { library -> context.generationState.llvm.allCachedBitcodeDependencies.forEach { library ->
val currentBinaryContainsLibrary = context.llvmModuleSpecification.containsLibrary(library) val currentBinaryContainsLibrary = context.llvmModuleSpecification.containsLibrary(library)
val cache = context.config.cachedLibraries.getLibraryCache(library) val cache = context.config.cachedLibraries.getLibraryCache(library)
?: error("Library $library is expected to be cached") ?: error("Library $library is expected to be cached")
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.konan
import llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.DWARF
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.llvmContext
import org.jetbrains.kotlin.backend.konan.llvm.tryDisposeLLVMContext
import org.jetbrains.kotlin.backend.konan.llvm.verifyModule
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.utils.addToStdlib.cast
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
internal class NativeGenerationState(private val context: Context) {
private val config = context.config
private val explicitlyProducePerFileCache = config.producePerFileCache && !config.produceBatchedPerFileCache
private val outputPath = config.cacheSupport.tryGetImplicitOutput(explicitlyProducePerFileCache) ?: config.outputPath
val outputFiles = OutputFiles(outputPath, config.target, config.produce, explicitlyProducePerFileCache)
val tempFiles = run {
val pathToTempDir = config.configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR)?.let {
val singleFileStrategy = config.cacheSupport.libraryToCache?.strategy as? CacheDeserializationStrategy.SingleFile
if (singleFileStrategy == null)
it
else File(it, CacheSupport.cacheFileId(singleFileStrategy.fqName, singleFileStrategy.filePath)).path
}
TempFiles(outputFiles.outputName, pathToTempDir)
}
val outputFile = outputFiles.mainFileName
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
val classFields = mutableListOf<SerializedClassFields>()
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
private val localClassNames = mutableMapOf<IrAttributeContainer, String>()
fun getLocalClassName(container: IrAttributeContainer): String? = localClassNames[container.attributeOwnerId]
fun putLocalClassName(container: IrAttributeContainer, name: String) {
localClassNames[container.attributeOwnerId] = name
}
fun copyLocalClassName(source: IrAttributeContainer, destination: IrAttributeContainer) {
getLocalClassName(source)?.let { name -> putLocalClassName(destination, name) }
}
/* test suite class -> test function names */
val testCasesToDump = mutableMapOf<ClassId, MutableCollection<String>>()
init {
llvmContext = LLVMContextCreate()!!
}
private val runtimeDelegate = lazy { Runtime(config.distribution.compilerInterface(config.target)) }
private val llvmDelegate = lazy { Llvm(context, LLVMModuleCreateWithNameInContext("out", llvmContext)!!) }
private val debugInfoDelegate = lazy {
DebugInfo(context).also {
it.builder = LLVMCreateDIBuilder(llvm.module)
// we don't split path to filename and directory to provide enough level uniquely for dsymutil to avoid symbol
// clashing, which happens on linking with libraries produced from intercepting sources.
val filePath = outputFile.toFileAndFolder(context).path()
it.compilationUnit = if (context.shouldContainLocationDebugInfo()) DICreateCompilationUnit(
builder = it.builder,
lang = DWARF.language(config),
File = filePath,
dir = "",
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion(config)
).cast()
else null
}
}
val llvmImports = Llvm.ImportsImpl(context)
val runtime by runtimeDelegate
val llvm by llvmDelegate
val debugInfo by debugInfoDelegate
val cStubsManager = CStubsManager(config.target)
lateinit var llvmDeclarations: LlvmDeclarations
fun verifyBitCode() {
if (!llvmDelegate.isInitialized()) return
verifyModule(llvm.module)
}
fun printBitCode() {
if (!llvmDelegate.isInitialized()) return
context.separator("BitCode:")
LLVMDumpModule(llvm.module)
}
private var isDisposed = false
fun dispose() {
if (isDisposed) return
if (debugInfoDelegate.isInitialized()) {
LLVMDisposeDIBuilder(debugInfo.builder)
}
if (llvmDelegate.isInitialized()) {
LLVMDisposeModule(llvm.module)
}
if (runtimeDelegate.isInitialized()) {
LLVMDisposeTargetData(runtime.targetData)
LLVMDisposeModule(runtime.llvmModule)
}
tryDisposeLLVMContext()
tempFiles.dispose()
isDisposed = true
}
}
@@ -89,7 +89,7 @@ private fun tryGetInlineThreshold(context: Context): Int? {
internal fun createLTOPipelineConfigForRuntime(context: Context): LlvmPipelineConfig { internal fun createLTOPipelineConfigForRuntime(context: Context): LlvmPipelineConfig {
val configurables: Configurables = context.config.platform.configurables val configurables: Configurables = context.config.platform.configurables
return LlvmPipelineConfig( return LlvmPipelineConfig(
context.llvm.targetTriple, context.generationState.llvm.targetTriple,
getCpuModel(context), getCpuModel(context),
getCpuFeatures(context), getCpuFeatures(context),
LlvmOptimizationLevel.AGGRESSIVE, LlvmOptimizationLevel.AGGRESSIVE,
@@ -160,7 +160,7 @@ internal fun createLTOFinalPipelineConfig(context: Context): LlvmPipelineConfig
} }
return LlvmPipelineConfig( return LlvmPipelineConfig(
context.llvm.targetTriple, context.generationState.llvm.targetTriple,
cpuModel, cpuModel,
cpuFeatures, cpuFeatures,
optimizationLevel, optimizationLevel,
@@ -17,13 +17,11 @@ import kotlin.random.Random
/** /**
* Creates and stores terminal compiler outputs. * Creates and stores terminal compiler outputs.
*/ */
class OutputFiles(outputPath: String?, target: KonanTarget, val produce: CompilerOutputKind, val producePerFileCache: Boolean) { class OutputFiles(val outputName: String, target: KonanTarget, val produce: CompilerOutputKind, val producePerFileCache: Boolean) {
private val prefix = produce.prefix(target) private val prefix = produce.prefix(target)
private val suffix = produce.suffix(target) private val suffix = produce.suffix(target)
val outputName = outputPath?.removeSuffixIfPresent(suffix) ?: produce.visibleName
fun klibOutputFileName(isPacked: Boolean): String = fun klibOutputFileName(isPacked: Boolean): String =
if (isPacked) "$outputName$suffix" else outputName if (isPacked) "$outputName$suffix" else outputName
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.serialization.* import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.builtins.FunctionInterfacePackageFragment
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -347,7 +346,6 @@ internal val umbrellaCompilation = NamedCompilerPhase(
// Pretend we're about to create a single file cache. // Pretend we're about to create a single file cache.
context.config.cacheSupport.libraryToCache!!.strategy = context.config.cacheSupport.libraryToCache!!.strategy =
CacheDeserializationStrategy.SingleFile(file.path, file.fqName.asString()) CacheDeserializationStrategy.SingleFile(file.path, file.fqName.asString())
context.config.recreateOutputFiles(explicitlyProducePerFileCache = false)
module.files += file module.files += file
if (context.shouldDefineFunctionClasses) if (context.shouldDefineFunctionClasses)
@@ -357,15 +355,6 @@ internal val umbrellaCompilation = NamedCompilerPhase(
module.files.clear() module.files.clear()
context.irModule!!.files.clear() // [dependenciesLowerPhase] puts all files to [context.irModule] for codegen. context.irModule!!.files.clear() // [dependenciesLowerPhase] puts all files to [context.irModule] for codegen.
context.inlineFunctionBodies.clear()
context.classFields.clear()
context.calledFromExportedInlineFunctions.clear()
context.constructedFromExportedInlineFunctions.clear()
context.localClassNames.clear()
context.testCasesToDump.clear()
context.mapping.loweredInlineFunctions.clear()
context.cStubsManager = CStubsManager(context.config.target)
} }
module.files += files module.files += files
@@ -382,11 +371,11 @@ internal val dumpTestsPhase = makeCustomPhase<Context, IrModuleFragment>(
if (!testDumpFile.exists) if (!testDumpFile.exists)
testDumpFile.createNew() testDumpFile.createNew()
if (context.testCasesToDump.isEmpty()) if (context.generationState.testCasesToDump.isEmpty())
return@makeCustomPhase return@makeCustomPhase
testDumpFile.appendLines( testDumpFile.appendLines(
context.testCasesToDump context.generationState.testCasesToDump
.flatMap { (suiteClassId, functionNames) -> .flatMap { (suiteClassId, functionNames) ->
val suiteName = suiteClassId.asString() val suiteName = suiteClassId.asString()
functionNames.asSequence().map { "$suiteName:$it" } functionNames.asSequence().map { "$suiteName:$it" }
@@ -418,8 +407,7 @@ internal val entryPointPhase = makeCustomPhase<Context, IrModuleFragment>(
internal val bitcodePhase = NamedCompilerPhase( internal val bitcodePhase = NamedCompilerPhase(
name = "Bitcode", name = "Bitcode",
description = "LLVM Bitcode generation", description = "LLVM Bitcode generation",
lower = contextLLVMSetupPhase then lower = returnsInsertionPhase then
returnsInsertionPhase then
buildDFGPhase then buildDFGPhase then
devirtualizationAnalysisPhase then devirtualizationAnalysisPhase then
dcePhase then dcePhase then
@@ -467,10 +455,30 @@ private val backendCodegen = NamedCompilerPhase(
bitcodePostprocessingPhase bitcodePostprocessingPhase
) )
internal val createGenerationStatePhase = namedUnitPhase(
name = "CreateGenerationState",
description = "Create generation state",
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
context.generationState = NativeGenerationState(context)
}
}
)
internal val disposeGenerationStatePhase = namedUnitPhase(
name = "DisposeGenerationState",
description = "Dispose generation state",
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
context.disposeGenerationState()
}
}
)
private val entireBackend = NamedCompilerPhase( private val entireBackend = NamedCompilerPhase(
name = "EntireBackend", name = "EntireBackend",
description = "Entire backend", description = "Entire backend",
lower = createLLVMImportsPhase then lower = createGenerationStatePhase then
buildAdditionalCacheInfoPhase then buildAdditionalCacheInfoPhase then
takeFromContext { it.irModule!! } then takeFromContext { it.irModule!! } then
specialBackendChecksPhase then specialBackendChecksPhase then
@@ -478,10 +486,10 @@ private val entireBackend = NamedCompilerPhase(
unitSink() then unitSink() then
saveAdditionalCacheInfoPhase then saveAdditionalCacheInfoPhase then
produceOutputPhase then produceOutputPhase then
disposeLLVMPhase then
objectFilesPhase then objectFilesPhase then
linkerPhase then linkerPhase then
finalizeCachePhase finalizeCachePhase then
disposeGenerationStatePhase
) )
private val middleEnd = NamedCompilerPhase( private val middleEnd = NamedCompilerPhase(
@@ -547,6 +555,10 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
disableUnless(rewriteExternalCallsCheckerGlobals, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS)) disableUnless(rewriteExternalCallsCheckerGlobals, getBoolean(KonanConfigKeys.CHECK_EXTERNAL_CALLS))
disableUnless(stringConcatenationTypeNarrowingPhase, config.optimizationsEnabled) disableUnless(stringConcatenationTypeNarrowingPhase, config.optimizationsEnabled)
disableUnless(optimizeTLSDataLoadsPhase, config.optimizationsEnabled) disableUnless(optimizeTLSDataLoadsPhase, config.optimizationsEnabled)
if (!config.debug && !config.lightDebug) {
disable(generateDebugInfoHeaderPhase)
disable(finalizeDebugInfoPhase)
}
if (!config.involvesLinkStage) { if (!config.involvesLinkStage) {
disable(bitcodePostprocessingPhase) disable(bitcodePostprocessingPhase)
disable(linkBitcodeDependenciesPhase) disable(linkBitcodeDependenciesPhase)
@@ -423,7 +423,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
declaredFields declaredFields
else else
declaredFields.sortedByDescending { declaredFields.sortedByDescending {
with(context.llvm) { LLVMStoreSizeOfType(runtime.targetData, getLLVMType(it.type)) } with(context.generationState.llvm) { LLVMStoreSizeOfType(runtime.targetData, getLLVMType(it.type)) }
} }
val superFieldsCount = 1 /* First field is ObjHeader */ + superFields.size val superFieldsCount = 1 /* First field is ObjHeader */ + superFields.size
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.konan.llvm package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase import org.jetbrains.kotlin.backend.common.phaser.CompilerPhase
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.PhaserState import org.jetbrains.kotlin.backend.common.phaser.PhaserState
@@ -23,77 +22,12 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.konan.target.Architecture
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.cast
internal val contextLLVMSetupPhase = makeKonanModuleOpPhase(
name = "ContextLLVMSetup",
description = "Set up Context for LLVM Bitcode generation",
op = { context, _ ->
// Note that we don't set module target explicitly.
// It is determined by the target of runtime.bc
// (see Llvm class in ContextUtils)
// Which in turn is determined by the clang flags
// used to compile runtime.bc.
// TODO
llvmContext = LLVMContextCreate()!!
context.llvmDisposed = false
context.runtime = Runtime(context.config.distribution.compilerInterface(context.config.target))
val llvmModule = LLVMModuleCreateWithNameInContext("out", llvmContext)!!
context.llvmModule = llvmModule
context.debugInfo.builder = LLVMCreateDIBuilder(llvmModule)
// we don't split path to filename and directory to provide enough level uniquely for dsymutil to avoid symbol
// clashing, which happens on linking with libraries produced from intercepting sources.
val filePath = context.config.outputFile.toFileAndFolder(context).path()
context.debugInfo.compilationUnit = if (context.shouldContainLocationDebugInfo()) DICreateCompilationUnit(
builder = context.debugInfo.builder,
lang = DWARF.language(context.config),
File = filePath,
dir = "",
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion(context.config)).cast()
else null
}
)
internal val createLLVMDeclarationsPhase = makeKonanModuleOpPhase( internal val createLLVMDeclarationsPhase = makeKonanModuleOpPhase(
name = "CreateLLVMDeclarations", name = "CreateLLVMDeclarations",
description = "Map IR declarations to LLVM", description = "Map IR declarations to LLVM",
prerequisite = setOf(contextLLVMSetupPhase), op = { context, _ -> context.generationState.llvmDeclarations = createLlvmDeclarations(context) }
op = { context, _ ->
context.llvmDeclarations = createLlvmDeclarations(context)
context.lifetimes = mutableMapOf()
context.codegenVisitor = CodeGeneratorVisitor(context, context.lifetimes)
}
)
internal val createLLVMImportsPhase = namedUnitPhase(
name = "CreateLLVMImoorts",
description = "Create LLVM imports",
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
context.llvmImports = Llvm.ImportsImpl(context)
}
}
)
internal val disposeLLVMPhase = namedUnitPhase(
name = "DisposeLLVM",
description = "Dispose LLVM",
lower = object : CompilerPhase<Context, Unit, Unit> {
override fun invoke(phaseConfig: PhaseConfig, phaserState: PhaserState<Unit>, context: Context, input: Unit) {
context.disposeLlvm()
context.disposeRuntime()
tryDisposeLLVMContext()
}
}
) )
internal val RTTIPhase = makeKonanModuleOpPhase( internal val RTTIPhase = makeKonanModuleOpPhase(
@@ -328,19 +262,13 @@ internal val localEscapeAnalysisPhase = makeKonanModuleOpPhase(
internal val codegenPhase = makeKonanModuleOpPhase( internal val codegenPhase = makeKonanModuleOpPhase(
name = "Codegen", name = "Codegen",
description = "Code generation", description = "Code generation",
op = { context, irModule -> op = { context, irModule -> irModule.acceptVoid(CodeGeneratorVisitor(context, context.lifetimes)) }
irModule.acceptVoid(context.codegenVisitor)
}
) )
internal val finalizeDebugInfoPhase = makeKonanModuleOpPhase( internal val finalizeDebugInfoPhase = makeKonanModuleOpPhase(
name = "FinalizeDebugInfo", name = "FinalizeDebugInfo",
description = "Finalize debug info", description = "Finalize debug info",
op = { context, _ -> op = { context, _ -> DIFinalize(context.generationState.debugInfo.builder) }
if (context.shouldContainAnyDebugInfo()) {
DIFinalize(context.debugInfo.builder)
}
}
) )
internal val cStubsPhase = makeKonanModuleOpPhase( internal val cStubsPhase = makeKonanModuleOpPhase(
@@ -374,7 +302,7 @@ internal val bitcodeOptimizationPhase = makeKonanModuleOpPhase(
description = "Optimize bitcode", description = "Optimize bitcode",
op = { context, _ -> op = { context, _ ->
val config = createLTOFinalPipelineConfig(context) val config = createLTOFinalPipelineConfig(context)
LlvmOptimizationPipeline(config, context.llvmModule!!, context).use { LlvmOptimizationPipeline(config, context.generationState.llvm.module, context).use {
it.run() it.run()
} }
} }
@@ -407,7 +335,7 @@ internal val removeRedundantSafepointsPhase = makeKonanModuleOpPhase(
description = "Remove function prologue safepoints inlined to another function", description = "Remove function prologue safepoints inlined to another function",
op = { context, _ -> op = { context, _ ->
RemoveRedundantSafepointsPass(context).runOnModule( RemoveRedundantSafepointsPass(context).runOnModule(
module = context.llvmModule!!, module = context.generationState.llvm.module,
isSafepointInliningAllowed = context.shouldInlineSafepoints() isSafepointInliningAllowed = context.shouldInlineSafepoints()
) )
} }
@@ -54,6 +54,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun llvmFunctionOrNull(function: IrFunction): LlvmCallable? = fun llvmFunctionOrNull(function: IrFunction): LlvmCallable? =
function.llvmFunctionOrNull function.llvmFunctionOrNull
val llvmDeclarations = context.generationState.llvmDeclarations
val intPtrType = LLVMIntPtrTypeInContext(llvmContext, llvmTargetData)!! val intPtrType = LLVMIntPtrTypeInContext(llvmContext, llvmTargetData)!!
internal val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!! internal val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!!
internal val immThreeIntPtrType = LLVMConstInt(intPtrType, 3, 1)!! internal val immThreeIntPtrType = LLVMConstInt(intPtrType, 3, 1)!!
@@ -80,10 +81,10 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
} }
fun generateLocationInfo(locationInfo: LocationInfo): DILocationRef? = if (locationInfo.inlinedAt != null) fun generateLocationInfo(locationInfo: LocationInfo): DILocationRef? = if (locationInfo.inlinedAt != null)
LLVMCreateLocationInlinedAt(LLVMGetModuleContext(context.llvmModule), locationInfo.line, locationInfo.column, LLVMCreateLocationInlinedAt(LLVMGetModuleContext(llvm.module), locationInfo.line, locationInfo.column,
locationInfo.scope, generateLocationInfo(locationInfo.inlinedAt)) locationInfo.scope, generateLocationInfo(locationInfo.inlinedAt))
else else
LLVMCreateLocation(LLVMGetModuleContext(context.llvmModule), locationInfo.line, locationInfo.column, locationInfo.scope) LLVMCreateLocation(LLVMGetModuleContext(llvm.module), locationInfo.line, locationInfo.column, locationInfo.scope)
val objCDataGenerator = when { val objCDataGenerator = when {
context.config.target.family.isAppleFamily -> ObjCDataGenerator(this) context.config.target.family.isAppleFamily -> ObjCDataGenerator(this)
@@ -104,7 +105,7 @@ internal sealed class ExceptionHandler {
kotlinException: LLVMValueRef kotlinException: LLVMValueRef
): Unit = with(functionGenerationContext) { ): Unit = with(functionGenerationContext) {
call( call(
context.llvm.throwExceptionFunction, llvm.throwExceptionFunction,
listOf(kotlinException), listOf(kotlinException),
Lifetime.IRRELEVANT, Lifetime.IRRELEVANT,
this@ExceptionHandler this@ExceptionHandler
@@ -201,7 +202,7 @@ internal inline fun generateFunction(
): LLVMValueRef { ): LLVMValueRef {
val function = addLlvmFunctionWithDefaultAttributes( val function = addLlvmFunctionWithDefaultAttributes(
codegen.context, codegen.context,
codegen.context.llvmModule!!, codegen.llvm.module,
name, name,
functionType functionType
) )
@@ -236,7 +237,7 @@ internal inline fun generateFunctionNoRuntime(
): LLVMValueRef { ): LLVMValueRef {
val function = addLlvmFunctionWithDefaultAttributes( val function = addLlvmFunctionWithDefaultAttributes(
codegen.context, codegen.context,
codegen.context.llvmModule!!, codegen.llvm.module,
name, name,
functionType functionType
) )
@@ -284,7 +285,7 @@ internal class StackLocalsManagerImpl(
if (context.memoryModel == MemoryModel.EXPERIMENTAL) alloca(kObjHeaderPtr) else null if (context.memoryModel == MemoryModel.EXPERIMENTAL) alloca(kObjHeaderPtr) else null
override fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef = with(functionGenerationContext) { override fun alloc(irClass: IrClass, cleanFieldsExplicitly: Boolean): LLVMValueRef = with(functionGenerationContext) {
val type = context.llvmDeclarations.forClass(irClass).bodyType val type = llvmDeclarations.forClass(irClass).bodyType
val stackLocal = appendingTo(bbInitStackLocals) { val stackLocal = appendingTo(bbInitStackLocals) {
val stackSlot = LLVMBuildAlloca(builder, type, "")!! val stackSlot = LLVMBuildAlloca(builder, type, "")!!
@@ -313,7 +314,7 @@ internal class StackLocalsManagerImpl(
// Create new type or get already created. // Create new type or get already created.
context.declaredLocalArrays.getOrPut(name) { context.declaredLocalArrays.getOrPut(name) {
val fieldTypes = listOf(kArrayHeader, LLVMArrayType(arrayToElementType[irClass.symbol]!!, count)) val fieldTypes = listOf(kArrayHeader, LLVMArrayType(arrayToElementType[irClass.symbol]!!, count))
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!! val classType = LLVMStructCreateNamed(LLVMGetModuleContext(llvm.module), name)!!
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, 1) LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, 1)
classType classType
} }
@@ -367,9 +368,9 @@ internal class StackLocalsManagerImpl(
private fun clean(stackLocal: StackLocal, refsOnly: Boolean) = with(functionGenerationContext) { private fun clean(stackLocal: StackLocal, refsOnly: Boolean) = with(functionGenerationContext) {
if (stackLocal.isArray) { if (stackLocal.isArray) {
if (stackLocal.irClass.symbol == context.ir.symbols.array) if (stackLocal.irClass.symbol == context.ir.symbols.array)
call(context.llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr)) call(llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
} else { } else {
val type = context.llvmDeclarations.forClass(stackLocal.irClass).bodyType val type = llvmDeclarations.forClass(stackLocal.irClass).bodyType
for (field in context.getLayoutBuilder(stackLocal.irClass).fields) { for (field in context.getLayoutBuilder(stackLocal.irClass).fields) {
val fieldIndex = field.index val fieldIndex = field.index
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!! val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
@@ -379,7 +380,7 @@ internal class StackLocalsManagerImpl(
if (refsOnly) if (refsOnly)
storeHeapRef(kNullObjHeaderPtr, fieldPtr) storeHeapRef(kNullObjHeaderPtr, fieldPtr)
else else
call(context.llvm.zeroHeapRefFunction, listOf(fieldPtr)) call(llvm.zeroHeapRefFunction, listOf(fieldPtr))
} }
} }
@@ -414,7 +415,7 @@ internal abstract class FunctionGenerationContextBuilder<T : FunctionGenerationC
this( this(
addLlvmFunctionWithDefaultAttributes( addLlvmFunctionWithDefaultAttributes(
codegen.context, codegen.context,
codegen.context.llvmModule!!, codegen.llvm.module,
functionName, functionName,
functionType functionType
), ),
@@ -448,6 +449,7 @@ internal abstract class FunctionGenerationContext(
) )
override val context = codegen.context override val context = codegen.context
val llvmDeclarations = codegen.llvmDeclarations
val vars = VariableManager(this) val vars = VariableManager(this)
private val basicBlockToLastLocation = mutableMapOf<LLVMBasicBlockRef, LocationInfoRange>() private val basicBlockToLastLocation = mutableMapOf<LLVMBasicBlockRef, LocationInfoRange>()
@@ -515,7 +517,7 @@ internal abstract class FunctionGenerationContext(
init { init {
irFunction?.let { irFunction?.let {
if (!irFunction.isExported()) { if (!irFunction.isExported()) {
if (!context.config.producePerFileCache || irFunction !in context.calledFromExportedInlineFunctions) if (!context.config.producePerFileCache || irFunction !in context.generationState.calledFromExportedInlineFunctions)
LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage) // (Cannot do this before the function body is created) LLVMSetLinkage(function, LLVMLinkage.LLVMInternalLinkage) // (Cannot do this before the function body is created)
} }
} }
@@ -563,7 +565,7 @@ internal abstract class FunctionGenerationContext(
val slotAddress = LLVMBuildAlloca(builder, type, name)!! val slotAddress = LLVMBuildAlloca(builder, type, name)!!
variableLocation?.let { variableLocation?.let {
DIInsertDeclaration( DIInsertDeclaration(
builder = codegen.context.debugInfo.builder, builder = codegen.context.generationState.debugInfo.builder,
value = slotAddress, value = slotAddress,
localVariable = it.localVariable, localVariable = it.localVariable,
location = it.location, location = it.location,
@@ -623,19 +625,19 @@ internal abstract class FunctionGenerationContext(
fun freeze(value: LLVMValueRef, exceptionHandler: ExceptionHandler) { fun freeze(value: LLVMValueRef, exceptionHandler: ExceptionHandler) {
if (isObjectRef(value)) if (isObjectRef(value))
call(context.llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler) call(llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler)
} }
fun checkGlobalsAccessible(exceptionHandler: ExceptionHandler) { fun checkGlobalsAccessible(exceptionHandler: ExceptionHandler) {
if (context.memoryModel == MemoryModel.STRICT) if (context.memoryModel == MemoryModel.STRICT)
call(context.llvm.checkGlobalsAccessible, emptyList(), Lifetime.IRRELEVANT, exceptionHandler) call(llvm.checkGlobalsAccessible, emptyList(), Lifetime.IRRELEVANT, exceptionHandler)
} }
private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) { private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
if (context.memoryModel == MemoryModel.STRICT) if (context.memoryModel == MemoryModel.STRICT)
store(value, address) store(value, address)
else else
call(context.llvm.updateReturnRefFunction, listOf(address, value)) call(llvm.updateReturnRefFunction, listOf(address, value))
} }
private fun updateRef(value: LLVMValueRef, address: LLVMValueRef, onStack: Boolean) { private fun updateRef(value: LLVMValueRef, address: LLVMValueRef, onStack: Boolean) {
@@ -643,9 +645,9 @@ internal abstract class FunctionGenerationContext(
if (context.memoryModel == MemoryModel.STRICT) if (context.memoryModel == MemoryModel.STRICT)
store(value, address) store(value, address)
else else
call(context.llvm.updateStackRefFunction, listOf(address, value)) call(llvm.updateStackRefFunction, listOf(address, value))
} else { } else {
call(context.llvm.updateHeapRefFunction, listOf(address, value)) call(llvm.updateHeapRefFunction, listOf(address, value))
} }
} }
@@ -659,8 +661,8 @@ internal abstract class FunctionGenerationContext(
"Attempt to switch the thread state when runtime is forbidden" "Attempt to switch the thread state when runtime is forbidden"
} }
when (state) { when (state) {
Native -> call(context.llvm.Kotlin_mm_switchThreadStateNative, emptyList()) Native -> call(llvm.Kotlin_mm_switchThreadStateNative, emptyList())
Runnable -> call(context.llvm.Kotlin_mm_switchThreadStateRunnable, emptyList()) Runnable -> call(llvm.Kotlin_mm_switchThreadStateRunnable, emptyList())
}.let {} // Force exhaustive. }.let {} // Force exhaustive.
} }
@@ -671,7 +673,7 @@ internal abstract class FunctionGenerationContext(
} }
fun memset(pointer: LLVMValueRef, value: Byte, size: Int, isVolatile: Boolean = false) = fun memset(pointer: LLVMValueRef, value: Byte, size: Int, isVolatile: Boolean = false) =
call(context.llvm.memsetFunction, call(llvm.memsetFunction,
listOf(pointer, listOf(pointer,
Int8(value).llvm, Int8(value).llvm,
Int32(size).llvm, Int32(size).llvm,
@@ -784,7 +786,7 @@ internal abstract class FunctionGenerationContext(
} }
fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef = fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime, resultSlot: LLVMValueRef?): LLVMValueRef =
call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime, resultSlot = resultSlot) call(llvm.allocInstanceFunction, listOf(typeInfo), lifetime, resultSlot = resultSlot)
fun allocInstance(irClass: IrClass, lifetime: Lifetime, stackLocalsManager: StackLocalsManager, resultSlot: LLVMValueRef?) = fun allocInstance(irClass: IrClass, lifetime: Lifetime, stackLocalsManager: StackLocalsManager, resultSlot: LLVMValueRef?) =
if (lifetime == Lifetime.STACK) if (lifetime == Lifetime.STACK)
@@ -806,13 +808,13 @@ internal abstract class FunctionGenerationContext(
return if (lifetime == Lifetime.STACK) { return if (lifetime == Lifetime.STACK) {
stackLocalsManager.allocArray(irClass, count) stackLocalsManager.allocArray(irClass, count)
} else { } else {
call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime, exceptionHandler, resultSlot = resultSlot) call(llvm.allocArrayFunction, listOf(typeInfo, count), lifetime, exceptionHandler, resultSlot = resultSlot)
} }
} }
fun unreachable(): LLVMValueRef? { fun unreachable(): LLVMValueRef? {
if (context.config.debug) { if (context.config.debug) {
call(context.llvm.llvmTrap, emptyList()) call(llvm.llvmTrap, emptyList())
} }
val res = LLVMBuildUnreachable(builder) val res = LLVMBuildUnreachable(builder)
currentPositionHolder.setAfterTerminator() currentPositionHolder.setAfterTerminator()
@@ -913,7 +915,7 @@ internal abstract class FunctionGenerationContext(
LLVMBuildExtractValue(builder, aggregate, index, name)!! LLVMBuildExtractValue(builder, aggregate, index, name)!!
fun gxxLandingpad(numClauses: Int, name: String = "", switchThreadState: Boolean = false): LLVMValueRef { fun gxxLandingpad(numClauses: Int, name: String = "", switchThreadState: Boolean = false): LLVMValueRef {
val personalityFunction = context.llvm.gxxPersonalityFunction.llvmValue val personalityFunction = llvm.gxxPersonalityFunction.llvmValue
// Type of `landingpad` instruction result (depends on personality function): // Type of `landingpad` instruction result (depends on personality function):
val landingpadType = structType(int8TypePtr, int32Type) val landingpadType = structType(int8TypePtr, int32Type)
@@ -923,7 +925,7 @@ internal abstract class FunctionGenerationContext(
if (switchThreadState) { if (switchThreadState) {
switchThreadState(Runnable) switchThreadState(Runnable)
} }
call(context.llvm.setCurrentFrameFunction, listOf(slotsPhi!!)) call(llvm.setCurrentFrameFunction, listOf(slotsPhi!!))
setCurrentFrameIsCalled = true setCurrentFrameIsCalled = true
return landingpad return landingpad
@@ -957,7 +959,7 @@ internal abstract class FunctionGenerationContext(
val typeId = extractValue(landingpad, 1) val typeId = extractValue(landingpad, 1)
val isKotlinException = icmpEq( val isKotlinException = icmpEq(
typeId, typeId,
call(context.llvm.llvmEhTypeidFor, listOf(kotlinExceptionRtti.llvm)) call(llvm.llvmEhTypeidFor, listOf(kotlinExceptionRtti.llvm))
) )
if (wrapExceptionMode) { if (wrapExceptionMode) {
@@ -968,7 +970,7 @@ internal abstract class FunctionGenerationContext(
appendingTo(foreignExceptionBlock) { appendingTo(foreignExceptionBlock) {
val isObjCException = icmpEq( val isObjCException = icmpEq(
typeId, typeId,
call(context.llvm.llvmEhTypeidFor, listOf(objcNSExceptionRtti.llvm)) call(llvm.llvmEhTypeidFor, listOf(objcNSExceptionRtti.llvm))
) )
condBr(isObjCException, forwardNativeExceptionBlock, fatalForeignExceptionBlock) condBr(isObjCException, forwardNativeExceptionBlock, fatalForeignExceptionBlock)
@@ -1001,12 +1003,12 @@ internal abstract class FunctionGenerationContext(
fun terminateWithCurrentException(landingpad: LLVMValueRef) { fun terminateWithCurrentException(landingpad: LLVMValueRef) {
val exceptionRecord = extractValue(landingpad, 0) val exceptionRecord = extractValue(landingpad, 0)
// So `std::terminate` is called from C++ catch block: // So `std::terminate` is called from C++ catch block:
call(context.llvm.cxaBeginCatchFunction, listOf(exceptionRecord)) call(llvm.cxaBeginCatchFunction, listOf(exceptionRecord))
terminate() terminate()
} }
fun terminate() { fun terminate() {
call(context.llvm.cxxStdTerminate, emptyList()) call(llvm.cxxStdTerminate, emptyList())
// Note: unreachable instruction to be generated here, but debug information is improper in this case. // Note: unreachable instruction to be generated here, but debug information is improper in this case.
val loopBlock = basicBlock("loop", position()?.start) val loopBlock = basicBlock("loop", position()?.start)
@@ -1044,14 +1046,14 @@ internal abstract class FunctionGenerationContext(
val exceptionRecord = extractValue(landingpadResult, 0, "er") val exceptionRecord = extractValue(landingpadResult, 0, "er")
// __cxa_begin_catch returns pointer to C++ exception object. // __cxa_begin_catch returns pointer to C++ exception object.
val beginCatch = context.llvm.cxaBeginCatchFunction val beginCatch = llvm.cxaBeginCatchFunction
val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord)) val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord))
// Pointer to Kotlin exception object: // Pointer to Kotlin exception object:
val exceptionPtr = call(context.llvm.Kotlin_getExceptionObject, listOf(exceptionRawPtr), Lifetime.GLOBAL) val exceptionPtr = call(llvm.Kotlin_getExceptionObject, listOf(exceptionRawPtr), Lifetime.GLOBAL)
// __cxa_end_catch performs some C++ cleanup, including calling `ExceptionObjHolder` class destructor. // __cxa_end_catch performs some C++ cleanup, including calling `ExceptionObjHolder` class destructor.
val endCatch = context.llvm.cxaEndCatchFunction val endCatch = llvm.cxaEndCatchFunction
call(endCatch, listOf()) call(endCatch, listOf())
return exceptionPtr return exceptionPtr
@@ -1061,20 +1063,20 @@ internal abstract class FunctionGenerationContext(
val exceptionRecord = extractValue(landingpadResult, 0, "er") val exceptionRecord = extractValue(landingpadResult, 0, "er")
// __cxa_begin_catch returns pointer to C++ exception object. // __cxa_begin_catch returns pointer to C++ exception object.
val exceptionRawPtr = call(context.llvm.cxaBeginCatchFunction, listOf(exceptionRecord)) val exceptionRawPtr = call(llvm.cxaBeginCatchFunction, listOf(exceptionRecord))
// This will take care of ARC - need to be done in the catching scope, i.e. before __cxa_end_catch // This will take care of ARC - need to be done in the catching scope, i.e. before __cxa_end_catch
val exception = call(context.ir.symbols.createForeignException.owner.llvmFunction, val exception = call(context.ir.symbols.createForeignException.owner.llvmFunction,
listOf(exceptionRawPtr), listOf(exceptionRawPtr),
Lifetime.GLOBAL, exceptionHandler) Lifetime.GLOBAL, exceptionHandler)
call(context.llvm.cxaEndCatchFunction, listOf()) call(llvm.cxaEndCatchFunction, listOf())
return exception return exception
} }
fun generateFrameCheck() { fun generateFrameCheck() {
if (!context.shouldOptimize()) if (!context.shouldOptimize())
call(context.llvm.checkCurrentFrameFunction, listOf(slotsPhi!!)) call(llvm.checkCurrentFrameFunction, listOf(slotsPhi!!))
} }
inline fun ifThenElse( inline fun ifThenElse(
@@ -1196,7 +1198,7 @@ internal abstract class FunctionGenerationContext(
} }
appendingTo(slowPathBB) { appendingTo(slowPathBB) {
val actualInterfaceTableSize = sub(kImmInt32Zero, interfaceTableSize) // -interfaceTableSize val actualInterfaceTableSize = sub(kImmInt32Zero, interfaceTableSize) // -interfaceTableSize
val slowValue = call(context.llvm.lookupInterfaceTableRecord, val slowValue = call(llvm.lookupInterfaceTableRecord,
listOf(interfaceTable, actualInterfaceTableSize, Int32(interfaceId).llvm)) listOf(interfaceTable, actualInterfaceTableSize, Int32(interfaceId).llvm))
br(takeResBB) br(takeResBB)
addPhiIncoming(resultPhi, currentBlock to slowValue) addPhiIncoming(resultPhi, currentBlock to slowValue)
@@ -1209,7 +1211,7 @@ internal abstract class FunctionGenerationContext(
assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr) assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr)
val typeInfoPtr: LLVMValueRef = if (irFunction.getObjCMethodInfo() != null) val typeInfoPtr: LLVMValueRef = if (irFunction.getObjCMethodInfo() != null)
call(context.llvm.getObjCKotlinTypeInfo, listOf(receiver)) call(llvm.getObjCKotlinTypeInfo, listOf(receiver))
else else
loadTypeInfo(receiver) loadTypeInfo(receiver)
@@ -1286,10 +1288,10 @@ internal abstract class FunctionGenerationContext(
// If thread local object is imported - access it via getter function. // If thread local object is imported - access it via getter function.
ObjectStorageKind.THREAD_LOCAL -> { ObjectStorageKind.THREAD_LOCAL -> {
val valueGetterName = irClass.threadLocalObjectStorageGetterSymbolName val valueGetterName = irClass.threadLocalObjectStorageGetterSymbolName
val valueGetterFunction = LLVMGetNamedFunction(context.llvmModule, valueGetterName) val valueGetterFunction = LLVMGetNamedFunction(llvm.module, valueGetterName)
?: addLlvmFunctionWithDefaultAttributes( ?: addLlvmFunctionWithDefaultAttributes(
context, context,
context.llvmModule!!, llvm.module,
valueGetterName, valueGetterName,
functionType(kObjHeaderPtrPtr, false) functionType(kObjHeaderPtrPtr, false)
) )
@@ -1311,7 +1313,7 @@ internal abstract class FunctionGenerationContext(
} }
} else { } else {
// Local globals and thread locals storage info is stored in our map. // Local globals and thread locals storage info is stored in our map.
val singleton = context.llvmDeclarations.forSingleton(irClass) val singleton = llvmDeclarations.forSingleton(irClass)
val instanceAddress = singleton.instanceStorage val instanceAddress = singleton.instanceStorage
instanceAddress.getAddress(this) instanceAddress.getAddress(this)
} }
@@ -1319,14 +1321,14 @@ internal abstract class FunctionGenerationContext(
when (storageKind) { when (storageKind) {
ObjectStorageKind.SHARED -> ObjectStorageKind.SHARED ->
// If current file used a shared object, make file's (de)initializer function deinit it. // If current file used a shared object, make file's (de)initializer function deinit it.
context.llvm.globalSharedObjects += objectPtr llvm.globalSharedObjects += objectPtr
ObjectStorageKind.THREAD_LOCAL -> ObjectStorageKind.THREAD_LOCAL ->
// If current file used locally defined TLS objects, make file's (de)initializer function // If current file used locally defined TLS objects, make file's (de)initializer function
// init and deinit TLS. // init and deinit TLS.
// Note: for exported TLS objects a getter is generated in a file they're defined in. Which // Note: for exported TLS objects a getter is generated in a file they're defined in. Which
// adds TLS init and deinit to that file's (de)initializer function. // adds TLS init and deinit to that file's (de)initializer function.
if (!isExternal(irClass)) if (!isExternal(irClass))
context.llvm.fileUsesThreadLocalObjects = true llvm.fileUsesThreadLocalObjects = true
ObjectStorageKind.PERMANENT -> { /* Do nothing, no need to free such an instance. */ } ObjectStorageKind.PERMANENT -> { /* Do nothing, no need to free such an instance. */ }
} }
@@ -1346,9 +1348,9 @@ internal abstract class FunctionGenerationContext(
val ctor = codegen.llvmFunction(defaultConstructor).llvmValue val ctor = codegen.llvmFunction(defaultConstructor).llvmValue
val initFunction = val initFunction =
if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) { if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) {
context.llvm.initSingletonFunction llvm.initSingletonFunction
} else { } else {
context.llvm.initThreadLocalSingleton llvm.initThreadLocalSingleton
} }
val args = listOf(objectPtr, typeInfo, ctor) val args = listOf(objectPtr, typeInfo, ctor)
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler, resultSlot = resultSlot) val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler, resultSlot = resultSlot)
@@ -1387,7 +1389,7 @@ internal abstract class FunctionGenerationContext(
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName() val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
val objCClass = getObjCClass(name, llvmSymbolOrigin) val objCClass = getObjCClass(name, llvmSymbolOrigin)
val getClass = context.llvm.externalFunction(LlvmFunctionProto( val getClass = llvm.externalFunction(LlvmFunctionProto(
"object_getClass", "object_getClass",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
@@ -1411,7 +1413,7 @@ internal abstract class FunctionGenerationContext(
return this.ifThenElse(storedClassIsNotNull, storedClass) { return this.ifThenElse(storedClassIsNotNull, storedClass) {
call( call(
context.llvm.createKotlinObjCClass, llvm.createKotlinObjCClass,
listOf(classInfo), listOf(classInfo),
exceptionHandler = exceptionHandler exceptionHandler = exceptionHandler
) )
@@ -1420,7 +1422,7 @@ internal abstract class FunctionGenerationContext(
} }
fun getObjCClass(binaryName: String, llvmSymbolOrigin: CompiledKlibModuleOrigin): LLVMValueRef { fun getObjCClass(binaryName: String, llvmSymbolOrigin: CompiledKlibModuleOrigin): LLVMValueRef {
context.llvm.imports.add(llvmSymbolOrigin) llvm.imports.add(llvmSymbolOrigin)
return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm) return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
} }
@@ -1470,7 +1472,7 @@ internal abstract class FunctionGenerationContext(
val expr = longArrayOf(DwarfOp.DW_OP_plus_uconst.value, val expr = longArrayOf(DwarfOp.DW_OP_plus_uconst.value,
runtime.pointerSize * slot.toLong()).toCValues() runtime.pointerSize * slot.toLong()).toCValues()
DIInsertDeclaration( DIInsertDeclaration(
builder = codegen.context.debugInfo.builder, builder = codegen.context.generationState.debugInfo.builder,
value = slots, value = slots,
localVariable = variable.localVariable, localVariable = variable.localVariable,
location = variable.location, location = variable.location,
@@ -1506,18 +1508,18 @@ internal abstract class FunctionGenerationContext(
startLocation?.let { debugLocation(it, it) } startLocation?.let { debugLocation(it, it) }
if (needsRuntimeInit || switchToRunnable) { if (needsRuntimeInit || switchToRunnable) {
check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" } check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" }
call(context.llvm.initRuntimeIfNeeded, emptyList()) call(llvm.initRuntimeIfNeeded, emptyList())
} }
if (switchToRunnable) { if (switchToRunnable) {
switchThreadState(Runnable) switchThreadState(Runnable)
} }
if (needSlots || needCleanupLandingpadAndLeaveFrame) { if (needSlots || needCleanupLandingpadAndLeaveFrame) {
call(context.llvm.enterFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm)) call(llvm.enterFrameFunction, listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
} else { } else {
check(!setCurrentFrameIsCalled) check(!setCurrentFrameIsCalled)
} }
if (context.memoryModel == MemoryModel.EXPERIMENTAL && !forbidRuntime) { if (context.memoryModel == MemoryModel.EXPERIMENTAL && !forbidRuntime) {
call(context.llvm.Kotlin_mm_safePointFunctionPrologue, emptyList()) call(llvm.Kotlin_mm_safePointFunctionPrologue, emptyList())
} }
resetDebugLocation() resetDebugLocation()
br(entryBb) br(entryBb)
@@ -1711,7 +1713,7 @@ internal abstract class FunctionGenerationContext(
private fun releaseVars() { private fun releaseVars() {
if (needCleanupLandingpadAndLeaveFrame || needSlots) { if (needCleanupLandingpadAndLeaveFrame || needSlots) {
check(!forbidRuntime) { "Attempt to leave a frame where runtime usage is forbidden" } check(!forbidRuntime) { "Attempt to leave a frame where runtime usage is forbidden" }
call(context.llvm.leaveFrameFunction, call(llvm.leaveFrameFunction,
listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm)) listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
} }
if (!stackLocalsManager.isEmpty() && context.memoryModel != MemoryModel.EXPERIMENTAL) { if (!stackLocalsManager.isEmpty() && context.memoryModel != MemoryModel.EXPERIMENTAL) {
@@ -7,17 +7,14 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.toKString import kotlinx.cinterop.toKString
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.serialization.mangle.MangleConstant
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
import org.jetbrains.kotlin.backend.konan.llvm.KonanBinaryInterface.functionName
import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin import org.jetbrains.kotlin.descriptors.konan.CompiledKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.CurrentKlibModuleOrigin import org.jetbrains.kotlin.descriptors.konan.CurrentKlibModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -143,7 +140,7 @@ internal interface ContextUtils : RuntimeAware {
val context: Context val context: Context
override val runtime: Runtime override val runtime: Runtime
get() = context.llvm.runtime get() = context.generationState.llvm.runtime
val argumentAbiInfo: TargetAbiInfo val argumentAbiInfo: TargetAbiInfo
get() = context.targetAbiInfo get() = context.targetAbiInfo
@@ -156,8 +153,11 @@ internal interface ContextUtils : RuntimeAware {
val llvmTargetData: LLVMTargetDataRef val llvmTargetData: LLVMTargetDataRef
get() = runtime.targetData get() = runtime.targetData
val llvm: Llvm
get() = context.generationState.llvm
val staticData: KotlinStaticData val staticData: KotlinStaticData
get() = context.llvm.staticData get() = context.generationState.llvm.staticData
/** /**
* TODO: maybe it'd be better to replace with [IrDeclaration::isEffectivelyExternal()], * TODO: maybe it'd be better to replace with [IrDeclaration::isEffectivelyExternal()],
@@ -190,10 +190,10 @@ internal interface ContextUtils : RuntimeAware {
this.computePrivateSymbolName(containerName) this.computePrivateSymbolName(containerName)
} }
val proto = LlvmFunctionProto(this, symbolName, this@ContextUtils) val proto = LlvmFunctionProto(this, symbolName, this@ContextUtils)
context.llvm.externalFunction(proto) llvm.externalFunction(proto)
} }
} else { } else {
context.llvmDeclarations.forFunctionOrNull(this) context.generationState.llvmDeclarations.forFunctionOrNull(this)
} }
} }
@@ -218,7 +218,7 @@ internal interface ContextUtils : RuntimeAware {
constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType, constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType,
origin = this.llvmSymbolOrigin)) origin = this.llvmSymbolOrigin))
} else { } else {
context.llvmDeclarations.forClass(this).typeInfo context.generationState.llvmDeclarations.forClass(this).typeInfo
} }
} }
@@ -271,10 +271,10 @@ internal class InitializersGenerationState {
&& moduleGlobalInitializers.isEmpty() && moduleThreadLocalInitializers.isEmpty() && moduleGlobalInitializers.isEmpty() && moduleThreadLocalInitializers.isEmpty()
} }
internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : RuntimeAware { internal class Llvm(val context: Context, val module: LLVMModuleRef) : RuntimeAware {
private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable { private fun importFunction(name: String, otherModule: LLVMModuleRef): LlvmCallable {
if (LLVMGetNamedFunction(llvmModule, name) != null) { if (LLVMGetNamedFunction(module, name) != null) {
throw IllegalArgumentException("function $name already exists") throw IllegalArgumentException("function $name already exists")
} }
@@ -283,7 +283,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
val attributesCopier = LlvmFunctionAttributeProvider.copyFromExternal(externalFunction) val attributesCopier = LlvmFunctionAttributeProvider.copyFromExternal(externalFunction)
val functionType = getFunctionType(externalFunction) val functionType = getFunctionType(externalFunction)
val function = LLVMAddFunction(llvmModule, name, functionType)!! val function = LLVMAddFunction(module, name, functionType)!!
attributesCopier.addFunctionAttributes(function) attributesCopier.addFunctionAttributes(function)
@@ -291,13 +291,13 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
} }
private fun importGlobal(name: String, otherModule: LLVMModuleRef): LLVMValueRef { private fun importGlobal(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
if (LLVMGetNamedGlobal(llvmModule, name) != null) { if (LLVMGetNamedGlobal(module, name) != null) {
throw IllegalArgumentException("global $name already exists") throw IllegalArgumentException("global $name already exists")
} }
val externalGlobal = LLVMGetNamedGlobal(otherModule, name)!! val externalGlobal = LLVMGetNamedGlobal(otherModule, name)!!
val globalType = getGlobalType(externalGlobal) val globalType = getGlobalType(externalGlobal)
val global = LLVMAddGlobal(llvmModule, globalType, name)!! val global = LLVMAddGlobal(module, globalType, name)!!
return global return global
} }
@@ -308,7 +308,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
} }
private fun llvmIntrinsic(name: String, type: LLVMTypeRef, vararg attributes: String): LlvmCallable { private fun llvmIntrinsic(name: String, type: LLVMTypeRef, vararg attributes: String): LlvmCallable {
val result = LLVMAddFunction(llvmModule, name, type)!! val result = LLVMAddFunction(module, name, type)!!
attributes.forEach { attributes.forEach {
val kindId = getLlvmAttributeKindId(it) val kindId = getLlvmAttributeKindId(it)
addLlvmFunctionEnumAttribute(result, kindId) addLlvmFunctionEnumAttribute(result, kindId)
@@ -318,7 +318,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable { internal fun externalFunction(llvmFunctionProto: LlvmFunctionProto): LlvmCallable {
this.imports.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent) this.imports.add(llvmFunctionProto.origin, onlyBitcode = llvmFunctionProto.independent)
val found = LLVMGetNamedFunction(llvmModule, llvmFunctionProto.name) val found = LLVMGetNamedFunction(module, llvmFunctionProto.name)
if (found != null) { if (found != null) {
assert(getFunctionType(found) == llvmFunctionProto.llvmFunctionType) { assert(getFunctionType(found) == llvmFunctionProto.llvmFunctionType) {
"Expected: ${LLVMPrintTypeToString(llvmFunctionProto.llvmFunctionType)!!.toKString()} " + "Expected: ${LLVMPrintTypeToString(llvmFunctionProto.llvmFunctionType)!!.toKString()} " +
@@ -327,13 +327,13 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
assert(LLVMGetLinkage(found) == LLVMLinkage.LLVMExternalLinkage) assert(LLVMGetLinkage(found) == LLVMLinkage.LLVMExternalLinkage)
return LlvmCallable(found, llvmFunctionProto) return LlvmCallable(found, llvmFunctionProto)
} else { } else {
val function = addLlvmFunctionWithDefaultAttributes(context, llvmModule, llvmFunctionProto.name, llvmFunctionProto.llvmFunctionType) val function = addLlvmFunctionWithDefaultAttributes(context, module, llvmFunctionProto.name, llvmFunctionProto.llvmFunctionType)
llvmFunctionProto.addFunctionAttributes(function) llvmFunctionProto.addFunctionAttributes(function)
return LlvmCallable(function, llvmFunctionProto) return LlvmCallable(function, llvmFunctionProto)
} }
} }
val imports get() = context.llvmImports val imports get() = context.generationState.llvmImports
class ImportsImpl(private val context: Context) : LlvmImports { class ImportsImpl(private val context: Context) : LlvmImports {
@@ -440,17 +440,17 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
val additionalProducedBitcodeFiles = mutableListOf<String>() val additionalProducedBitcodeFiles = mutableListOf<String>()
val staticData = KotlinStaticData(context) val staticData = KotlinStaticData(context, module)
private val target = context.config.target private val target = context.config.target
override val runtime get() = context.runtime override val runtime get() = context.generationState.runtime
val targetTriple = runtime.target val targetTriple = runtime.target
init { init {
LLVMSetDataLayout(llvmModule, runtime.dataLayout) LLVMSetDataLayout(module, runtime.dataLayout)
LLVMSetTarget(llvmModule, targetTriple) LLVMSetTarget(module, targetTriple)
} }
private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule) private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule)
@@ -533,7 +533,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
var tlsCount = 0 var tlsCount = 0
val tlsKey by lazy { val tlsKey by lazy {
val global = LLVMAddGlobal(llvmModule, kInt8Ptr, "__KonanTlsKey")!! val global = LLVMAddGlobal(module, kInt8Ptr, "__KonanTlsKey")!!
LLVMSetLinkage(global, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(global, LLVMLinkage.LLVMInternalLinkage)
LLVMSetInitializer(global, LLVMConstNull(kInt8Ptr)) LLVMSetInitializer(global, LLVMConstNull(kInt8Ptr))
global global
@@ -601,7 +601,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) : Runti
val boxCacheGlobals = mutableMapOf<BoxCache, StaticData.Global>() val boxCacheGlobals = mutableMapOf<BoxCache, StaticData.Global>()
val runtimeAnnotationMap by lazy { val runtimeAnnotationMap by lazy {
context.llvm.staticData.getGlobal("llvm.global.annotations") staticData.getGlobal("llvm.global.annotations")
?.getInitializer() ?.getInitializer()
?.let { getOperands(it) } ?.let { getOperands(it) }
?.groupBy( ?.groupBy(
@@ -72,14 +72,14 @@ internal class DebugInfo internal constructor(override val context: Context):Con
var types = mutableMapOf<IrType, DITypeOpaqueRef>() var types = mutableMapOf<IrType, DITypeOpaqueRef>()
val llvmTypes = mapOf<IrType, LLVMTypeRef>( val llvmTypes = mapOf<IrType, LLVMTypeRef>(
context.irBuiltIns.booleanType to context.llvm.llvmInt8, context.irBuiltIns.booleanType to llvm.llvmInt8,
context.irBuiltIns.byteType to context.llvm.llvmInt8, context.irBuiltIns.byteType to llvm.llvmInt8,
context.irBuiltIns.charType to context.llvm.llvmInt16, context.irBuiltIns.charType to llvm.llvmInt16,
context.irBuiltIns.shortType to context.llvm.llvmInt16, context.irBuiltIns.shortType to llvm.llvmInt16,
context.irBuiltIns.intType to context.llvm.llvmInt32, context.irBuiltIns.intType to llvm.llvmInt32,
context.irBuiltIns.longType to context.llvm.llvmInt64, context.irBuiltIns.longType to llvm.llvmInt64,
context.irBuiltIns.floatType to context.llvm.llvmFloat, context.irBuiltIns.floatType to llvm.llvmFloat,
context.irBuiltIns.doubleType to context.llvm.llvmDouble) context.irBuiltIns.doubleType to llvm.llvmDouble)
val llvmTypeSizes = llvmTypes.map { it.key to LLVMSizeOfTypeInBits(llvmTargetData, it.value) }.toMap() val llvmTypeSizes = llvmTypes.map { it.key to LLVMSizeOfTypeInBits(llvmTargetData, it.value) }.toMap()
val llvmTypeAlignments = llvmTypes.map {it.key to LLVMPreferredAlignmentOfType(llvmTargetData, it.value)}.toMap() val llvmTypeAlignments = llvmTypes.map {it.key to LLVMPreferredAlignmentOfType(llvmTargetData, it.value)}.toMap()
val otherLlvmType = LLVMPointerType(int64Type, 0)!! val otherLlvmType = LLVMPointerType(int64Type, 0)!!
@@ -132,59 +132,58 @@ internal fun String?.toFileAndFolder(context: Context):FileAndFolder {
} }
internal fun generateDebugInfoHeader(context: Context) { internal fun generateDebugInfoHeader(context: Context) {
if (context.shouldContainAnyDebugInfo()) { val debugInfo = context.generationState.debugInfo
val path = context.config.outputFile val module = context.generationState.llvm.module
.toFileAndFolder(context) val path = context.generationState.outputFile.toFileAndFolder(context)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
context.debugInfo.module = DICreateModule( debugInfo.module = DICreateModule(
builder = context.debugInfo.builder, builder = debugInfo.builder,
scope = null, scope = null,
name = path.path(), name = path.path(),
configurationMacro = "", configurationMacro = "",
includePath = "", includePath = "",
iSysRoot = "") iSysRoot = "")
/* TODO: figure out what here 2 means: /* TODO: figure out what here 2 means:
* *
* 0:b-backend-dwarf:minamoto@minamoto-osx(0)# cat /dev/null | clang -xc -S -emit-llvm -g -o - - * 0:b-backend-dwarf:minamoto@minamoto-osx(0)# cat /dev/null | clang -xc -S -emit-llvm -g -o - -
* ; ModuleID = '-' * ; ModuleID = '-'
* source_filename = "-" * source_filename = "-"
* target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" * target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
* target triple = "x86_64-apple-macosx10.12.0" * target triple = "x86_64-apple-macosx10.12.0"
* *
* !llvm.dbg.cu = !{!0} * !llvm.dbg.cu = !{!0}
* !llvm.module.flags = !{!3, !4, !5} * !llvm.module.flags = !{!3, !4, !5}
* !llvm.ident = !{!6} * !llvm.ident = !{!6}
* *
* !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Apple LLVM version 8.0.0 (clang-800.0.38)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) * !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Apple LLVM version 8.0.0 (clang-800.0.38)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
* !1 = !DIFile(filename: "-", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf") * !1 = !DIFile(filename: "-", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf")
* !2 = !{} * !2 = !{}
* !3 = !{i32 2, !"Dwarf Version", i32 2} ; <- * !3 = !{i32 2, !"Dwarf Version", i32 2} ; <-
* !4 = !{i32 2, !"Debug Info Version", i32 700000003} ; <- * !4 = !{i32 2, !"Debug Info Version", i32 700000003} ; <-
* !5 = !{i32 1, !"PIC Level", i32 2} * !5 = !{i32 1, !"PIC Level", i32 2}
* !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.38)"} * !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.38)"}
*/ */
val llvmTwo = Int32(2).llvm val llvmTwo = Int32(2).llvm
val dwarfVersion = node(llvmTwo, DWARF.dwarfVersionMetaDataNodeName, Int32(DWARF.dwarfVersion(context.config)).llvm) val dwarfVersion = node(llvmTwo, DWARF.dwarfVersionMetaDataNodeName, Int32(DWARF.dwarfVersion(context.config)).llvm)
val nodeDebugInfoVersion = node(llvmTwo, DWARF.dwarfDebugInfoMetaDataNodeName, Int32(DWARF.debugInfoVersion).llvm) val nodeDebugInfoVersion = node(llvmTwo, DWARF.dwarfDebugInfoMetaDataNodeName, Int32(DWARF.debugInfoVersion).llvm)
val llvmModuleFlags = "llvm.module.flags" val llvmModuleFlags = "llvm.module.flags"
LLVMAddNamedMetadataOperand(context.llvmModule, llvmModuleFlags, dwarfVersion) LLVMAddNamedMetadataOperand(module, llvmModuleFlags, dwarfVersion)
LLVMAddNamedMetadataOperand(context.llvmModule, llvmModuleFlags, nodeDebugInfoVersion) LLVMAddNamedMetadataOperand(module, llvmModuleFlags, nodeDebugInfoVersion)
val objHeaderType = DICreateStructType( val objHeaderType = DICreateStructType(
refBuilder = context.debugInfo.builder, refBuilder = debugInfo.builder,
// TODO: here should be DIFile as scope. // TODO: here should be DIFile as scope.
scope = null, scope = null,
name = "ObjHeader", name = "ObjHeader",
file = null, file = null,
lineNumber = 0, lineNumber = 0,
sizeInBits = 0, sizeInBits = 0,
alignInBits = 0, alignInBits = 0,
flags = DWARF.flagsForwardDeclaration, flags = DWARF.flagsForwardDeclaration,
derivedFrom = null, derivedFrom = null,
elements = null, elements = null,
elementsCount = 0, elementsCount = 0,
refPlace = null).cast<DITypeOpaqueRef>() refPlace = null).cast<DITypeOpaqueRef>()
context.debugInfo.objHeaderPointerType = dwarfPointerType(context, objHeaderType) debugInfo.objHeaderPointerType = dwarfPointerType(context, objHeaderType)
}
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -193,7 +192,7 @@ internal fun IrType.dwarfType(context: Context, targetData: LLVMTargetDataRef):
this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(context, targetData, this.render(), llvmType(context), encoding().value.toInt()) this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(context, targetData, this.render(), llvmType(context), encoding().value.toInt())
else -> { else -> {
return when { return when {
classOrNull != null || this.isTypeParameter() -> context.debugInfo.objHeaderPointerType!! classOrNull != null || this.isTypeParameter() -> context.generationState.debugInfo.objHeaderPointerType!!
else -> TODO("$this: Does this case really exist?") else -> TODO("$this: Does this case really exist?")
} }
} }
@@ -201,13 +200,13 @@ internal fun IrType.dwarfType(context: Context, targetData: LLVMTargetDataRef):
} }
internal fun IrType.diType(context: Context, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef = internal fun IrType.diType(context: Context, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
context.debugInfo.types.getOrPut(this) { context.generationState.debugInfo.types.getOrPut(this) {
dwarfType(context, llvmTargetData) dwarfType(context, llvmTargetData)
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typeName:String, type:LLVMTypeRef, encoding:Int) = DICreateBasicType( private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typeName:String, type:LLVMTypeRef, encoding:Int) = DICreateBasicType(
context.debugInfo.builder, typeName, context.generationState.debugInfo.builder, typeName,
LLVMSizeOfTypeInBits(targetData, type), LLVMSizeOfTypeInBits(targetData, type),
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef
@@ -217,21 +216,23 @@ internal val IrFunction.types:List<IrType>
return listOf(returnType, *parameters.toTypedArray()) return listOf(returnType, *parameters.toTypedArray())
} }
internal fun IrType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize) internal fun IrType.size(context:Context) = context.generationState.debugInfo.llvmTypeSizes.getOrDefault(this, context.generationState.debugInfo.otherTypeSize)
internal fun IrType.alignment(context:Context) = context.debugInfo.llvmTypeAlignments.getOrDefault(this, context.debugInfo.otherTypeAlignment).toLong() internal fun IrType.alignment(context:Context) = context.generationState.debugInfo.llvmTypeAlignments.getOrDefault(this, context.generationState.debugInfo.otherTypeAlignment).toLong()
internal fun IrType.llvmType(context:Context): LLVMTypeRef = context.debugInfo.llvmTypes.getOrElse(this) { internal fun IrType.llvmType(context:Context): LLVMTypeRef = with(context.generationState) {
when(computePrimitiveBinaryTypeOrNull()) { debugInfo.llvmTypes.getOrElse(this@llvmType) {
PrimitiveBinaryType.BOOLEAN -> context.llvm.llvmInt1 when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.BYTE -> context.llvm.llvmInt8 PrimitiveBinaryType.BOOLEAN -> llvm.llvmInt1
PrimitiveBinaryType.SHORT -> context.llvm.llvmInt16 PrimitiveBinaryType.BYTE -> llvm.llvmInt8
PrimitiveBinaryType.INT -> context.llvm.llvmInt32 PrimitiveBinaryType.SHORT -> llvm.llvmInt16
PrimitiveBinaryType.LONG -> context.llvm.llvmInt64 PrimitiveBinaryType.INT -> llvm.llvmInt32
PrimitiveBinaryType.FLOAT -> context.llvm.llvmFloat PrimitiveBinaryType.LONG -> llvm.llvmInt64
PrimitiveBinaryType.DOUBLE -> context.llvm.llvmDouble PrimitiveBinaryType.FLOAT -> llvm.llvmFloat
PrimitiveBinaryType.VECTOR128 -> context.llvm.llvmVector128 PrimitiveBinaryType.DOUBLE -> llvm.llvmDouble
else -> context.debugInfo.otherLlvmType PrimitiveBinaryType.VECTOR128 -> llvm.llvmVector128
else -> debugInfo.otherLlvmType
}
} }
} }
@@ -256,7 +257,7 @@ internal fun IrFunction.subroutineType(context: Context, llvmTargetData: LLVMTar
internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, types: List<IrType>): DISubroutineTypeRef { internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, types: List<IrType>): DISubroutineTypeRef {
return memScoped { return memScoped {
DICreateSubroutineType(context.debugInfo.builder, allocArrayOf( DICreateSubroutineType(context.generationState.debugInfo.builder, allocArrayOf(
types.map { it.diType(context, llvmTargetData) }), types.map { it.diType(context, llvmTargetData) }),
types.size)!! types.size)!!
} }
@@ -264,24 +265,24 @@ internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef,
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun dwarfPointerType(context: Context, type: DITypeOpaqueRef) = private fun dwarfPointerType(context: Context, type: DITypeOpaqueRef) =
DICreatePointerType(context.debugInfo.builder, type) as DITypeOpaqueRef DICreatePointerType(context.generationState.debugInfo.builder, type) as DITypeOpaqueRef
internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): LocationInfo? { internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): LocationInfo? {
if (!context.shouldContainLocationDebugInfo()) { if (!context.shouldContainLocationDebugInfo()) {
return null return null
} }
val file = context.debugInfo.compilerGeneratedFile val file = context.generationState.debugInfo.compilerGeneratedFile
// TODO: can we share the scope among all bridges? // TODO: can we share the scope among all bridges?
val scope: DIScopeOpaqueRef = DICreateFunction( val scope: DIScopeOpaqueRef = DICreateFunction(
builder = context.debugInfo.builder, builder = context.generationState.debugInfo.builder,
scope = file.reinterpret(), scope = file.reinterpret(),
name = function.name, name = function.name,
linkageName = function.name, linkageName = function.name,
file = file, file = file,
lineNo = 0, lineNo = 0,
type = subroutineType(context, context.llvm.runtime.targetData, emptyList()), // TODO: use proper type. type = subroutineType(context, context.generationState.runtime.targetData, emptyList()), // TODO: use proper type.
isLocal = 0, isLocal = 0,
isDefinition = 1, isDefinition = 1,
scopeLine = 0 scopeLine = 0
@@ -168,7 +168,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
IntrinsicType.IMMUTABLE_BLOB -> { IntrinsicType.IMMUTABLE_BLOB -> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val arg = callSite.getValueArgument(0) as IrConst<String> val arg = callSite.getValueArgument(0) as IrConst<String>
context.llvm.staticData.createImmutableBlob(arg) codegen.llvm.staticData.createImmutableBlob(arg)
} }
IntrinsicType.OBJC_GET_SELECTOR -> { IntrinsicType.OBJC_GET_SELECTOR -> {
val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String
@@ -422,7 +422,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
or(bitsWithPadding, preservedBits) or(bitsWithPadding, preservedBits)
} }
llvm.LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned() LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned()
return codegen.theUnitInstanceRef.llvm return codegen.theUnitInstanceRef.llvm
} }
@@ -460,14 +460,14 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
val functionParameterTypes = listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)) val functionParameterTypes = listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr))
val libobjc = context.standardLlvmSymbolsOrigin val libobjc = context.standardLlvmSymbolsOrigin
val normalMessenger = context.llvm.externalFunction(LlvmFunctionProto( val normalMessenger = codegen.llvm.externalFunction(LlvmFunctionProto(
"objc_msgSend$messengerNameSuffix", "objc_msgSend$messengerNameSuffix",
functionReturnType, functionReturnType,
functionParameterTypes, functionParameterTypes,
isVararg = true, isVararg = true,
origin = libobjc origin = libobjc
)) ))
val superMessenger = context.llvm.externalFunction(LlvmFunctionProto( val superMessenger = codegen.llvm.externalFunction(LlvmFunctionProto(
"objc_msgSendSuper$messengerNameSuffix", "objc_msgSendSuper$messengerNameSuffix",
functionReturnType, functionReturnType,
functionParameterTypes, functionParameterTypes,
@@ -491,13 +491,13 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
assert (first.type == second.type) { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" } assert (first.type == second.type) { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" }
return when (val typeKind = LLVMGetTypeKind(first.type)) { return when (val typeKind = LLVMGetTypeKind(first.type)) {
llvm.LLVMTypeKind.LLVMFloatTypeKind, llvm.LLVMTypeKind.LLVMDoubleTypeKind, LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind,
LLVMTypeKind.LLVMVectorTypeKind -> { LLVMTypeKind.LLVMVectorTypeKind -> {
// TODO LLVM API does not provide guarantee for LLVMIntTypeInContext availability for longer types; consider meaningful diag message instead of NPE // TODO LLVM API does not provide guarantee for LLVMIntTypeInContext availability for longer types; consider meaningful diag message instead of NPE
val integerType = LLVMIntTypeInContext(llvmContext, first.type.sizeInBits())!! val integerType = LLVMIntTypeInContext(llvmContext, first.type.sizeInBits())!!
icmpEq(bitcast(integerType, first), bitcast(integerType, second)) icmpEq(bitcast(integerType, first), bitcast(integerType, second))
} }
llvm.LLVMTypeKind.LLVMIntegerTypeKind, llvm.LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(first, second) LLVMTypeKind.LLVMIntegerTypeKind, LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(first, second)
else -> error(typeKind) else -> error(typeKind)
} }
} }
@@ -205,6 +205,9 @@ private interface CodeContext {
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrElement, Lifetime>) : IrElementVisitorVoid { internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrElement, Lifetime>) : IrElementVisitorVoid {
private val llvm = context.generationState.llvm
private val debugInfo: DebugInfo
get() = context.generationState.debugInfo
val codegen = CodeGenerator(context) val codegen = CodeGenerator(context)
@@ -343,12 +346,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) { private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) {
val initializer = irField.initializer ?: return val initializer = irField.initializer ?: return
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this) val address = context.generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
storeAny(evaluateExpression(initializer.expression), address, false) storeAny(evaluateExpression(initializer.expression), address, false)
} }
private fun FunctionGenerationContext.initGlobalField(irField: IrField) { private fun FunctionGenerationContext.initGlobalField(irField: IrField) {
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this) val address = context.generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val initialValue = if (irField.hasNonConstInitializer) { val initialValue = if (irField.hasNonConstInitializer) {
val initialization = evaluateExpression(irField.initializer!!.expression) val initialization = evaluateExpression(irField.initializer!!.expression)
if (irField.shouldBeFrozen(context)) if (irField.shouldBeFrozen(context))
@@ -358,7 +361,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
null null
} }
if (irField.needsGCRegistration(context)) { if (irField.needsGCRegistration(context)) {
call(context.llvm.initAndRegisterGlobalFunction, listOf(address, initialValue call(llvm.initAndRegisterGlobalFunction, listOf(address, initialValue
?: kNullObjHeaderPtr)) ?: kNullObjHeaderPtr))
} else if (initialValue != null) { } else if (initialValue != null) {
storeAny(initialValue, address, false) storeAny(initialValue, address, false)
@@ -367,20 +370,20 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun runAndProcessInitializers(konanLibrary: KotlinLibrary?, f: () -> Unit) { private fun runAndProcessInitializers(konanLibrary: KotlinLibrary?, f: () -> Unit) {
// TODO: collect those two in one place. // TODO: collect those two in one place.
context.llvm.fileUsesThreadLocalObjects = false llvm.fileUsesThreadLocalObjects = false
context.llvm.globalSharedObjects.clear() llvm.globalSharedObjects.clear()
context.llvm.initializersGenerationState.reset() llvm.initializersGenerationState.reset()
f() f()
context.llvm.initializersGenerationState.globalInitFunction?.let { fileInitFunction -> llvm.initializersGenerationState.globalInitFunction?.let { fileInitFunction ->
generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) { generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) {
using(FunctionScope(fileInitFunction, this)) { using(FunctionScope(fileInitFunction, this)) {
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext) val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
using(parameterScope) usingParameterScope@{ using(parameterScope) usingParameterScope@{
using(VariableScope()) usingVariableScope@{ using(VariableScope()) usingVariableScope@{
context.llvm.initializersGenerationState.topLevelFields llvm.initializersGenerationState.topLevelFields
.filter { it.storageKind(context) != FieldStorageKind.THREAD_LOCAL } .filter { it.storageKind(context) != FieldStorageKind.THREAD_LOCAL }
.filterNot { it.shouldBeInitializedEagerly } .filterNot { it.shouldBeInitializedEagerly }
.forEach { initGlobalField(it) } .forEach { initGlobalField(it) }
@@ -391,13 +394,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
} }
context.llvm.initializersGenerationState.threadLocalInitFunction?.let { fileInitFunction -> llvm.initializersGenerationState.threadLocalInitFunction?.let { fileInitFunction ->
generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) { generateFunction(codegen, fileInitFunction, fileInitFunction.location(start = true), fileInitFunction.location(start = false)) {
using(FunctionScope(fileInitFunction, this)) { using(FunctionScope(fileInitFunction, this)) {
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext) val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
using(parameterScope) usingParameterScope@{ using(parameterScope) usingParameterScope@{
using(VariableScope()) usingVariableScope@{ using(VariableScope()) usingVariableScope@{
context.llvm.initializersGenerationState.topLevelFields llvm.initializersGenerationState.topLevelFields
.filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL } .filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
.filterNot { it.shouldBeInitializedEagerly } .filterNot { it.shouldBeInitializedEagerly }
.forEach { initThreadLocalField(it) } .forEach { initThreadLocalField(it) }
@@ -408,14 +411,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
} }
if (!context.llvm.fileUsesThreadLocalObjects && context.llvm.globalSharedObjects.isEmpty() if (!llvm.fileUsesThreadLocalObjects && llvm.globalSharedObjects.isEmpty()
&& context.llvm.initializersGenerationState.isEmpty()) { && llvm.initializersGenerationState.isEmpty()) {
return return
} }
// Create global initialization records. // Create global initialization records.
val initNode = createInitNode(createInitBody()) val initNode = createInitNode(createInitBody())
context.llvm.irStaticInitializers.add(IrStaticInitializer(konanLibrary, createInitCtor(initNode))) llvm.irStaticInitializers.add(IrStaticInitializer(konanLibrary, createInitCtor(initNode)))
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -441,8 +444,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.coverage.writeRegionInfo() context.coverage.writeRegionInfo()
overrideRuntimeGlobals() overrideRuntimeGlobals()
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals) appendLlvmUsed("llvm.used", llvm.usedFunctions + llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals) appendLlvmUsed("llvm.compiler.used", llvm.compilerUsedGlobals)
if (context.config.produce.isNativeLibrary) { if (context.config.produce.isNativeLibrary) {
appendCAdapters() appendCAdapters()
} }
@@ -454,8 +457,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
val kVoidFuncType = functionType(voidType) val kVoidFuncType = functionType(voidType)
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!! val kNodeInitType = LLVMGetTypeByName(llvm.module, "struct.InitNode")!!
val kMemoryStateType = LLVMGetTypeByName(context.llvmModule, "struct.MemoryState")!! val kMemoryStateType = LLVMGetTypeByName(llvm.module, "struct.MemoryState")!!
val kInitFuncType = functionType(voidType, false, int32Type, pointerType(kMemoryStateType)) val kInitFuncType = functionType(voidType, false, int32Type, pointerType(kMemoryStateType))
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -472,7 +475,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun createInitBody(): LLVMValueRef { private fun createInitBody(): LLVMValueRef {
val initFunction = addLlvmFunctionWithDefaultAttributes( val initFunction = addLlvmFunctionWithDefaultAttributes(
context, context,
context.llvmModule!!, llvm.module,
"", "",
kInitFuncType kInitFuncType
) )
@@ -496,56 +499,55 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Globals initializers may contain accesses to objects, so visit them first. // Globals initializers may contain accesses to objects, so visit them first.
appendingTo(bbInit) { appendingTo(bbInit) {
context.llvm.initializersGenerationState.topLevelFields llvm.initializersGenerationState.topLevelFields
.filter { !context.useLazyFileInitializers() || it.shouldBeInitializedEagerly } .filter { !context.useLazyFileInitializers() || it.shouldBeInitializedEagerly }
.filterNot { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL } .filterNot { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
.forEach { initGlobalField(it) } .forEach { initGlobalField(it) }
context.llvm.initializersGenerationState.moduleGlobalInitializers.forEach { llvm.initializersGenerationState.moduleGlobalInitializers.forEach {
evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT) evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT)
} }
ret(null) ret(null)
} }
appendingTo(bbLocalInit) { appendingTo(bbLocalInit) {
context.llvm.initializersGenerationState.threadLocalInitState?.let { llvm.initializersGenerationState.threadLocalInitState?.let {
val address = it.getAddress(functionGenerationContext) val address = it.getAddress(functionGenerationContext)
store(Int32(FILE_NOT_INITIALIZED).llvm, address) store(Int32(FILE_NOT_INITIALIZED).llvm, address)
LLVMSetInitializer(address, Int32(FILE_NOT_INITIALIZED).llvm) LLVMSetInitializer(address, Int32(FILE_NOT_INITIALIZED).llvm)
} }
context.llvm.initializersGenerationState.topLevelFields llvm.initializersGenerationState.topLevelFields
.filter { !context.useLazyFileInitializers() || it.shouldBeInitializedEagerly } .filter { !context.useLazyFileInitializers() || it.shouldBeInitializedEagerly }
.filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL } .filter { it.storageKind(context) == FieldStorageKind.THREAD_LOCAL }
.forEach { initThreadLocalField(it) } .forEach { initThreadLocalField(it) }
context.llvm.initializersGenerationState.moduleThreadLocalInitializers.forEach { llvm.initializersGenerationState.moduleThreadLocalInitializers.forEach {
evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT, null) evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT, null)
} }
ret(null) ret(null)
} }
appendingTo(bbLocalAlloc) { appendingTo(bbLocalAlloc) {
if (context.llvm.tlsCount > 0) { if (llvm.tlsCount > 0) {
val memory = LLVMGetParam(initFunction, 1)!! val memory = LLVMGetParam(initFunction, 1)!!
call(context.llvm.addTLSRecord, listOf(memory, context.llvm.tlsKey, call(llvm.addTLSRecord, listOf(memory, llvm.tlsKey, Int32(llvm.tlsCount).llvm))
Int32(context.llvm.tlsCount).llvm))
} }
ret(null) ret(null)
} }
appendingTo(bbGlobalDeinit) { appendingTo(bbGlobalDeinit) {
context.llvm.initializersGenerationState.topLevelFields llvm.initializersGenerationState.topLevelFields
// Only if a subject for memory management. // Only if a subject for memory management.
.forEach { irField -> .forEach { irField ->
if (irField.type.binaryTypeIsReference() && irField.storageKind(context) != FieldStorageKind.THREAD_LOCAL) { if (irField.type.binaryTypeIsReference() && irField.storageKind(context) != FieldStorageKind.THREAD_LOCAL) {
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress( val address = context.generationState.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
functionGenerationContext functionGenerationContext
) )
storeHeapRef(codegen.kNullObjHeaderPtr, address) storeHeapRef(codegen.kNullObjHeaderPtr, address)
} }
} }
context.llvm.globalSharedObjects.forEach { address -> llvm.globalSharedObjects.forEach { address ->
storeHeapRef(codegen.kNullObjHeaderPtr, address) storeHeapRef(codegen.kNullObjHeaderPtr, address)
} }
context.llvm.initializersGenerationState.globalInitState?.let { llvm.initializersGenerationState.globalInitState?.let {
store(Int32(FILE_NOT_INITIALIZED).llvm, it) store(Int32(FILE_NOT_INITIALIZED).llvm, it)
} }
ret(null) ret(null)
@@ -564,15 +566,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Create static object of class InitNode. // Create static object of class InitNode.
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!! val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!!
// Create global variable with init record data. // Create global variable with init record data.
return context.llvm.staticData.placeGlobal( return llvm.staticData.placeGlobal("init_node", constPointer(initNode), isExported = false).llvmGlobal
"init_node", constPointer(initNode), isExported = false).llvmGlobal
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun createInitCtor(initNodePtr: LLVMValueRef): LLVMValueRef { private fun createInitCtor(initNodePtr: LLVMValueRef): LLVMValueRef {
val ctorFunction = generateFunctionNoRuntime(codegen, kVoidFuncType, "") { val ctorFunction = generateFunctionNoRuntime(codegen, kVoidFuncType, "") {
call(context.llvm.appendToInitalizersTail, listOf(initNodePtr)) call(llvm.appendToInitalizersTail, listOf(initNodePtr))
ret(null) ret(null)
} }
LLVMSetLinkage(ctorFunction, LLVMLinkage.LLVMPrivateLinkage) LLVMSetLinkage(ctorFunction, LLVMLinkage.LLVMPrivateLinkage)
@@ -784,14 +785,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
private fun getGlobalInitStateFor(file: IrFile): LLVMValueRef = private fun getGlobalInitStateFor(file: IrFile): LLVMValueRef =
context.llvm.initializersGenerationState.fileGlobalInitStates.getOrPut(file) { llvm.initializersGenerationState.fileGlobalInitStates.getOrPut(file) {
codegen.addGlobal("state_global$${file.fileEntry.name}", int32Type, false).also { codegen.addGlobal("state_global$${file.fileEntry.name}", int32Type, false).also {
LLVMSetInitializer(it, Int32(FILE_NOT_INITIALIZED).llvm) LLVMSetInitializer(it, Int32(FILE_NOT_INITIALIZED).llvm)
} }
} }
private fun getThreadLocalInitStateFor(file: IrFile): AddressAccess = private fun getThreadLocalInitStateFor(file: IrFile): AddressAccess =
context.llvm.initializersGenerationState.fileThreadLocalInitStates.getOrPut(file) { llvm.initializersGenerationState.fileThreadLocalInitStates.getOrPut(file) {
codegen.addKotlinThreadLocal("state_thread_local$${file.fileEntry.name}", int32Type) codegen.addKotlinThreadLocal("state_thread_local$${file.fileEntry.name}", int32Type)
} }
@@ -801,31 +802,31 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val body = declaration.body val body = declaration.body
if (declaration.origin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER) { if (declaration.origin == DECLARATION_ORIGIN_FILE_GLOBAL_INITIALIZER) {
require(context.llvm.initializersGenerationState.globalInitFunction == null) { "There can only be at most one global file initializer" } require(llvm.initializersGenerationState.globalInitFunction == null) { "There can only be at most one global file initializer" }
require(body == null) { "The body of file initializer should be null" } require(body == null) { "The body of file initializer should be null" }
require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" } require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" }
require(declaration.returnsUnit()) { "File initializer must return Unit" } require(declaration.returnsUnit()) { "File initializer must return Unit" }
context.llvm.initializersGenerationState.globalInitFunction = declaration llvm.initializersGenerationState.globalInitFunction = declaration
context.llvm.initializersGenerationState.globalInitState = getGlobalInitStateFor(declaration.parent as IrFile) llvm.initializersGenerationState.globalInitState = getGlobalInitStateFor(declaration.parent as IrFile)
} }
if (declaration.origin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER if (declaration.origin == DECLARATION_ORIGIN_FILE_THREAD_LOCAL_INITIALIZER
|| declaration.origin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER) { || declaration.origin == DECLARATION_ORIGIN_FILE_STANDALONE_THREAD_LOCAL_INITIALIZER) {
require(context.llvm.initializersGenerationState.threadLocalInitFunction == null) { "There can only be at most one thread local file initializer" } require(llvm.initializersGenerationState.threadLocalInitFunction == null) { "There can only be at most one thread local file initializer" }
require(body == null) { "The body of file initializer should be null" } require(body == null) { "The body of file initializer should be null" }
require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" } require(declaration.valueParameters.isEmpty()) { "File initializer must be parameterless" }
require(declaration.returnsUnit()) { "File initializer must return Unit" } require(declaration.returnsUnit()) { "File initializer must return Unit" }
context.llvm.initializersGenerationState.threadLocalInitFunction = declaration llvm.initializersGenerationState.threadLocalInitFunction = declaration
context.llvm.initializersGenerationState.threadLocalInitState = getThreadLocalInitStateFor(declaration.parent as IrFile) llvm.initializersGenerationState.threadLocalInitState = getThreadLocalInitStateFor(declaration.parent as IrFile)
} }
if (declaration.origin == DECLARATION_ORIGIN_MODULE_GLOBAL_INITIALIZER) { if (declaration.origin == DECLARATION_ORIGIN_MODULE_GLOBAL_INITIALIZER) {
require(declaration.valueParameters.isEmpty()) { "Module initializer must be a parameterless function" } require(declaration.valueParameters.isEmpty()) { "Module initializer must be a parameterless function" }
require(declaration.returnsUnit()) { "Module initializer must return Unit" } require(declaration.returnsUnit()) { "Module initializer must return Unit" }
context.llvm.initializersGenerationState.moduleGlobalInitializers.add(declaration) llvm.initializersGenerationState.moduleGlobalInitializers.add(declaration)
} }
if (declaration.origin == DECLARATION_ORIGIN_MODULE_THREAD_LOCAL_INITIALIZER) { if (declaration.origin == DECLARATION_ORIGIN_MODULE_THREAD_LOCAL_INITIALIZER) {
require(declaration.valueParameters.isEmpty()) { "Module initializer must be a parameterless function" } require(declaration.valueParameters.isEmpty()) { "Module initializer must be a parameterless function" }
require(declaration.returnsUnit()) { "Module initializer must return Unit" } require(declaration.returnsUnit()) { "Module initializer must return Unit" }
context.llvm.initializersGenerationState.moduleThreadLocalInitializers.add(declaration) llvm.initializersGenerationState.moduleThreadLocalInitializers.add(declaration)
} }
if ((declaration as? IrSimpleFunction)?.modality == Modality.ABSTRACT if ((declaration as? IrSimpleFunction)?.modality == Modality.ABSTRACT
@@ -851,7 +852,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
recordCoverage(body) recordCoverage(body)
if (declaration.isReifiedInline) { if (declaration.isReifiedInline) {
callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner, callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner,
listOf(context.llvm.staticData.kotlinStringLiteral( listOf(llvm.staticData.kotlinStringLiteral(
"unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm), "unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm),
Lifetime.IRRELEVANT, null) Lifetime.IRRELEVANT, null)
return@usingVariableScope return@usingVariableScope
@@ -870,12 +871,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.retainAnnotation(context.config.target)) { if (declaration.retainAnnotation(context.config.target)) {
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration).llvmValue) llvm.usedFunctions.add(codegen.llvmFunction(declaration).llvmValue)
} }
if (context.shouldVerifyBitCode()) if (context.shouldVerifyBitCode())
verifyModule(context.llvmModule!!, verifyModule(llvm.module, "${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
"${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
} }
private fun IrFunction.location(start: Boolean) = private fun IrFunction.location(start: Boolean) =
@@ -904,13 +904,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
if (declaration.kind.isSingleton && !declaration.isUnit()) { if (declaration.kind.isSingleton && !declaration.isUnit()) {
val singleton = context.llvmDeclarations.forSingleton(declaration) val singleton = context.generationState.llvmDeclarations.forSingleton(declaration)
val access = singleton.instanceStorage val access = singleton.instanceStorage
if (access is GlobalAddressAccess) { if (access is GlobalAddressAccess) {
// Global objects are kept in a data segment and can be accessed by any module (if exported) and also // Global objects are kept in a data segment and can be accessed by any module (if exported) and also
// they need to be initialized statically. // they need to be initialized statically.
LLVMSetInitializer(access.getAddress(null), if (declaration.storageKind(context) == ObjectStorageKind.PERMANENT) LLVMSetInitializer(access.getAddress(null), if (declaration.storageKind(context) == ObjectStorageKind.PERMANENT)
context.llvm.staticData.createConstKotlinObject(declaration, llvm.staticData.createConstKotlinObject(declaration,
*computeFields(declaration)).llvm else codegen.kNullObjHeaderPtr) *computeFields(declaration)).llvm else codegen.kNullObjHeaderPtr)
} else { } else {
// Thread local objects are kept in a special map, so they need a getter function to be accessible // Thread local objects are kept in a special map, so they need a getter function to be accessible
@@ -928,7 +928,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
// Getter uses TLS object, so need to ensure that this file's (de)initializer function // Getter uses TLS object, so need to ensure that this file's (de)initializer function
// inits and deinits TLS. // inits and deinits TLS.
context.llvm.fileUsesThreadLocalObjects = true llvm.fileUsesThreadLocalObjects = true
} }
} }
} }
@@ -955,7 +955,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
debugFieldDeclaration(declaration) debugFieldDeclaration(declaration)
if (context.needGlobalInit(declaration)) { if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(declaration.type) val type = codegen.getLLVMType(declaration.type)
val globalPropertyAccess = context.llvmDeclarations.forStaticField(declaration).storageAddressAccess val globalPropertyAccess = context.generationState.llvmDeclarations.forStaticField(declaration).storageAddressAccess
val initializer = declaration.initializer?.expression val initializer = declaration.initializer?.expression
val globalProperty = (globalPropertyAccess as? GlobalAddressAccess)?.getAddress(null) val globalProperty = (globalPropertyAccess as? GlobalAddressAccess)?.getAddress(null)
if (globalProperty != null) { if (globalProperty != null) {
@@ -966,7 +966,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// (Cannot do this before the global is initialized). // (Cannot do this before the global is initialized).
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
} }
context.llvm.initializersGenerationState.topLevelFields.add(declaration) llvm.initializersGenerationState.topLevelFields.add(declaration)
} }
} }
@@ -1384,7 +1384,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.positionAtEnd(loopBody) functionGenerationContext.positionAtEnd(loopBody)
if (context.memoryModel == MemoryModel.EXPERIMENTAL) if (context.memoryModel == MemoryModel.EXPERIMENTAL)
call(context.llvm.Kotlin_mm_safePointWhileLoopBody, emptyList()) call(llvm.Kotlin_mm_safePointWhileLoopBody, emptyList())
loop.body?.generate() loop.body?.generate()
functionGenerationContext.br(loopScope.loopCheck) functionGenerationContext.br(loopScope.loopCheck)
@@ -1406,7 +1406,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.positionAtEnd(loopBody) functionGenerationContext.positionAtEnd(loopBody)
if (context.memoryModel == MemoryModel.EXPERIMENTAL) if (context.memoryModel == MemoryModel.EXPERIMENTAL)
call(context.llvm.Kotlin_mm_safePointWhileLoopBody, emptyList()) call(llvm.Kotlin_mm_safePointWhileLoopBody, emptyList())
loop.body?.generate() loop.body?.generate()
functionGenerationContext.br(loopScope.loopCheck) functionGenerationContext.br(loopScope.loopCheck)
@@ -1453,7 +1453,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val file = (currentCodeContext.fileScope() as FileScope).file.file() val file = (currentCodeContext.fileScope() as FileScope).file.file()
return when (element) { return when (element) {
is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation( is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation(
builder = context.debugInfo.builder, builder = debugInfo.builder,
functionScope = locationInfo.scope, functionScope = locationInfo.scope,
diType = element.type.diType(context, codegen.llvmTargetData), diType = element.type.diType(context, codegen.llvmTargetData),
name = element.debugNameConversion(), name = element.debugNameConversion(),
@@ -1462,7 +1462,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
location = location) location = location)
else null else null
is IrValueParameter -> debugInfoParameterLocation( is IrValueParameter -> debugInfoParameterLocation(
builder = context.debugInfo.builder, builder = debugInfo.builder,
functionScope = locationInfo.scope, functionScope = locationInfo.scope,
diType = element.type.diType(context, codegen.llvmTargetData), diType = element.type.diType(context, codegen.llvmTargetData),
name = element.debugNameConversion(), name = element.debugNameConversion(),
@@ -1580,7 +1580,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString() val dstFullClassName = dstClass.fqNameWhenAvailable?.toString() ?: dstClass.name.toString()
callDirect( callDirect(
context.ir.symbols.throwTypeCastException.owner, context.ir.symbols.throwTypeCastException.owner,
listOf(srcArg, context.llvm.staticData.kotlinStringLiteral(dstFullClassName).llvm), listOf(srcArg, llvm.staticData.kotlinStringLiteral(dstFullClassName).llvm),
Lifetime.GLOBAL, Lifetime.GLOBAL,
null null
) )
@@ -1645,11 +1645,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj) val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj)
return if (!context.ghaEnabled()) { return if (!context.ghaEnabled()) {
call(context.llvm.isInstanceFunction, listOf(srcObjInfoPtr, codegen.typeInfoValue(dstClass))) call(llvm.isInstanceFunction, listOf(srcObjInfoPtr, codegen.typeInfoValue(dstClass)))
} else { } else {
val dstHierarchyInfo = context.getLayoutBuilder(dstClass).hierarchyInfo val dstHierarchyInfo = context.getLayoutBuilder(dstClass).hierarchyInfo
if (!dstClass.isInterface) { if (!dstClass.isInterface) {
call(context.llvm.isInstanceOfClassFastFunction, call(llvm.isInstanceOfClassFastFunction,
listOf(srcObjInfoPtr, Int32(dstHierarchyInfo.classIdLo).llvm, Int32(dstHierarchyInfo.classIdHi).llvm)) listOf(srcObjInfoPtr, Int32(dstHierarchyInfo.classIdLo).llvm, Int32(dstHierarchyInfo.classIdHi).llvm))
} else { } else {
// Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId // Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId
@@ -1675,7 +1675,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (dstClass.isInterface) { if (dstClass.isInterface) {
val isMeta = if (dstClass.isObjCMetaClass()) kTrue else kFalse val isMeta = if (dstClass.isObjCMetaClass()) kTrue else kFalse
call( call(
context.llvm.Kotlin_Interop_DoesObjectConformToProtocol, llvm.Kotlin_Interop_DoesObjectConformToProtocol,
listOf( listOf(
objCObject, objCObject,
genGetObjCProtocol(dstClass), genGetObjCProtocol(dstClass),
@@ -1684,7 +1684,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
) )
} else { } else {
call( call(
context.llvm.Kotlin_Interop_IsObjectKindOfClass, llvm.Kotlin_Interop_IsObjectKindOfClass,
listOf(objCObject, genGetObjCClass(dstClass)) listOf(objCObject, genGetObjCClass(dstClass))
) )
}.let { }.let {
@@ -1701,7 +1701,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
origin = context.standardLlvmSymbolsOrigin origin = context.standardLlvmSymbolsOrigin
) )
val isClass = context.llvm.externalFunction(isClassProto) val isClass = llvm.externalFunction(isClassProto)
call(isClass, listOf(objCObject)).let { call(isClass, listOf(objCObject)).let {
functionGenerationContext.icmpNe(it, Int8(0).llvm) functionGenerationContext.icmpNe(it, Int8(0).llvm)
} }
@@ -1711,7 +1711,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val protocolClass = val protocolClass =
functionGenerationContext.getObjCClass("Protocol", context.standardLlvmSymbolsOrigin) functionGenerationContext.getObjCClass("Protocol", context.standardLlvmSymbolsOrigin)
call( call(
context.llvm.Kotlin_Interop_IsObjectKindOfClass, llvm.Kotlin_Interop_IsObjectKindOfClass,
listOf(objCObject, protocolClass) listOf(objCObject, protocolClass)
) )
} else { } else {
@@ -1743,7 +1743,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (context.config.threadsAreAllowed && value.symbol.owner.isGlobalNonPrimitive(context)) { if (context.config.threadsAreAllowed && value.symbol.owner.isGlobalNonPrimitive(context)) {
functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler) functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler)
} }
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress( val ptr = context.generationState.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext functionGenerationContext
) )
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal, resultSlot) functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal, resultSlot)
@@ -1802,17 +1802,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
val parentAsClass = value.symbol.owner.parentAsClass val parentAsClass = value.symbol.owner.parentAsClass
if (needMutationCheck(parentAsClass)) { if (needMutationCheck(parentAsClass)) {
functionGenerationContext.call(context.llvm.mutationCheck, functionGenerationContext.call(llvm.mutationCheck,
listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)), listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)),
Lifetime.IRRELEVANT, currentCodeContext.exceptionHandler) Lifetime.IRRELEVANT, currentCodeContext.exceptionHandler)
} }
if (needLifetimeConstraintsCheck(valueToAssign, parentAsClass)) { if (needLifetimeConstraintsCheck(valueToAssign, parentAsClass)) {
functionGenerationContext.call(context.llvm.checkLifetimesConstraint, listOf(thisPtr, valueToAssign)) functionGenerationContext.call(llvm.checkLifetimesConstraint, listOf(thisPtr, valueToAssign))
} }
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner), false) functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner), false)
} else { } else {
assert(value.receiver == null) assert(value.receiver == null)
val globalAddress = context.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress( val globalAddress = context.generationState.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext functionGenerationContext
) )
if (context.config.threadsAreAllowed && value.symbol.owner.storageKind(context) == FieldStorageKind.GLOBAL) if (context.config.threadsAreAllowed && value.symbol.owner.storageKind(context) == FieldStorageKind.GLOBAL)
@@ -1833,7 +1833,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef { private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
val fieldInfo = context.llvmDeclarations.forField(value) val fieldInfo = context.generationState.llvmDeclarations.forField(value)
val typePtr = pointerType(fieldInfo.classBodyType) val typePtr = pointerType(fieldInfo.classBodyType)
@@ -1844,7 +1844,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateStringConst(value: IrConst<String>) = private fun evaluateStringConst(value: IrConst<String>) =
context.llvm.staticData.kotlinStringLiteral(value.value) llvm.staticData.kotlinStringLiteral(value.value)
private fun evaluateConst(value: IrConst<*>): ConstValue { private fun evaluateConst(value: IrConst<*>): ConstValue {
context.log{"evaluateConst : ${ir2string(value)}"} context.log{"evaluateConst : ${ir2string(value)}"}
@@ -1900,7 +1900,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
require(codegen.getLLVMType(value.type) == codegen.kObjHeaderPtr) { require(codegen.getLLVMType(value.type) == codegen.kObjHeaderPtr) {
"Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}" "Can't wrap ${value.value.kind.asString} constant to type ${value.type.render()}"
} }
value.toBoxCacheValue(context) ?: context.llvm.staticData.createConstKotlinObject( value.toBoxCacheValue(context) ?: llvm.staticData.createConstKotlinObject(
constructedType.getClass()!!, constructedType.getClass()!!,
evaluateConst(value.value) evaluateConst(value.value)
) )
@@ -1914,7 +1914,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) { require(clazz.symbol == symbols.array || clazz.symbol in symbols.primitiveTypesToPrimitiveArrays.values) {
"Statically initialized array should have array type" "Statically initialized array should have array type"
} }
context.llvm.staticData.createConstKotlinArray( llvm.staticData.createConstKotlinArray(
value.type.getClass()!!, value.type.getClass()!!,
value.elements.map { evaluateConstantValue(it) } value.elements.map { evaluateConstantValue(it) }
) )
@@ -1944,7 +1944,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
require(codegen.getLLVMType(value.type) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" } require(codegen.getLLVMType(value.type) == codegen.kObjHeaderPtr) { "Constant object is not an object, but ${value.type.render()}" }
context.llvm.staticData.createConstKotlinObject( llvm.staticData.createConstKotlinObject(
constructedClass, constructedClass,
*fields.toTypedArray() *fields.toTypedArray()
) )
@@ -1968,7 +1968,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock, val resultSlot: LLVMValueRef?) : private inner class ReturnableBlockScope(val returnableBlock: IrReturnableBlock, val resultSlot: LLVMValueRef?) :
FileScope(returnableBlock.inlineFunctionSymbol?.owner?.let { FileScope(returnableBlock.inlineFunctionSymbol?.owner?.let {
context.mapping.loweredInlineFunctions[it]?.irFile ?: it.fileOrNull context.generationState.loweredInlineFunctions[it]?.irFile ?: it.fileOrNull
} }
?: (currentCodeContext.fileScope() as? FileScope)?.file ?: (currentCodeContext.fileScope() as? FileScope)?.file
?: error("returnable block should belong to current file at least")) { ?: error("returnable block should belong to current file at least")) {
@@ -1977,13 +1977,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
var resultPhi : LLVMValueRef? = null var resultPhi : LLVMValueRef? = null
private val functionScope by lazy { private val functionScope by lazy {
returnableBlock.inlineFunctionSymbol?.owner?.let { returnableBlock.inlineFunctionSymbol?.owner?.let {
it.scope(file().fileEntry.line(context.mapping.loweredInlineFunctions[it]?.startOffset ?: it.startOffset)) it.scope(file().fileEntry.line(context.generationState.loweredInlineFunctions[it]?.startOffset ?: it.startOffset))
} }
} }
private fun getExit(): LLVMBasicBlockRef { private fun getExit(): LLVMBasicBlockRef {
val location = returnableBlock.inlineFunctionSymbol?.owner?.let { val location = returnableBlock.inlineFunctionSymbol?.owner?.let {
location(context.mapping.loweredInlineFunctions[it]?.endOffset ?: it.endOffset) location(context.generationState.loweredInlineFunctions[it]?.endOffset ?: it.endOffset)
} ?: returnableBlock.statements.lastOrNull()?.let { } ?: returnableBlock.statements.lastOrNull()?.let {
location(it.endOffset) location(it.endOffset)
} }
@@ -2040,8 +2040,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private val scope by lazy { private val scope by lazy {
if (!context.shouldContainLocationDebugInfo() || returnableBlock.startOffset == UNDEFINED_OFFSET) if (!context.shouldContainLocationDebugInfo() || returnableBlock.startOffset == UNDEFINED_OFFSET)
return@lazy null return@lazy null
val lexicalBlockFile = DICreateLexicalBlockFile(context.debugInfo.builder, functionScope()!!.scope(), super.file.file()) val lexicalBlockFile = DICreateLexicalBlockFile(debugInfo.builder, functionScope()!!.scope(), super.file.file())
DICreateLexicalBlock(context.debugInfo.builder, lexicalBlockFile, super.file.file(), returnableBlock.startLine(), returnableBlock.startColumn())!! DICreateLexicalBlock(debugInfo.builder, lexicalBlockFile, super.file.file(), returnableBlock.startLine(), returnableBlock.startColumn())!!
} }
override fun scope() = scope override fun scope() = scope
@@ -2074,7 +2074,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val members = mutableListOf<DIDerivedTypeRef>() val members = mutableListOf<DIDerivedTypeRef>()
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val scope = if (isExported && context.shouldContainDebugInfo()) val scope = if (isExported && context.shouldContainDebugInfo())
context.debugInfo.objHeaderPointerType debugInfo.objHeaderPointerType
else null else null
override fun classScope(): CodeContext? = this override fun classScope(): CodeContext? = this
} }
@@ -2197,7 +2197,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits) scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
scope.members.add(DICreateMemberType( scope.members.add(DICreateMemberType(
refBuilder = context.debugInfo.builder, refBuilder = debugInfo.builder,
refScope = scope.scope as DIScopeOpaqueRef, refScope = scope.scope as DIScopeOpaqueRef,
name = expression.computeSymbolName(), name = expression.computeSymbolName(),
file = irFile.file(), file = irFile.file(),
@@ -2213,9 +2213,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun IrFile.file(): DIFileRef { private fun IrFile.file(): DIFileRef {
return context.debugInfo.files.getOrPut(this.fileEntry.name) { return debugInfo.files.getOrPut(this.fileEntry.name) {
val path = this.fileEntry.name.toFileAndFolder(context) val path = this.fileEntry.name.toFileAndFolder(context)
DICreateFile(context.debugInfo.builder, path.file, path.folder)!! DICreateFile(debugInfo.builder, path.file, path.folder)!!
} }
} }
@@ -2245,7 +2245,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
else else
codegen.llvmFunctionOrNull(this)?.llvmValue codegen.llvmFunctionOrNull(this)?.llvmValue
return if (!isReifiedInline && functionLlvmValue != null) { return if (!isReifiedInline && functionLlvmValue != null) {
context.debugInfo.subprograms.getOrPut(functionLlvmValue) { debugInfo.subprograms.getOrPut(functionLlvmValue) {
memScoped { memScoped {
val subroutineType = subroutineType(context, codegen.llvmTargetData) val subroutineType = subroutineType(context, codegen.llvmTargetData)
val llvmFunction = codegen.llvmFunction(this@scope).llvmValue val llvmFunction = codegen.llvmFunction(this@scope).llvmValue
@@ -2256,7 +2256,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
} as DIScopeOpaqueRef } as DIScopeOpaqueRef
} else { } else {
context.debugInfo.inlinedSubprograms.getOrPut(this) { debugInfo.inlinedSubprograms.getOrPut(this) {
memScoped { memScoped {
val subroutineType = subroutineType(context, codegen.llvmTargetData) val subroutineType = subroutineType(context, codegen.llvmTargetData)
diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType) diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType)
@@ -2268,7 +2268,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef): DIScopeOpaqueRef? { private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef): DIScopeOpaqueRef? {
return context.debugInfo.subprograms.getOrPut(this) { return debugInfo.subprograms.getOrPut(this) {
diFunctionScope(name!!, name!!, startLine, subroutineType).also { diFunctionScope(name!!, name!!, startLine, subroutineType).also {
DIFunctionAddSubprogram(this@scope, it) DIFunctionAddSubprogram(this@scope, it)
} }
@@ -2277,8 +2277,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef) = DICreateFunction( private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef) = DICreateFunction(
builder = context.debugInfo.builder, builder = debugInfo.builder,
scope = context.debugInfo.compilationUnit, scope = debugInfo.compilationUnit,
name = name, name = name,
linkageName = linkageName, linkageName = linkageName,
file = file().file(), file = file().file(),
@@ -2447,7 +2447,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetOrdering(state, LLVMAtomicOrdering.LLVMAtomicOrderingAcquire) LLVMSetOrdering(state, LLVMAtomicOrdering.LLVMAtomicOrderingAcquire)
condBr(icmpEq(state, Int32(FILE_INITIALIZED).llvm), bbExit, bbInit) condBr(icmpEq(state, Int32(FILE_INITIALIZED).llvm), bbExit, bbInit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
call(context.llvm.callInitGlobalPossiblyLock, listOf(statePtr, initializerPtr), call(llvm.callInitGlobalPossiblyLock, listOf(statePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler) exceptionHandler = currentCodeContext.exceptionHandler)
br(bbExit) br(bbExit)
positionAtEnd(bbExit) positionAtEnd(bbExit)
@@ -2474,7 +2474,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
positionAtEnd(bbCheckLocalState) positionAtEnd(bbCheckLocalState)
condBr(icmpNe(load(localStatePtr), Int32(FILE_INITIALIZED).llvm), bbInit, bbExit) condBr(icmpNe(load(localStatePtr), Int32(FILE_INITIALIZED).llvm), bbInit, bbExit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
call(context.llvm.callInitThreadLocal, listOf(globalStatePtr, localStatePtr, initializerPtr), call(llvm.callInitThreadLocal, listOf(globalStatePtr, localStatePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler) exceptionHandler = currentCodeContext.exceptionHandler)
br(bbExit) br(bbExit)
positionAtEnd(bbExit) positionAtEnd(bbExit)
@@ -2492,7 +2492,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
moveBlockAfterEntry(bbInit) moveBlockAfterEntry(bbInit)
condBr(icmpEq(load(statePtr), Int32(FILE_INITIALIZED).llvm), bbExit, bbInit) condBr(icmpEq(load(statePtr), Int32(FILE_INITIALIZED).llvm), bbExit, bbInit)
positionAtEnd(bbInit) positionAtEnd(bbInit)
call(context.llvm.callInitThreadLocal, listOf(kNullInt32Ptr, statePtr, initializerPtr), call(llvm.callInitThreadLocal, listOf(kNullInt32Ptr, statePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler) exceptionHandler = currentCodeContext.exceptionHandler)
br(bbExit) br(bbExit)
positionAtEnd(bbExit) positionAtEnd(bbExit)
@@ -2562,7 +2562,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
origin = irClass.llvmSymbolOrigin, origin = irClass.llvmSymbolOrigin,
independent = true // Protocol is header-only declaration. independent = true // Protocol is header-only declaration.
) )
val protocolGetter = context.llvm.externalFunction(protocolGetterProto) val protocolGetter = llvm.externalFunction(protocolGetterProto)
return call(protocolGetter, emptyList()) return call(protocolGetter, emptyList())
} }
@@ -2733,9 +2733,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun appendLlvmUsed(name: String, args: List<LLVMValueRef>) { private fun appendLlvmUsed(name: String, args: List<LLVMValueRef>) {
if (args.isEmpty()) return if (args.isEmpty()) return
val argsCasted = args.map { it -> constPointer(it).bitcast(int8TypePtr) } val argsCasted = args.map { constPointer(it).bitcast(int8TypePtr) }
val llvmUsedGlobal = val llvmUsedGlobal = llvm.staticData.placeGlobalArray(name, int8TypePtr, argsCasted)
context.llvm.staticData.placeGlobalArray(name, int8TypePtr, argsCasted)
LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage) LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata") LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata")
@@ -2755,14 +2754,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetLinkage(initializer, LLVMLinkage.LLVMPrivateLinkage) LLVMSetLinkage(initializer, LLVMLinkage.LLVMPrivateLinkage)
context.llvm.otherStaticInitializers += initializer llvm.otherStaticInitializers += initializer
} else { } else {
context.llvmImports.add(context.standardLlvmSymbolsOrigin) context.generationState.llvmImports.add(context.standardLlvmSymbolsOrigin)
// Define a strong runtime global. It'll overrule a weak global defined in a statically linked runtime. // Define a strong runtime global. It'll overrule a weak global defined in a statically linked runtime.
val global = context.llvm.staticData.placeGlobal(name, value, true) val global = llvm.staticData.placeGlobal(name, value, true)
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) { if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
context.llvm.usedGlobals += global.llvmGlobal llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility) LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
} }
} }
@@ -2782,8 +2781,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
SourceInfoType.CORESYMBOLICATION -> "Kotlin_getSourceInfo_core_symbolication" SourceInfoType.CORESYMBOLICATION -> "Kotlin_getSourceInfo_core_symbolication"
} }
if (getSourceInfoFunctionName != null) { if (getSourceInfoFunctionName != null) {
val getSourceInfoFunction = LLVMGetNamedFunction(context.llvmModule, getSourceInfoFunctionName) val getSourceInfoFunction = LLVMGetNamedFunction(llvm.module, getSourceInfoFunctionName)
?: LLVMAddFunction(context.llvmModule, getSourceInfoFunctionName, ?: LLVMAddFunction(llvm.module, getSourceInfoFunctionName,
functionType(int32Type, false, int8TypePtr, int8TypePtr, int32Type)) functionType(int32Type, false, int8TypePtr, int8TypePtr, int32Type))
overrideRuntimeGlobal("Kotlin_getSourceInfo_Function", constValue(getSourceInfoFunction!!)) overrideRuntimeGlobal("Kotlin_getSourceInfo_Function", constValue(getSourceInfoFunction!!))
} }
@@ -2827,13 +2826,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun appendStaticInitializers() { fun appendStaticInitializers() {
// Note: the list of libraries is topologically sorted (in order for initializers to be called correctly). // Note: the list of libraries is topologically sorted (in order for initializers to be called correctly).
val libraries = (context.llvm.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */) val libraries = (llvm.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */)
val libraryToInitializers = libraries.associateWith { val libraryToInitializers = libraries.associateWith {
mutableListOf<LLVMValueRef>() mutableListOf<LLVMValueRef>()
} }
context.llvm.irStaticInitializers.forEach { llvm.irStaticInitializers.forEach {
val library = it.konanLibrary val library = it.konanLibrary
val initializers = libraryToInitializers[library] val initializers = libraryToInitializers[library]
?: error("initializer for not included library ${library?.libraryFile}") ?: error("initializer for not included library ${library?.libraryFile}")
@@ -2846,7 +2845,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
fun addCtorFunction(ctorName: String) = fun addCtorFunction(ctorName: String) =
addLlvmFunctionWithDefaultAttributes( addLlvmFunctionWithDefaultAttributes(
context, context,
context.llvmModule!!, llvm.module,
ctorName, ctorName,
kVoidFuncType kVoidFuncType
).also { LLVMSetLinkage(it, LLVMLinkage.LLVMExternalLinkage) } ).also { LLVMSetLinkage(it, LLVMLinkage.LLVMExternalLinkage) }
@@ -2855,15 +2854,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val initializers = libraryToInitializers.getValue(library) val initializers = libraryToInitializers.getValue(library)
val ctorName = when { val ctorName = when {
library == null -> context.config.moduleId.moduleConstructorName // TODO: Try to not use moduleId.
library == null -> (if (context.config.produce.isCache) context.generationState.outputFiles.cacheFileName else context.config.moduleId).moduleConstructorName
library == context.config.libraryToCache?.klib library == context.config.libraryToCache?.klib
&& context.config.producePerFileCache -> && context.config.producePerFileCache ->
fileCtorName(library.uniqueName, context.config.outputFiles.perFileCacheFileName) fileCtorName(library.uniqueName, context.generationState.outputFiles.perFileCacheFileName)
else -> library.moduleConstructorName else -> library.moduleConstructorName
} }
if (library == null || context.llvmModuleSpecification.containsLibrary(library)) { if (library == null || context.llvmModuleSpecification.containsLibrary(library)) {
val otherInitializers = context.llvm.otherStaticInitializers.takeIf { library == null }.orEmpty() val otherInitializers = llvm.otherStaticInitializers.takeIf { library == null }.orEmpty()
val ctorFunction = addCtorFunction(ctorName) val ctorFunction = addCtorFunction(ctorName)
appendStaticInitializers(ctorFunction, initializers + otherInitializers) appendStaticInitializers(ctorFunction, initializers + otherInitializers)
@@ -2895,7 +2895,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun appendStaticInitializers(ctorFunction: LLVMValueRef, initializers: List<LLVMValueRef>) { private fun appendStaticInitializers(ctorFunction: LLVMValueRef, initializers: List<LLVMValueRef>) {
generateFunctionNoRuntime(codegen, ctorFunction) { generateFunctionNoRuntime(codegen, ctorFunction) {
val initGuardName = ctorFunction.name.orEmpty() + "_guard" val initGuardName = ctorFunction.name.orEmpty() + "_guard"
val initGuard = LLVMAddGlobal(context.llvmModule, int32Type, initGuardName) val initGuard = LLVMAddGlobal(llvm.module, int32Type, initGuardName)
LLVMSetInitializer(initGuard, kImmZero) LLVMSetInitializer(initGuard, kImmZero)
LLVMSetLinkage(initGuard, LLVMLinkage.LLVMPrivateLinkage) LLVMSetLinkage(initGuard, LLVMLinkage.LLVMPrivateLinkage)
val bbInited = basicBlock("inited", null) val bbInited = basicBlock("inited", null)
@@ -2935,7 +2935,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage) LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage)
// Append initializers of global variables in "llvm.global_ctors" array. // Append initializers of global variables in "llvm.global_ctors" array.
val globalCtors = context.llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType, val globalCtors = llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
listOf(createGlobalCtor(globalCtorFunction))) listOf(createGlobalCtor(globalCtorFunction)))
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage) LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
if (context.config.produce == CompilerOutputKind.PROGRAM) { if (context.config.produce == CompilerOutputKind.PROGRAM) {
@@ -2981,7 +2981,7 @@ internal class LocationInfo(val scope: DIScopeOpaqueRef,
internal fun Context.generateRuntimeConstantsModule() : LLVMModuleRef { internal fun Context.generateRuntimeConstantsModule() : LLVMModuleRef {
val llvmModule = LLVMModuleCreateWithNameInContext("constants", llvmContext)!! val llvmModule = LLVMModuleCreateWithNameInContext("constants", llvmContext)!!
LLVMSetDataLayout(llvmModule, llvm.runtime.dataLayout) LLVMSetDataLayout(llvmModule, generationState.runtime.dataLayout)
val static = StaticData(llvmModule) val static = StaticData(llvmModule)
fun setRuntimeConstGlobal(name: String, value: ConstValue) { fun setRuntimeConstGlobal(name: String, value: ConstValue) {
@@ -20,7 +20,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
fun generate(irClass: IrClass) { fun generate(irClass: IrClass) {
assert(irClass.isFinalClass) assert(irClass.isFinalClass)
val objCLLvmDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!! val objCLLvmDeclarations = context.generationState.llvmDeclarations.forClass(irClass).objCDeclarations!!
val instanceMethods = generateInstanceMethodDescs(irClass) val instanceMethods = generateInstanceMethodDescs(irClass)
@@ -28,11 +28,11 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
val classMethods = companionObject?.generateMethodDescs().orEmpty() val classMethods = companionObject?.generateMethodDescs().orEmpty()
val superclassName = irClass.getSuperClassNotAny()!!.let { val superclassName = irClass.getSuperClassNotAny()!!.let {
context.llvm.imports.add(it.llvmSymbolOrigin) llvm.imports.add(it.llvmSymbolOrigin)
it.descriptor.getExternalObjCClassBinaryName() it.descriptor.getExternalObjCClassBinaryName()
} }
val protocolNames = irClass.getSuperInterfaces().map { val protocolNames = irClass.getSuperInterfaces().map {
context.llvm.imports.add(it.llvmSymbolOrigin) llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString().removeSuffix("Protocol") it.name.asString().removeSuffix("Protocol")
} }
@@ -87,7 +87,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
.distinctBy { it.selector } .distinctBy { it.selector }
allInitMethodsInfo.mapTo(this) { allInitMethodsInfo.mapTo(this) {
ObjCMethodDesc(it.selector, it.encoding, context.llvm.missingInitImp.llvmValue) ObjCMethodDesc(it.selector, it.encoding, llvm.missingInitImp.llvmValue)
} }
} }
@@ -164,6 +164,6 @@ internal fun CodeGenerator.kotlinObjCClassInfo(irClass: IrClass): LLVMValueRef {
origin = irClass.llvmSymbolOrigin origin = irClass.llvmSymbolOrigin
) )
} else { } else {
context.llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal
} }
} }
@@ -16,7 +16,7 @@ private fun ConstPointer.add(index: Int): ConstPointer {
return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!) return constPointer(LLVMConstGEP(llvm, cValuesOf(Int32(index).llvm), 1)!!)
} }
internal class KotlinStaticData(override val context: Context) : ContextUtils, StaticData(context.llvmModule!!) { internal class KotlinStaticData(override val context: Context, module: LLVMModuleRef) : ContextUtils, StaticData(module) {
private val stringLiterals = mutableMapOf<String, ConstPointer>() private val stringLiterals = mutableMapOf<String, ConstPointer>()
// Must match OBJECT_TAG_PERMANENT_CONTAINER in C++. // Must match OBJECT_TAG_PERMANENT_CONTAINER in C++.
@@ -104,10 +104,10 @@ internal class KotlinStaticData(override val context: Context) : ContextUtils, S
} }
return if (isExternal(descriptor)) { return if (isExternal(descriptor)) {
constPointer(importGlobal( constPointer(importGlobal(
kind.llvmName, context.llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin kind.llvmName, runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
)) ))
} else { } else {
context.llvmDeclarations.forUnique(kind).pointer context.generationState.llvmDeclarations.forUnique(kind).pointer
} }
} }
@@ -84,11 +84,11 @@ private fun ContextUtils.createClassBodyType(name: String, fields: List<ClassLay
val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) } val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) }
// TODO: consider adding synthetic ObjHeader field to Any. // TODO: consider adding synthetic ObjHeader field to Any.
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!! val classType = LLVMStructCreateNamed(LLVMGetModuleContext(llvm.module), name)!!
// LLVMStructSetBody expects the struct to be properly aligned and will insert padding accordingly. In our case // LLVMStructSetBody expects the struct to be properly aligned and will insert padding accordingly. In our case
// `allocInstance` returns 16x + 8 address, i.e. always misaligned for vector types. Workaround is to use packed struct. // `allocInstance` returns 16x + 8 address, i.e. always misaligned for vector types. Workaround is to use packed struct.
val hasBigAlignment = fields.any { LLVMABIAlignmentOfType(context.llvm.runtime.targetData, getLLVMType(it.type)) > 8 } val hasBigAlignment = fields.any { LLVMABIAlignmentOfType(runtime.targetData, getLLVMType(it.type)) > 8 }
val packed = if (hasBigAlignment) 1 else 0 val packed = if (hasBigAlignment) 1 else 0
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, packed) LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, packed)
@@ -191,7 +191,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false) typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false)
val llvmTypeInfoPtr = LLVMAddAlias(context.llvmModule, val llvmTypeInfoPtr = LLVMAddAlias(llvm.module,
kTypeInfoPtr, kTypeInfoPtr,
typeInfoGlobal.pointer.getElementPtr(0).llvm, typeInfoGlobal.pointer.getElementPtr(0).llvm,
typeInfoSymbolName)!! typeInfoSymbolName)!!
@@ -202,7 +202,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists") throw IllegalArgumentException("Global '$typeInfoSymbolName' already exists")
} }
} else { } else {
if (!context.config.producePerFileCache || declaration !in context.constructedFromExportedInlineFunctions) if (!context.config.producePerFileCache || declaration !in context.generationState.constructedFromExportedInlineFunctions)
LLVMSetLinkage(llvmTypeInfoPtr, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(llvmTypeInfoPtr, LLVMLinkage.LLVMInternalLinkage)
} }
@@ -296,7 +296,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
"kobjcclassinfo:$internalName" "kobjcclassinfo:$internalName"
} }
val classInfoGlobal = staticData.createGlobal( val classInfoGlobal = staticData.createGlobal(
context.llvm.runtime.kotlinObjCClassInfo, runtime.kotlinObjCClassInfo,
classInfoSymbolName, classInfoSymbolName,
isExported = isExported isExported = isExported
).apply { ).apply {
@@ -360,12 +360,12 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|| declaration.annotations.hasAnnotation(RuntimeNames.cCall)) return || declaration.annotations.hasAnnotation(RuntimeNames.cCall)) return
val proto = LlvmFunctionProto(declaration, declaration.computeSymbolName(), this) val proto = LlvmFunctionProto(declaration, declaration.computeSymbolName(), this)
context.llvm.externalFunction(proto) llvm.externalFunction(proto)
} else { } else {
val symbolName = if (declaration.isExported()) { val symbolName = if (declaration.isExported()) {
declaration.computeSymbolName().also { declaration.computeSymbolName().also {
if (declaration.name.asString() != "main") { if (declaration.name.asString() != "main") {
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it } assert(LLVMGetNamedFunction(llvm.module, it) == null) { it }
} else { } else {
// As a workaround, allow `main` functions to clash because frontend accepts this. // As a workaround, allow `main` functions to clash because frontend accepts this.
// See [OverloadResolver.isTopLevelMainInDifferentFiles] usage. // See [OverloadResolver.isTopLevelMainInDifferentFiles] usage.
@@ -384,7 +384,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val proto = LlvmFunctionProto(declaration, symbolName, this) val proto = LlvmFunctionProto(declaration, symbolName, this)
val llvmFunction = addLlvmFunctionWithDefaultAttributes( val llvmFunction = addLlvmFunctionWithDefaultAttributes(
context, context,
context.llvmModule!!, llvm.module,
symbolName, symbolName,
proto.llvmFunctionType proto.llvmFunctionType
).also { ).also {
@@ -252,15 +252,14 @@ internal fun getGlobalType(ptrToGlobal: LLVMValueRef): LLVMTypeRef {
internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): LLVMValueRef { internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): LLVMValueRef {
if (isExported) if (isExported)
assert(LLVMGetNamedGlobal(context.llvmModule, name) == null) assert(LLVMGetNamedGlobal(llvm.module, name) == null)
return LLVMAddGlobal(context.llvmModule, type, name)!! return LLVMAddGlobal(llvm.module, type, name)!!
} }
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin): LLVMValueRef { internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin): LLVMValueRef {
llvm.imports.add(origin)
context.llvm.imports.add(origin) val found = LLVMGetNamedGlobal(llvm.module, name)
val found = LLVMGetNamedGlobal(context.llvmModule, name)
return if (found != null) { return if (found != null) {
assert (getGlobalType(found) == type) assert (getGlobalType(found) == type)
assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" } assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
@@ -282,26 +281,26 @@ internal class TLSAddressAccess(
private val context: Context, private val index: Int): AddressAccess() { private val context: Context, private val index: Int): AddressAccess() {
override fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef { override fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef {
return generationContext!!.call(context.llvm.lookupTLS, return generationContext!!.call(context.generationState.llvm.lookupTLS,
listOf(context.llvm.tlsKey, Int32(index).llvm)) listOf(context.generationState.llvm.tlsKey, Int32(index).llvm))
} }
} }
internal fun ContextUtils.addKotlinThreadLocal(name: String, type: LLVMTypeRef): AddressAccess { internal fun ContextUtils.addKotlinThreadLocal(name: String, type: LLVMTypeRef): AddressAccess {
return if (isObjectType(type)) { return if (isObjectType(type)) {
val index = context.llvm.tlsCount++ val index = llvm.tlsCount++
TLSAddressAccess(context, index) TLSAddressAccess(context, index)
} else { } else {
// TODO: This will break if Workers get decoupled from host threads. // TODO: This will break if Workers get decoupled from host threads.
GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also { GlobalAddressAccess(LLVMAddGlobal(llvm.module, type, name)!!.also {
LLVMSetThreadLocalMode(it, context.llvm.tlsMode) LLVMSetThreadLocalMode(it, llvm.tlsMode)
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}) })
} }
} }
internal fun ContextUtils.addKotlinGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): AddressAccess { internal fun ContextUtils.addKotlinGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): AddressAccess {
return GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also { return GlobalAddressAccess(LLVMAddGlobal(llvm.module, type, name)!!.also {
if (!isExported) if (!isExported)
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}) })
@@ -200,7 +200,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val className = irClass.fqNameForIrSerialization val className = irClass.fqNameForIrSerialization
val llvmDeclarations = context.llvmDeclarations.forClass(irClass) val llvmDeclarations = context.generationState.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType val bodyType = llvmDeclarations.bodyType
@@ -390,7 +390,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private val debugOperations: ConstValue by lazy { private val debugOperations: ConstValue by lazy {
if (debugRuntimeOrNull != null) { if (debugRuntimeOrNull != null) {
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!! val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
val local = LLVMAddGlobal(context.llvmModule, LLVMGetElementType(LLVMTypeOf(external)),"Konan_debugOperationsList")!! val local = LLVMAddGlobal(llvm.module, LLVMGetElementType(LLVMTypeOf(external)),"Konan_debugOperationsList")!!
constPointer(LLVMConstBitCast(local, kInt8PtrPtr)!!) constPointer(LLVMConstBitCast(local, kInt8PtrPtr)!!)
} else { } else {
Zero(kInt8PtrPtr) Zero(kInt8PtrPtr)
@@ -411,7 +411,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return NullPointer(runtime.extendedTypeInfoType) return NullPointer(runtime.extendedTypeInfoType)
val className = irClass.fqNameForIrSerialization.toString() val className = irClass.fqNameForIrSerialization.toString()
val llvmDeclarations = context.llvmDeclarations.forClass(irClass) val llvmDeclarations = context.generationState.llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType val bodyType = llvmDeclarations.bodyType
val elementType = getElementType(irClass) val elementType = getElementType(irClass)
@@ -577,16 +577,16 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
when { when {
irClass.isAnonymousObject -> { irClass.isAnonymousObject -> {
relativeName = context.getLocalClassName(irClass) relativeName = context.generationState.getLocalClassName(irClass)
flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName]. flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName].
} }
irClass.isLocal -> { irClass.isLocal -> {
relativeName = context.getLocalClassName(irClass) relativeName = context.generationState.getLocalClassName(irClass)
flags = TF_REFLECTION_SHOW_REL_NAME // Only allow relative name to be used in KClass.simpleName. flags = TF_REFLECTION_SHOW_REL_NAME // Only allow relative name to be used in KClass.simpleName.
} }
isLoweredFunctionReference(irClass) -> { isLoweredFunctionReference(irClass) -> {
// TODO: might return null so use fallback here, to be fixed in KT-47194 // TODO: might return null so use fallback here, to be fixed in KT-47194
relativeName = context.getLocalClassName(irClass) ?: generateDefaultRelativeName(irClass) relativeName = context.generationState.getLocalClassName(irClass) ?: generateDefaultRelativeName(irClass)
flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName]. flags = 0 // Forbid to use package and relative names in KClass.[simpleName|qualifiedName].
} }
else -> { else -> {
@@ -30,7 +30,7 @@ internal class CoverageManager(val context: Context) {
private val llvmProfileFilenameGlobal = "__llvm_profile_filename" private val llvmProfileFilenameGlobal = "__llvm_profile_filename"
private val defaultOutputFilePath: String by lazy { private val defaultOutputFilePath: String by lazy {
"${context.config.outputFile}.profraw" "${context.generationState.outputFile}.profraw"
} }
private val outputFileName: String = private val outputFileName: String =
@@ -124,8 +124,8 @@ internal class CoverageManager(val context: Context) {
internal fun runCoveragePass(context: Context) { internal fun runCoveragePass(context: Context) {
if (!context.coverage.enabled) return if (!context.coverage.enabled) return
val passManager = LLVMCreatePassManager()!! val passManager = LLVMCreatePassManager()!!
LLVMKotlinAddTargetLibraryInfoWrapperPass(passManager, context.llvm.targetTriple) LLVMKotlinAddTargetLibraryInfoWrapperPass(passManager, context.generationState.llvm.targetTriple)
context.coverage.addLateLlvmPasses(passManager) context.coverage.addLateLlvmPasses(passManager)
LLVMRunPassManager(passManager, context.llvmModule) LLVMRunPassManager(passManager, context.generationState.llvm.module)
LLVMDisposePassManager(passManager) LLVMDisposePassManager(passManager)
} }
@@ -41,7 +41,7 @@ internal class LLVMCoverageInstrumentation(
val numberOfRegions = Int32(functionRegions.regions.size).llvm val numberOfRegions = Int32(functionRegions.regions.size).llvm
val regionNumber = Int32(functionRegions.regionEnumeration.getValue(region)).llvm val regionNumber = Int32(functionRegions.regionEnumeration.getValue(region)).llvm
val args = listOf(functionNameGlobal, functionHash, numberOfRegions, regionNumber) val args = listOf(functionNameGlobal, functionHash, numberOfRegions, regionNumber)
callSitePlacer(LLVMInstrProfIncrement(context.llvmModule)!!, args) callSitePlacer(LLVMInstrProfIncrement(context.generationState.llvm.module)!!, args)
} }
// Each profiled function should have a global with its name in a specific format. // Each profiled function should have a global with its name in a specific format.
@@ -30,7 +30,7 @@ private fun LLVMCoverageRegion.populateFrom(region: Region, regionId: Int, files
} }
/** /**
* Writes all of the coverage information to the [org.jetbrains.kotlin.backend.konan.Context.llvmModule]. * Writes all of the coverage information to the [org.jetbrains.kotlin.backend.konan.NativeGenerationState.llvm.module].
* See http://llvm.org/docs/CoverageMappingFormat.html for the format description. * See http://llvm.org/docs/CoverageMappingFormat.html for the format description.
*/ */
internal class LLVMCoverageWriter( internal class LLVMCoverageWriter(
@@ -40,8 +40,7 @@ internal class LLVMCoverageWriter(
fun write() { fun write() {
if (filesRegionsInfo.isEmpty()) return if (filesRegionsInfo.isEmpty()) return
val module = context.llvmModule val module = context.generationState.llvm.module
?: error("LLVM module should be initialized.")
val filesIndex = filesRegionsInfo.mapIndexed { index, fileRegionInfo -> fileRegionInfo.file to index }.toMap() val filesIndex = filesRegionsInfo.mapIndexed { index, fileRegionInfo -> fileRegionInfo.file to index }.toMap()
val coverageGlobal = memScoped { val coverageGlobal = memScoped {
@@ -54,8 +53,8 @@ internal class LLVMCoverageWriter(
fileIds.toCValues(), fileIds.size.signExtend(), fileIds.toCValues(), fileIds.size.signExtend(),
regions.toCValues(), regions.size.signExtend()) regions.toCValues(), regions.size.signExtend())
val functionName = context.llvmDeclarations.forFunction(functionRegions.function).llvmValue.name val functionName = context.generationState.llvmDeclarations.forFunction(functionRegions.function).llvmValue.name
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(context.llvmModule), val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(context.generationState.llvm.module),
functionName, functionRegions.structuralHash, functionCoverage)!! functionName, functionRegions.structuralHash, functionCoverage)!!
Pair(functionMappingRecord, functionCoverage) Pair(functionMappingRecord, functionCoverage)
@@ -70,6 +69,6 @@ internal class LLVMCoverageWriter(
retval retval
} }
context.llvm.usedGlobals.add(coverageGlobal) context.generationState.llvm.usedGlobals.add(coverageGlobal)
} }
} }
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
internal open class ObjCCodeGenerator(val codegen: CodeGenerator) { internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
val context = codegen.context val context = codegen.context
val llvm = codegen.llvm
val dataGenerator = codegen.objCDataGenerator!! val dataGenerator = codegen.objCDataGenerator!!
@@ -26,7 +27,7 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
} }
private val objcMsgSend = constPointer( private val objcMsgSend = constPointer(
context.llvm.externalFunction(LlvmFunctionProto( llvm.externalFunction(LlvmFunctionProto(
"objc_msgSend", "objc_msgSend",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr), LlvmParamType(int8TypePtr)),
@@ -43,17 +44,17 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
listOf(LlvmFunctionAttribute.NoUnwind), listOf(LlvmFunctionAttribute.NoUnwind),
origin = context.stdlibModule.llvmSymbolOrigin origin = context.stdlibModule.llvmSymbolOrigin
) )
context.llvm.externalFunction(proto) llvm.externalFunction(proto)
} }
val objcAlloc = context.llvm.externalFunction(LlvmFunctionProto( val objcAlloc = llvm.externalFunction(LlvmFunctionProto(
"objc_alloc", "objc_alloc",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
origin = context.stdlibModule.llvmSymbolOrigin origin = context.stdlibModule.llvmSymbolOrigin
)) ))
val objcAutoreleaseReturnValue = context.llvm.externalFunction(LlvmFunctionProto( val objcAutoreleaseReturnValue = llvm.externalFunction(LlvmFunctionProto(
"llvm.objc.autoreleaseReturnValue", "llvm.objc.autoreleaseReturnValue",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
@@ -61,7 +62,7 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
origin = context.stdlibModule.llvmSymbolOrigin origin = context.stdlibModule.llvmSymbolOrigin
)) ))
val objcRetainAutoreleasedReturnValue = context.llvm.externalFunction(LlvmFunctionProto( val objcRetainAutoreleasedReturnValue = llvm.externalFunction(LlvmFunctionProto(
"llvm.objc.retainAutoreleasedReturnValue", "llvm.objc.retainAutoreleasedReturnValue",
LlvmRetType(int8TypePtr), LlvmRetType(int8TypePtr),
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.descriptors.konan.CurrentKlibModuleOrigin
internal class ObjCDataGenerator(val codegen: CodeGenerator) { internal class ObjCDataGenerator(val codegen: CodeGenerator) {
val context = codegen.context val context = codegen.context
val llvm = codegen.llvm
fun finishModule() { fun finishModule() {
addModuleClassList( addModuleClassList(
@@ -39,7 +40,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
global.setAlignment(codegen.runtime.pointerAlignment) global.setAlignment(codegen.runtime.pointerAlignment)
global.setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip") global.setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip")
context.llvm.compilerUsedGlobals += global.llvmGlobal llvm.compilerUsedGlobals += global.llvmGlobal
global.pointer global.pointer
} }
@@ -52,7 +53,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
it.setAlignment(codegen.runtime.pointerAlignment) it.setAlignment(codegen.runtime.pointerAlignment)
} }
context.llvm.compilerUsedGlobals += global.pointer.llvm llvm.compilerUsedGlobals += global.pointer.llvm
global.pointer.bitcast(pointerType(int8TypePtr)) global.pointer.bitcast(pointerType(int8TypePtr))
} }
@@ -60,8 +61,8 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private val classObjectType = codegen.runtime.objCClassObjectType private val classObjectType = codegen.runtime.objCClassObjectType
fun exportClass(name: String) { fun exportClass(name: String) {
context.llvm.usedGlobals += getClassGlobal(name, isMetaclass = false).llvm llvm.usedGlobals += getClassGlobal(name, isMetaclass = false).llvm
context.llvm.usedGlobals += getClassGlobal(name, isMetaclass = true).llvm llvm.usedGlobals += getClassGlobal(name, isMetaclass = true).llvm
} }
private fun getClassGlobal(name: String, isMetaclass: Boolean): ConstPointer { private fun getClassGlobal(name: String, isMetaclass: Boolean): ConstPointer {
@@ -74,7 +75,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
val globalName = prefix + name val globalName = prefix + name
// TODO: refactor usages and use [Global] class. // TODO: refactor usages and use [Global] class.
val llvmGlobal = LLVMGetNamedGlobal(context.llvmModule, globalName) ?: val llvmGlobal = LLVMGetNamedGlobal(llvm.module, globalName) ?:
codegen.importGlobal(globalName, classObjectType, CurrentKlibModuleOrigin) codegen.importGlobal(globalName, classObjectType, CurrentKlibModuleOrigin)
return constPointer(llvmGlobal) return constPointer(llvmGlobal)
@@ -95,7 +96,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
class Method(val selector: String, val encoding: String, val imp: ConstPointer) class Method(val selector: String, val encoding: String, val imp: ConstPointer)
fun emitClass(name: String, superName: String, instanceMethods: List<Method>) { fun emitClass(name: String, superName: String, instanceMethods: List<Method>) {
val runtime = context.llvm.runtime val runtime = llvm.runtime
val classRoType = runtime.objCClassRoType val classRoType = runtime.objCClassRoType
val methodType = runtime.objCMethodType val methodType = runtime.objCMethodType
@@ -120,13 +121,13 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
) )
val globalName = "\u0001l_OBJC_\$_INSTANCE_METHODS_$name" val globalName = "\u0001l_OBJC_\$_INSTANCE_METHODS_$name"
val global = context.llvm.staticData.placeGlobal(globalName, methodList).also { val global = llvm.staticData.placeGlobal(globalName, methodList).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage) it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment) it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const") it.setSection("__DATA, __objc_const")
} }
context.llvm.compilerUsedGlobals += global.llvmGlobal llvm.compilerUsedGlobals += global.llvmGlobal
return global.pointer.bitcast(pointerType(methodListType)) return global.pointer.bitcast(pointerType(methodListType))
} }
@@ -169,7 +170,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
"\u0001l_OBJC_CLASS_RO_\$_" "\u0001l_OBJC_CLASS_RO_\$_"
} + name } + name
val roGlobal = context.llvm.staticData.placeGlobal(roLabel, roValue).also { val roGlobal = llvm.staticData.placeGlobal(roLabel, roValue).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage) it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment) it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const") it.setSection("__DATA, __objc_const")
@@ -200,7 +201,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
LLVMSetSection(classGlobal.llvm, "__DATA, __objc_data") LLVMSetSection(classGlobal.llvm, "__DATA, __objc_data")
LLVMSetAlignment(classGlobal.llvm, LLVMABIAlignmentOfType(runtime.targetData, classObjectType)) LLVMSetAlignment(classGlobal.llvm, LLVMABIAlignmentOfType(runtime.targetData, classObjectType))
context.llvm.usedGlobals.add(classGlobal.llvm) llvm.usedGlobals.add(classGlobal.llvm)
return classGlobal return classGlobal
} }
@@ -227,7 +228,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) { private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) {
if (elements.isEmpty()) return if (elements.isEmpty()) return
val global = context.llvm.staticData.placeGlobalArray( val global = llvm.staticData.placeGlobalArray(
name, name,
int8TypePtr, int8TypePtr,
elements.map { it.bitcast(int8TypePtr) } elements.map { it.bitcast(int8TypePtr) }
@@ -235,14 +236,14 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
global.setAlignment( global.setAlignment(
LLVMABIAlignmentOfType( LLVMABIAlignmentOfType(
context.llvm.runtime.targetData, llvm.runtime.targetData,
LLVMGetInitializer(global.llvmGlobal)!!.type LLVMGetInitializer(global.llvmGlobal)!!.type
) )
) )
global.setSection(section) global.setSection(section)
context.llvm.compilerUsedGlobals += global.llvmGlobal llvm.compilerUsedGlobals += global.llvmGlobal
} }
private val classNames = CStringLiteralsTable(classNameGenerator) private val classNames = CStringLiteralsTable(classNameGenerator)
@@ -256,8 +257,8 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private val literals = mutableMapOf<String, ConstPointer>() private val literals = mutableMapOf<String, ConstPointer>()
fun get(value: String) = literals.getOrPut(value) { fun get(value: String) = literals.getOrPut(value) {
val globalPointer = generator.generate(context.llvmModule!!, value) val globalPointer = generator.generate(llvm.module, value)
context.llvm.compilerUsedGlobals += globalPointer.llvm llvm.compilerUsedGlobals += globalPointer.llvm
globalPointer.getElementPtr(0) globalPointer.getElementPtr(0)
} }
} }
@@ -42,7 +42,7 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
thisRef thisRef
} }
val blockPtr = callFromBridge( val blockPtr = callFromBridge(
context.llvm.Kotlin_ObjCExport_GetAssociatedObject, llvm.Kotlin_ObjCExport_GetAssociatedObject,
listOf(associatedObjectHolder) listOf(associatedObjectHolder)
) )
@@ -133,7 +133,7 @@ private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
associatedObject: LLVMValueRef, associatedObject: LLVMValueRef,
resultLifetime: Lifetime resultLifetime: Lifetime
): LLVMValueRef = call( ): LLVMValueRef = call(
context.llvm.Kotlin_ObjCExport_AllocInstanceWithAssociatedObject, llvm.Kotlin_ObjCExport_AllocInstanceWithAssociatedObject,
listOf(typeInfo.llvm, associatedObject), listOf(typeInfo.llvm, associatedObject),
resultLifetime resultLifetime
) )
@@ -170,7 +170,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
) { ) {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0)) val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
val refHolder = structGep(blockPtr, 1) val refHolder = structGep(blockPtr, 1)
call(context.llvm.kRefSharedHolderDispose, listOf(refHolder)) call(llvm.kRefSharedHolderDispose, listOf(refHolder))
ret(null) ret(null)
}.also { }.also {
@@ -192,20 +192,20 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
// so it is technically not necessary to check owner. // so it is technically not necessary to check owner.
// However this is not guaranteed by Objective-C runtime, so keep it suboptimal but reliable: // However this is not guaranteed by Objective-C runtime, so keep it suboptimal but reliable:
val ref = call( val ref = call(
context.llvm.kRefSharedHolderRef, llvm.kRefSharedHolderRef,
listOf(srcRefHolder), listOf(srcRefHolder),
exceptionHandler = ExceptionHandler.Caller, exceptionHandler = ExceptionHandler.Caller,
verbatim = true verbatim = true
) )
call(context.llvm.kRefSharedHolderInit, listOf(dstRefHolder, ref)) call(llvm.kRefSharedHolderInit, listOf(dstRefHolder, ref))
ret(null) ret(null)
}.also { }.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
} }
fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) = fun CodeGenerator.LongInt(value: Long) =
when (val longWidth = llvm.longTypeWidth) { when (val longWidth = llvm.longTypeWidth) {
32L -> Int32(value.toInt()) 32L -> Int32(value.toInt())
64L -> Int64(value) 64L -> Int64(value)
@@ -231,8 +231,8 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
} }
return Struct(codegen.runtime.blockDescriptorType, return Struct(codegen.runtime.blockDescriptorType,
codegen.context.LongInt(0L), codegen.LongInt(0L),
codegen.context.LongInt(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)), codegen.LongInt(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)),
constPointer(copyHelper), constPointer(copyHelper),
constPointer(disposeHelper), constPointer(disposeHelper),
codegen.staticData.cStringLiteral(signature), codegen.staticData.cStringLiteral(signature),
@@ -251,7 +251,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
}.generate { }.generate {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0)) val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
val kotlinObject = call( val kotlinObject = call(
context.llvm.kRefSharedHolderRef, llvm.kRefSharedHolderRef,
listOf(structGep(blockPtr, 1)), listOf(structGep(blockPtr, 1)),
exceptionHandler = ExceptionHandler.Caller, exceptionHandler = ExceptionHandler.Caller,
verbatim = true verbatim = true
@@ -334,7 +334,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
store(value, structGep(blockOnStackBase, index)) store(value, structGep(blockOnStackBase, index))
} }
call(context.llvm.kRefSharedHolderInitLocal, listOf(refHolder, kotlinRef)) call(llvm.kRefSharedHolderInitLocal, listOf(refHolder, kotlinRef))
val copiedBlock = callFromBridge(retainBlock, listOf(bitcast(int8TypePtr, blockOnStack))) val copiedBlock = callFromBridge(retainBlock, listOf(bitcast(int8TypePtr, blockOnStack)))
@@ -353,5 +353,5 @@ private val ObjCExportCodeGeneratorBase.retainBlock: LlvmCallable
listOf(LlvmParamType(int8TypePtr)), listOf(LlvmParamType(int8TypePtr)),
origin = CurrentKlibModuleOrigin origin = CurrentKlibModuleOrigin
) )
return context.llvm.externalFunction(functionProto) return llvm.externalFunction(functionProto)
} }
@@ -218,7 +218,7 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
val rttiGenerator = RTTIGenerator(context) val rttiGenerator = RTTIGenerator(context)
private val objcTerminate: LlvmCallable by lazy { private val objcTerminate: LlvmCallable by lazy {
context.llvm.externalFunction(LlvmFunctionProto( llvm.externalFunction(LlvmFunctionProto(
"objc_terminate", "objc_terminate",
LlvmRetType(voidType), LlvmRetType(voidType),
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind), functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
@@ -255,13 +255,13 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
} }
fun ObjCExportFunctionGenerationContext.kotlinReferenceToLocalObjC(value: LLVMValueRef) = fun ObjCExportFunctionGenerationContext.kotlinReferenceToLocalObjC(value: LLVMValueRef) =
callFromBridge(context.llvm.Kotlin_ObjCExport_refToLocalObjC, listOf(value)) callFromBridge(llvm.Kotlin_ObjCExport_refToLocalObjC, listOf(value))
fun ObjCExportFunctionGenerationContext.kotlinReferenceToRetainedObjC(value: LLVMValueRef) = fun ObjCExportFunctionGenerationContext.kotlinReferenceToRetainedObjC(value: LLVMValueRef) =
callFromBridge(context.llvm.Kotlin_ObjCExport_refToRetainedObjC, listOf(value)) callFromBridge(llvm.Kotlin_ObjCExport_refToRetainedObjC, listOf(value))
fun ObjCExportFunctionGenerationContext.objCReferenceToKotlin(value: LLVMValueRef, resultLifetime: Lifetime) = fun ObjCExportFunctionGenerationContext.objCReferenceToKotlin(value: LLVMValueRef, resultLifetime: Lifetime) =
callFromBridge(context.llvm.Kotlin_ObjCExport_refFromObjC, listOf(value), resultLifetime) callFromBridge(llvm.Kotlin_ObjCExport_refFromObjC, listOf(value), resultLifetime)
private val blockToKotlinFunctionConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>() private val blockToKotlinFunctionConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>()
@@ -536,7 +536,7 @@ internal class ObjCExportCodeGenerator(
LLVMSetLinkage(initializer, LLVMLinkage.LLVMInternalLinkage) LLVMSetLinkage(initializer, LLVMLinkage.LLVMInternalLinkage)
context.llvm.otherStaticInitializers += initializer llvm.otherStaticInitializers += initializer
} }
private fun emitKt42254Hint() { private fun emitKt42254Hint() {
@@ -551,7 +551,7 @@ internal class ObjCExportCodeGenerator(
val name = "See https://youtrack.jetbrains.com/issue/KT-42254" val name = "See https://youtrack.jetbrains.com/issue/KT-42254"
val global = staticData.placeGlobal(name, Int8(0), isExported = true) val global = staticData.placeGlobal(name, Int8(0), isExported = true)
context.llvm.usedGlobals += global.llvmGlobal llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility) LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
} }
} }
@@ -693,13 +693,13 @@ private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(
val global = codegen.importGlobal(name, value.llvmType, origin) val global = codegen.importGlobal(name, value.llvmType, origin)
externalGlobalInitializers[global] = value externalGlobalInitializers[global] = value
} else { } else {
context.llvmImports.add(origin) context.generationState.llvmImports.add(origin)
val global = staticData.placeGlobal(name, value, isExported = true) val global = staticData.placeGlobal(name, value, isExported = true)
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) { if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
// Note: actually this is required only if global's weak/common definition is in another object file, // 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. // but it is simpler to do this for all globals, considering that all usages can't be removed by DCE anyway.
context.llvm.usedGlobals += global.llvmGlobal llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility) LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
// See also [emitKt42254Hint]. // See also [emitKt42254Hint].
@@ -733,7 +733,7 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
private fun ObjCExportCodeGeneratorBase.setOwnWritableTypeInfo(irClass: IrClass, writableTypeInfoValue: Struct) { private fun ObjCExportCodeGeneratorBase.setOwnWritableTypeInfo(irClass: IrClass, writableTypeInfoValue: Struct) {
require(!codegen.isExternal(irClass)) require(!codegen.isExternal(irClass))
val writeableTypeInfoGlobal = context.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!! val writeableTypeInfoGlobal = context.generationState.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!
writeableTypeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage) writeableTypeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage)
writeableTypeInfoGlobal.setInitializer(writableTypeInfoValue) writeableTypeInfoGlobal.setInitializer(writableTypeInfoValue)
} }
@@ -828,7 +828,7 @@ private fun ObjCExportCodeGenerator.generateContinuationToRetainedCompletionConv
val resultArgument = objCReferenceToKotlin(arguments[0], Lifetime.ARGUMENT) val resultArgument = objCReferenceToKotlin(arguments[0], Lifetime.ARGUMENT)
val errorArgument = arguments[1] val errorArgument = arguments[1]
callFromBridge(context.llvm.Kotlin_ObjCExport_resumeContinuation, listOf(continuation, resultArgument, errorArgument)) callFromBridge(llvm.Kotlin_ObjCExport_resumeContinuation, listOf(continuation, resultArgument, errorArgument))
ret(null) ret(null)
} }
} }
@@ -848,7 +848,7 @@ private fun ObjCExportCodeGenerator.generateUnitContinuationToRetainedCompletion
codegen.theUnitInstanceRef.llvm codegen.theUnitInstanceRef.llvm
} }
callFromBridge(context.llvm.Kotlin_ObjCExport_resumeContinuation, listOf(continuation, resultArgument, errorArgument)) callFromBridge(llvm.Kotlin_ObjCExport_resumeContinuation, listOf(continuation, resultArgument, errorArgument))
ret(null) ret(null)
} }
} }
@@ -896,7 +896,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() { private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
setObjCExportTypeInfo( setObjCExportTypeInfo(
symbols.string.owner, symbols.string.owner,
constPointer(context.llvm.Kotlin_ObjCExport_CreateRetainedNSStringFromKString.llvmValue) constPointer(llvm.Kotlin_ObjCExport_CreateRetainedNSStringFromKString.llvmValue)
) )
emitCollectionConverters() emitCollectionConverters()
@@ -906,7 +906,7 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
private fun ObjCExportCodeGenerator.emitCollectionConverters() { private fun ObjCExportCodeGenerator.emitCollectionConverters() {
fun importConverter(name: String): ConstPointer = constPointer(context.llvm.externalFunction(LlvmFunctionProto( fun importConverter(name: String): ConstPointer = constPointer(llvm.externalFunction(LlvmFunctionProto(
name, name,
kotlinToObjCFunctionType, kotlinToObjCFunctionType,
origin = CurrentKlibModuleOrigin origin = CurrentKlibModuleOrigin
@@ -974,7 +974,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: MethodBridge, baseMethod: IrFunction): LLVMValueRef = private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: MethodBridge, baseMethod: IrFunction): LLVMValueRef =
generateObjCImpBy(methodBridge, suffix = baseMethod.computeSymbolName()) { generateObjCImpBy(methodBridge, suffix = baseMethod.computeSymbolName()) {
callFromBridge( callFromBridge(
context.llvm.Kotlin_ObjCExport_AbstractMethodCalled, llvm.Kotlin_ObjCExport_AbstractMethodCalled,
listOf(param(0), param(1)) listOf(param(0), param(1))
) )
unreachable() unreachable()
@@ -996,7 +996,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
) { args, resultLifetime, exceptionHandler -> ) { args, resultLifetime, exceptionHandler ->
if (target is IrConstructor && target.constructedClass.isAbstract()) { if (target is IrConstructor && target.constructedClass.isAbstract()) {
callFromBridge( callFromBridge(
context.llvm.Kotlin_ObjCExport_AbstractClassConstructorCalled, llvm.Kotlin_ObjCExport_AbstractClassConstructorCalled,
listOf(param(0), codegen.typeInfoValue(target.parent as IrClass)) listOf(param(0), codegen.typeInfoValue(target.parent as IrClass))
) )
} }
@@ -1060,9 +1060,9 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
is MethodBridgeValueParameter.SuspendCompletion -> { is MethodBridgeValueParameter.SuspendCompletion -> {
val createContinuationArgument = if (paramBridge.useUnitCompletion) { val createContinuationArgument = if (paramBridge.useUnitCompletion) {
context.llvm.Kotlin_ObjCExport_createUnitContinuationArgument llvm.Kotlin_ObjCExport_createUnitContinuationArgument
} else { } else {
context.llvm.Kotlin_ObjCExport_createContinuationArgument llvm.Kotlin_ObjCExport_createContinuationArgument
} }
callFromBridge( callFromBridge(
createContinuationArgument, createContinuationArgument,
@@ -1079,7 +1079,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
val exceptionHandler = when { val exceptionHandler = when {
errorOutPtr != null -> kotlinExceptionHandler { exception -> errorOutPtr != null -> kotlinExceptionHandler { exception ->
callFromBridge( callFromBridge(
context.llvm.Kotlin_ObjCExport_RethrowExceptionAsNSError, llvm.Kotlin_ObjCExport_RethrowExceptionAsNSError,
listOf(exception, errorOutPtr!!, generateExceptionTypeInfoArray(baseMethod!!)) listOf(exception, errorOutPtr!!, generateExceptionTypeInfoArray(baseMethod!!))
) )
@@ -1209,7 +1209,7 @@ private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
methodBridge: MethodBridge methodBridge: MethodBridge
): LLVMValueRef = generateObjCImp(methodBridge, bridgeSuffix = target.computeSymbolName(), isDirect = true) { args, resultLifetime, exceptionHandler -> ): LLVMValueRef = generateObjCImp(methodBridge, bridgeSuffix = target.computeSymbolName(), isDirect = true) { args, resultLifetime, exceptionHandler ->
val arrayInstance = callFromBridge( val arrayInstance = callFromBridge(
context.llvm.allocArrayFunction, llvm.allocArrayFunction,
listOf(target.constructedClass.llvmTypeInfoPtr, args.first()), listOf(target.constructedClass.llvmTypeInfoPtr, args.first()),
resultLifetime = Lifetime.ARGUMENT resultLifetime = Lifetime.ARGUMENT
) )
@@ -1336,7 +1336,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
fun rethrow() { fun rethrow() {
val error = load(errorOutPtr!!) val error = load(errorOutPtr!!)
val exception = callFromBridge( val exception = callFromBridge(
context.llvm.Kotlin_ObjCExport_NSErrorAsException, llvm.Kotlin_ObjCExport_NSErrorAsException,
listOf(error), listOf(error),
resultLifetime = Lifetime.THROW resultLifetime = Lifetime.THROW
) )
@@ -1887,7 +1887,7 @@ private fun ObjCExportCodeGenerator.createUnitInstanceAdapter(selector: String)
// Note: generateObjCToKotlinSyntheticGetter switches to Runnable, which is probably not required here and thus suboptimal. // Note: generateObjCToKotlinSyntheticGetter switches to Runnable, which is probably not required here and thus suboptimal.
initRuntimeIfNeeded() // For instance methods it gets called when allocating. initRuntimeIfNeeded() // For instance methods it gets called when allocating.
autoreleaseAndRet(callFromBridge(context.llvm.Kotlin_ObjCExport_convertUnitToRetained, listOf(codegen.theUnitInstanceRef.llvm))) autoreleaseAndRet(callFromBridge(llvm.Kotlin_ObjCExport_convertUnitToRetained, listOf(codegen.theUnitInstanceRef.llvm)))
} }
private fun ObjCExportCodeGenerator.createObjectInstanceAdapter( private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
@@ -1942,7 +1942,7 @@ private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportC
val imp = generateObjCImpBy(methodBridge, suffix = "ThrowableAsError") { val imp = generateObjCImpBy(methodBridge, suffix = "ThrowableAsError") {
val exception = objCReferenceToKotlin(param(0), Lifetime.ARGUMENT) val exception = objCReferenceToKotlin(param(0), Lifetime.ARGUMENT)
ret(callFromBridge(context.llvm.Kotlin_ObjCExport_WrapExceptionToNSError, listOf(exception))) ret(callFromBridge(llvm.Kotlin_ObjCExport_WrapExceptionToNSError, listOf(exception)))
} }
val selector = ObjCExportNamer.kotlinThrowableAsErrorMethodName val selector = ObjCExportNamer.kotlinThrowableAsErrorMethodName
@@ -2045,5 +2045,5 @@ private fun Context.is64BitNSInteger(): Boolean {
require(configurables is AppleConfigurables) { require(configurables is AppleConfigurables) {
"Target ${configurables.target} has no support for NSInteger type." "Target ${configurables.target} has no support for NSInteger type."
} }
return llvm.nsIntegerTypeWidth == 64L return generationState.llvm.nsIntegerTypeWidth == 64L
} }
@@ -32,7 +32,7 @@ internal class CacheInfoBuilder(private val context: Context, private val module
if (!declaration.isInterface && !declaration.isLocal if (!declaration.isInterface && !declaration.isLocal
&& declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS && declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS
) { ) {
context.classFields.add(buildClassFields(declaration, context.getLayoutBuilder(declaration).getDeclaredFields())) context.generationState.classFields.add(buildClassFields(declaration, context.getLayoutBuilder(declaration).getDeclaredFields()))
} }
} }
@@ -41,7 +41,7 @@ internal class CacheInfoBuilder(private val context: Context, private val module
// as for functions - both their callees will be handled and inline bodies will be built for the top function. // 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) { if (!declaration.isFakeOverride && declaration.isInline && declaration.isExported) {
context.inlineFunctionBodies.add(buildInlineFunctionReference(declaration)) context.generationState.inlineFunctionBodies.add(buildInlineFunctionReference(declaration))
trackCallees(declaration) trackCallees(declaration)
} }
} }
@@ -64,8 +64,10 @@ internal class CacheInfoBuilder(private val context: Context, private val module
private fun processFunction(function: IrFunction) { private fun processFunction(function: IrFunction) {
if (function.getPackageFragment() !is IrExternalPackageFragment) { if (function.getPackageFragment() !is IrExternalPackageFragment) {
context.calledFromExportedInlineFunctions.add(function) context.generationState.calledFromExportedInlineFunctions.add(function)
(function as? IrConstructor)?.constructedClass?.let { context.constructedFromExportedInlineFunctions.add(it) } (function as? IrConstructor)?.constructedClass?.let {
context.generationState.constructedFromExportedInlineFunctions.add(it)
}
if (function.isInline && !function.isExported) { if (function.isInline && !function.isExported) {
// An exported inline function calls a non-exported inline function: // An exported inline function calls a non-exported inline function:
// should track its callees as well as it won't be handled by the main visitor. // should track its callees as well as it won't be handled by the main visitor.
@@ -199,6 +199,7 @@ internal class ExportCachesAbiVisitor(val context: Context) : FileLoweringPass,
internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPass, IrElementTransformerVoid() { internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPass, IrElementTransformerVoid() {
private val cachesAbiSupport = context.cachesAbiSupport private val cachesAbiSupport = context.cachesAbiSupport
private val enumsSupport = context.enumsSupport private val enumsSupport = context.enumsSupport
private val llvmImports = context.generationState.llvmImports
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(this) irFile.transformChildrenVoid(this)
@@ -217,7 +218,7 @@ internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPa
return expression return expression
} }
val accessor = cachesAbiSupport.getCompanionObjectAccessor(irClass) val accessor = cachesAbiSupport.getCompanionObjectAccessor(irClass)
context.llvmImports.add(irClass.llvmSymbolOrigin) llvmImports.add(irClass.llvmSymbolOrigin)
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()) return irCall(expression.startOffset, expression.endOffset, accessor, emptyList())
} }
@@ -233,7 +234,7 @@ internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPa
irClass?.isInner == true && context.innerClassesSupport.getOuterThisField(irClass) == field -> { irClass?.isInner == true && context.innerClassesSupport.getOuterThisField(irClass) == field -> {
val accessor = cachesAbiSupport.getOuterThisAccessor(irClass) val accessor = cachesAbiSupport.getOuterThisAccessor(irClass)
context.llvmImports.add(irClass.llvmSymbolOrigin) llvmImports.add(irClass.llvmSymbolOrigin)
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply { return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
putValueArgument(0, expression.receiver) putValueArgument(0, expression.receiver)
} }
@@ -241,7 +242,7 @@ internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPa
property?.isLateinit == true -> { property?.isLateinit == true -> {
val accessor = cachesAbiSupport.getLateinitPropertyAccessor(property) val accessor = cachesAbiSupport.getLateinitPropertyAccessor(property)
context.llvmImports.add(property.llvmSymbolOrigin) llvmImports.add(property.llvmSymbolOrigin)
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply { return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
if (irClass != null) if (irClass != null)
putValueArgument(0, expression.receiver) putValueArgument(0, expression.receiver)
@@ -255,7 +256,7 @@ internal class ImportCachesAbiTransformer(val context: Context) : FileLoweringPa
require(enumsSupport.getImplObject(enumClass) == irClass) { "Expected a enum's impl object: ${irClass.render()}" } require(enumsSupport.getImplObject(enumClass) == irClass) { "Expected a enum's impl object: ${irClass.render()}" }
require(field == enumsSupport.getValuesField(irClass)) { "Expected VALUES field: ${field.render()}" } require(field == enumsSupport.getValuesField(irClass)) { "Expected VALUES field: ${field.render()}" }
val accessor = cachesAbiSupport.getEnumValuesAccessor(enumClass) val accessor = cachesAbiSupport.getEnumValuesAccessor(enumClass)
context.llvmImports.add(enumClass.llvmSymbolOrigin) llvmImports.add(enumClass.llvmSymbolOrigin)
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()) return irCall(expression.startOffset, expression.endOffset, accessor, emptyList())
} }
@@ -223,7 +223,7 @@ internal class FunctionReferenceLowering(val context: Context) : FileLoweringPas
createParameterDeclarations() createParameterDeclarations()
// copy the generated name for IrClass, partially solves KT-47194 // copy the generated name for IrClass, partially solves KT-47194
context.copyLocalClassName(functionReference, this) context.generationState.copyLocalClassName(functionReference, this)
} }
private val functionReferenceThis = functionReferenceClass.thisReceiver!! private val functionReferenceThis = functionReferenceClass.thisReceiver!!
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.cgen.* import org.jetbrains.kotlin.backend.konan.cgen.*
@@ -98,11 +97,11 @@ private abstract class BaseInteropIrTransformer(private val context: Context) :
} }
override fun addC(lines: List<String>) { override fun addC(lines: List<String>) {
context.cStubsManager.addStub(location, lines, language) context.generationState.cStubsManager.addStub(location, lines, language)
} }
override fun getUniqueCName(prefix: String) = override fun getUniqueCName(prefix: String) =
"$uniquePrefix${context.cStubsManager.getUniqueName(prefix)}" "$uniquePrefix${context.generationState.cStubsManager.getUniqueName(prefix)}"
override fun getUniqueKotlinFunctionReferenceClassName(prefix: String) = override fun getUniqueKotlinFunctionReferenceClassName(prefix: String) =
"$prefix${context.functionReferenceCount++}" "$prefix${context.functionReferenceCount++}"
@@ -538,7 +537,7 @@ private class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfor
): IrExpression = generateWithStubs(call) { ): IrExpression = generateWithStubs(call) {
if (method.parent !is IrClass) { if (method.parent !is IrClass) {
// Category-provided. // Category-provided.
this@InteropLoweringPart1.context.llvmImports.add(method.llvmSymbolOrigin) this@InteropLoweringPart1.context.generationState.llvmImports.add(method.llvmSymbolOrigin)
} }
this.generateObjCCall( this.generateObjCCall(
@@ -1002,7 +1001,7 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
private fun generateCCall(expression: IrCall): IrExpression { private fun generateCCall(expression: IrCall): IrExpression {
val function = expression.symbol.owner val function = expression.symbol.owner
context.llvmImports.add(function.llvmSymbolOrigin) context.generationState.llvmImports.add(function.llvmSymbolOrigin)
val exceptionMode = ForeignExceptionMode.byValue( val exceptionMode = ForeignExceptionMode.byValue(
function.konanLibrary?.manifestProperties?.getProperty(ForeignExceptionMode.manifestKey) function.konanLibrary?.manifestProperties?.getProperty(ForeignExceptionMode.manifestKey)
) )
@@ -15,10 +15,8 @@ import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.deepCopyWithVariables import org.jetbrains.kotlin.ir.deepCopyWithVariables
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
internal class InlineFunctionsSupport(mapping: NativeMapping) { internal class InlineFunctionsSupport(mapping: NativeMapping) {
private val notLoweredInlineFunctions = mapping.notLoweredInlineFunctions private val notLoweredInlineFunctions = mapping.notLoweredInlineFunctions
@@ -43,12 +41,12 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { override fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val function = super.getFunctionDeclaration(symbol) val function = super.getFunctionDeclaration(symbol)
context.mapping.loweredInlineFunctions[function]?.let { return it.irFunction } context.generationState.loweredInlineFunctions[function]?.let { return it.irFunction }
val packageFragment = function.getPackageFragment() val packageFragment = function.getPackageFragment()
val (possiblyLoweredFunction, shouldLower) = if (packageFragment !is IrExternalPackageFragment) { val (possiblyLoweredFunction, shouldLower) = if (packageFragment !is IrExternalPackageFragment) {
context.inlineFunctionsSupport.getNonLoweredInlineFunction(function, copy = context.config.produceBatchedPerFileCache).also { context.inlineFunctionsSupport.getNonLoweredInlineFunction(function, copy = context.config.produceBatchedPerFileCache).also {
context.mapping.loweredInlineFunctions[function] = context.generationState.loweredInlineFunctions[function] =
InlineFunctionOriginInfo(it, packageFragment as IrFile, function.startOffset, function.endOffset) InlineFunctionOriginInfo(it, packageFragment as IrFile, function.startOffset, function.endOffset)
} to true } to true
} else { } else {
@@ -60,7 +58,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
"No IR and no cache for ${function.render()}" "No IR and no cache for ${function.render()}"
} }
val (shouldLower, deserializedInlineFunction) = moduleDeserializer.deserializeInlineFunction(function) val (shouldLower, deserializedInlineFunction) = moduleDeserializer.deserializeInlineFunction(function)
context.mapping.loweredInlineFunctions[function] = deserializedInlineFunction context.generationState.loweredInlineFunctions[function] = deserializedInlineFunction
function to shouldLower function to shouldLower
} }
@@ -68,7 +66,7 @@ internal class NativeInlineFunctionResolver(override val context: Context) : Def
val body = possiblyLoweredFunction.body ?: return possiblyLoweredFunction val body = possiblyLoweredFunction.body ?: return possiblyLoweredFunction
PreInlineLowering(context).lower(body, possiblyLoweredFunction, context.mapping.loweredInlineFunctions[function]!!.irFile) PreInlineLowering(context).lower(body, possiblyLoweredFunction, context.generationState.loweredInlineFunctions[function]!!.irFile)
ArrayConstructorLowering(context).lower(body, possiblyLoweredFunction) ArrayConstructorLowering(context).lower(body, possiblyLoweredFunction)
@@ -16,6 +16,6 @@ internal class NativeInventNamesForLocalClasses(val context: Context) : InventNa
override fun sanitizeNameIfNeeded(name: String) = name override fun sanitizeNameIfNeeded(name: String) = name
override fun putLocalClassName(declaration: IrAttributeContainer, localClassName: String) { override fun putLocalClassName(declaration: IrAttributeContainer, localClassName: String) {
context.putLocalClassName(declaration, localClassName) context.generationState.putLocalClassName(declaration, localClassName)
} }
} }
@@ -642,7 +642,7 @@ internal class TestProcessor (val context: Context) {
fun recordFunction(suiteClassId: ClassId, function: TestFunction) { fun recordFunction(suiteClassId: ClassId, function: TestFunction) {
if (function.kind == FunctionKind.TEST) if (function.kind == FunctionKind.TEST)
context.testCasesToDump.computeIfAbsent(suiteClassId) { mutableListOf() } += function.functionName context.generationState.testCasesToDump.computeIfAbsent(suiteClassId) { mutableListOf() } += function.functionName
} }
annotationCollector.topLevelFunctions.forEach { function -> annotationCollector.topLevelFunctions.forEach { function ->
@@ -112,7 +112,7 @@ internal class ObjCExport(val context: Context, symbolTable: SymbolTable) {
} }
private fun produceFrameworkSpecific(headerLines: List<String>) { private fun produceFrameworkSpecific(headerLines: List<String>) {
val framework = File(context.config.outputFile) val framework = File(context.generationState.outputFile)
val frameworkContents = when(target.family) { val frameworkContents = when(target.family) {
Family.IOS, Family.IOS,
Family.WATCHOS, Family.WATCHOS,
@@ -293,7 +293,7 @@ internal class ObjCExport(val context: Context, symbolTable: SymbolTable) {
val result = Command(clangCommand).getResult(withErrors = true) val result = Command(clangCommand).getResult(withErrors = true)
if (result.exitCode == 0) { if (result.exitCode == 0) {
context.llvm.additionalProducedBitcodeFiles += bitcode.absolutePath context.generationState.llvm.additionalProducedBitcodeFiles += bitcode.absolutePath
} else { } else {
// Note: ignoring compile errors intentionally. // Note: ignoring compile errors intentionally.
// In this case resulting framework will likely be unusable due to compile errors when importing it. // In this case resulting framework will likely be unusable due to compile errors when importing it.
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.Lifetime
import org.jetbrains.kotlin.backend.konan.logMultiple import org.jetbrains.kotlin.backend.konan.logMultiple
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import kotlin.math.min
private val DataFlowIR.Node.isAlloc private val DataFlowIR.Node.isAlloc
get() = this is DataFlowIR.Node.NewObject || this is DataFlowIR.Node.AllocInstance get() = this is DataFlowIR.Node.NewObject || this is DataFlowIR.Node.AllocInstance
@@ -642,7 +641,7 @@ internal object EscapeAnalysis {
?: (node as? DataFlowIR.Node.Variable) ?: (node as? DataFlowIR.Node.Variable)
?.values?.singleOrNull()?.let { arrayLengthOf(it.node) } ?.values?.singleOrNull()?.let { arrayLengthOf(it.node) }
private val pointerSize = context.llvm.runtime.pointerSize private val pointerSize = context.generationState.runtime.pointerSize
private fun arrayItemSizeOf(irClass: IrClass): Int? = when (irClass.symbol) { private fun arrayItemSizeOf(irClass: IrClass): Int? = when (irClass.symbol) {
symbols.array -> pointerSize symbols.array -> pointerSize
@@ -32,9 +32,9 @@ private fun process(function: LLVMValueRef, currentThreadTLV: LLVMValueRef) {
} }
internal fun removeMultipleThreadDataLoads(context: Context) { internal fun removeMultipleThreadDataLoads(context: Context) {
val currentThreadTLV = context.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return val currentThreadTLV = context.generationState.llvm.runtimeAnnotationMap["current_thread_tlv"]?.singleOrNull() ?: return
getFunctions(context.llvmModule!!) getFunctions(context.generationState.llvm.module)
.filter { it.name?.startsWith("kfun:") == true } .filter { it.name?.startsWith("kfun:") == true }
.filterNot { LLVMIsDeclaration(it) == 1 } .filterNot { LLVMIsDeclaration(it) == 1 }
.forEach { process(it, currentThreadTLV) } .forEach { process(it, currentThreadTLV) }