Compare commits

...

10 Commits

Author SHA1 Message Date
Sergey Bogolepov
a7fd140329 [K/N] Separate compilation POC 2021-08-09 10:28:17 +07:00
Sergey Bogolepov
4bfa5ad532 wip 2021-08-07 11:47:02 +07:00
Sergey Bogolepov
b694fcdac6 wip 2021-08-07 11:46:47 +07:00
Sergey Bogolepov
b991d3cd4c wip 2021-08-07 11:46:37 +07:00
Sergey Bogolepov
f95c1a0996 [K/N] Rename lldLocation to linker
Actually, there is nothing LLD-specific in this property now,
so let's rename it to avoid confusion.
2021-08-07 11:45:55 +07:00
Sergey Bogolepov
216e306e58 [K/N] Invoke MinGW linker directly
There is an overhead of invoking linker via `clang -fuse-ld`. It became
significant in LLVM 11.1.0. Let's avoid it by invoking LLD directly.
2021-08-07 11:45:54 +07:00
Sergey Bogolepov
1b6ff4d8bd wip 2021-08-07 11:20:11 +07:00
Sergey Bogolepov
65358742dd Working with compiler caches 2021-08-07 11:20:11 +07:00
Sergey Bogolepov
e05c139668 brr 2021-08-07 11:20:11 +07:00
Sergey Bogolepov
d7283d2983 brr 2021-08-07 11:20:10 +07:00
56 changed files with 998 additions and 626 deletions

View File

@@ -82,9 +82,9 @@ class NamedCompilerPhase<in Context : CommonBackendContext, Data>(
return input
}
assert(phaserState.alreadyDone.containsAll(prerequisite)) {
"Lowering $name: phases ${(prerequisite - phaserState.alreadyDone).map { it.name }} are required, but not satisfied"
}
// assert(phaserState.alreadyDone.containsAll(prerequisite)) {
// "Lowering $name: phases ${(prerequisite - phaserState.alreadyDone).map { it.name }} are required, but not satisfied"
// }
context.inVerbosePhase = this in phaseConfig.verbose

View File

@@ -35,7 +35,7 @@ fun getOriginalKotlinClass(objCProtocol: ObjCProtocol): KClass<*>? {
}
@SymbolName("Kotlin_ObjCInterop_getTypeInfoForClass")
private external fun getTypeInfoForClass(ptr: NativePtr): NativePtr
private fun getTypeInfoForClass(ptr: NativePtr): NativePtr = NativePtr.NULL
@SymbolName("Kotlin_ObjCInterop_getTypeInfoForProtocol")
private external fun getTypeInfoForProtocol(ptr: NativePtr): NativePtr
private fun getTypeInfoForProtocol(ptr: NativePtr): NativePtr = NativePtr.NULL

View File

@@ -259,7 +259,7 @@ private fun processCLib(flavor: KotlinPlatform, cinteropArguments: CInteropArgum
else -> listOf()
}
val libName = additionalArgs.cstubsName ?: fqParts.joinToString("") + "stubs"
val libName = additionalArgs.cstubsName ?: (fqParts.joinToString("") + "stubs")
val tempFiles = TempFiles(libName, cinteropArguments.tempDir)

View File

@@ -6,7 +6,9 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.*
import java.util.stream.Collectors
typealias BitcodeFile = String
typealias ObjectFile = String
@@ -48,7 +50,7 @@ internal class BitcodeCompiler(val context: Context) {
}
private fun clang(configurables: ClangFlags, file: BitcodeFile): ObjectFile {
val objectFile = temporary("result", ".o")
val objectFile = temporary(File(file).name, ".o")
val targetTriple = if (configurables is AppleConfigurables) {
platform.targetTriple.withOSVersion(configurables.osVersionMin)
@@ -84,9 +86,11 @@ internal class BitcodeCompiler(val context: Context) {
RelocationModeFlags.Mode.DEFAULT -> emptyList()
}
fun makeObjectFiles(bitcodeFile: BitcodeFile): List<ObjectFile> =
listOf(when (val configurables = platform.configurables) {
is ClangFlags -> clang(configurables, bitcodeFile)
fun makeObjectFiles(bitcodeFiles: List<BitcodeFile>): List<ObjectFile> =
when (val configurables = platform.configurables) {
is ClangFlags -> bitcodeFiles.parallelStream().map {
clang(configurables, it)
}.collect(Collectors.toList())
else -> error("Unsupported configurables kind: ${configurables::class.simpleName}!")
})
}
}

View File

@@ -167,13 +167,13 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
* Initialize static boxing.
* If output target is native binary then the cache is created.
*/
internal fun initializeCachedBoxes(context: Context) {
internal fun initializeCachedBoxes(context: Context, codegen: CodeGenerator) {
if (context.producedLlvmModuleContainsStdlib) {
BoxCache.values().forEach { cache ->
val cacheName = "${cache.name}_CACHE"
val rangeStart = "${cache.name}_RANGE_FROM"
val rangeEnd = "${cache.name}_RANGE_TO"
initCache(cache, context, cacheName, rangeStart, rangeEnd)
initCache(cache, context, codegen, cacheName, rangeStart, rangeEnd)
}
}
}
@@ -181,11 +181,11 @@ internal fun initializeCachedBoxes(context: Context) {
/**
* Adds global that refers to the cache.
*/
private fun initCache(cache: BoxCache, context: Context, cacheName: String,
rangeStartName: String, rangeEndName: String) {
private fun initCache(cache: BoxCache, context: Context, codegen: CodeGenerator,
cacheName: String, rangeStartName: String, rangeEndName: String) {
val kotlinType = context.irBuiltIns.getKotlinClass(cache)
val staticData = context.llvm.staticData
val staticData = codegen.llvm.staticData
val llvmType = staticData.getLLVMType(kotlinType.defaultType)
val (start, end) = context.config.target.getBoxCacheRange(cache)
@@ -196,7 +196,7 @@ private fun initCache(cache: BoxCache, context: Context, cacheName: String,
staticData.placeGlobal(rangeEndName, createConstant(llvmType, end), true)
.setConstant(true)
val values = (start..end).map { staticData.createInitializer(kotlinType, createConstant(llvmType, it)) }
val llvmBoxType = structType(context.llvm.runtime.objHeaderType, llvmType)
val llvmBoxType = structType(codegen.llvm.runtime.objHeaderType, llvmType)
staticData.placeGlobalConstArray(cacheName, llvmBoxType, values, true).llvm
}

View File

@@ -237,7 +237,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
val packageFragmentDescriptor = descriptor.findPackage()
val file = filesMap.getOrPut(packageFragmentDescriptor) {
IrFileImpl(NaiveSourceBasedFileEntryImpl("[K][Suspend]Functions"), packageFragmentDescriptor).also {
IrFileImpl(NaiveSourceBasedFileEntryImpl("[K][Suspend]Functions_${packageFragmentDescriptor.fqName}"), packageFragmentDescriptor).also {
this@BuiltInFictitiousFunctionIrClassFactory.module?.files?.add(it)
}
}

View File

@@ -187,10 +187,15 @@ private class ExportedElementScope(val kind: ScopeKind, val name: String) {
}
}
private class ExportedElement(val kind: ElementKind,
val scope: ExportedElementScope,
val declaration: DeclarationDescriptor,
val owner: CAdapterGenerator) : ContextUtils {
private class ExportedElement(
val kind: ElementKind,
val scope: ExportedElementScope,
val declaration: DeclarationDescriptor,
val owner: CAdapterGenerator
) : ContextUtils {
override val llvmModule: LLVMModuleRef = owner.llvmModule
init {
scope.elements.add(this)
}
@@ -226,7 +231,7 @@ private class ExportedElement(val kind: ElementKind,
ret(result)
}
} else {
LLVMAddAlias(context.llvmModule, llvmFunction.type, llvmFunction, cname)!!
LLVMAddAlias(llvmModule, llvmFunction.type, llvmFunction, cname)!!
}
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
}
@@ -236,7 +241,7 @@ private class ExportedElement(val kind: ElementKind,
// Produce type getter.
val getTypeFunction = addLlvmFunctionWithDefaultAttributes(
context,
context.llvmModule!!,
llvmModule,
"${cname}_type",
owner.kGetTypeFuncType
)
@@ -513,7 +518,7 @@ private fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescript
getPackage(it).fragments.filter { it.module == this }
}
internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVisitor<Boolean, Void?> {
internal class CAdapterGenerator(val context: Context, val llvmModule: LLVMModuleRef) : DeclarationDescriptorVisitor<Boolean, Void?> {
private val scopes = mutableListOf<ExportedElementScope>()
internal val prefix = context.config.fullExportedNamePrefix

View File

@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.target.ClangArgs
import org.jetbrains.kotlin.konan.target.KonanTarget
import kotlin.random.Random
private const val dumpBridges = false
@@ -32,6 +33,8 @@ class CStubsManager(private val target: KonanTarget) {
}
else -> ".c"
}
// TODO: We link it into "out" llvm module, so we don't need to bother about naming.
// But if we want to compile it to a separate object, then we should come up with something smarter.
val cSource = createTempFile("cstubs", sourceFileExtension).deleteOnExit()
cSource.writeLines(stubs.flatMap { it.lines })

View File

@@ -26,7 +26,7 @@ private fun LLVMValueRef.isLLVMBuiltin(): Boolean {
}
private class CallsChecker(val context: Context, goodFunctions: List<String>) {
private class CallsChecker(val context: Context, val llvmModule: LLVMModuleRef, goodFunctions: List<String>) {
private val goodFunctionsExact = goodFunctions.filterNot { it.endsWith("*") }.toSet()
private val goodFunctionsByPrefix = goodFunctions.filter { it.endsWith("*") }.map { it.substring(0, it.length - 1) }.sorted()
@@ -39,10 +39,10 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
}
private fun externalFunction(name: String, type: LLVMTypeRef) =
context.llvm.externalFunction(name, type, context.stdlibModule.llvmSymbolOrigin)
moduleToLlvm.getValue(llvmModule).externalFunction(name, type, context.stdlibModule.llvmSymbolOrigin)
private fun moduleFunction(name: String) =
LLVMGetNamedFunction(context.llvmModule, name) ?: throw IllegalStateException("$name function is not available")
LLVMGetNamedFunction(llvmModule, name) ?: throw IllegalStateException("$name function is not available")
val getMethodImpl = externalFunction("class_getMethodImplementation", functionType(pointerType(functionType(voidType, false)), false, int8TypePtr, int8TypePtr))
val getClass = externalFunction("object_getClass", functionType(int8TypePtr, false, int8TypePtr))
@@ -127,8 +127,9 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
calledPtrLlvm = LLVMBuildBitCast(builder, calleeInfo.calledPtr, int8TypePtr, "")
}
}
val callSiteDescriptionLlvm = context.llvm.staticData.cStringLiteral(callSiteDescription).llvm
val calledNameLlvm = if (calledName == null) LLVMConstNull(int8TypePtr) else context.llvm.staticData.cStringLiteral(calledName).llvm
val llvm = moduleToLlvm.getValue(llvmModule)
val callSiteDescriptionLlvm = llvm.staticData.cStringLiteral(callSiteDescription).llvm
val calledNameLlvm = if (calledName == null) LLVMConstNull(int8TypePtr) else llvm.staticData.cStringLiteral(calledName).llvm
LLVMBuildCall(builder, checkerFunction, listOf(callSiteDescriptionLlvm, calledNameLlvm, calledPtrLlvm).toCValues(), 3, "")
}
LLVMDisposeBuilder(builder)
@@ -150,8 +151,8 @@ private class CallsChecker(val context: Context, goodFunctions: List<String>) {
private const val functionListGlobal = "Kotlin_callsCheckerKnownFunctions"
private const val functionListSizeGlobal = "Kotlin_callsCheckerKnownFunctionsCount"
internal fun checkLlvmModuleExternalCalls(context: Context) {
val staticData = context.llvm.staticData
internal fun checkLlvmModuleExternalCalls(context: Context, llvmModule: LLVMModuleRef) {
val staticData = moduleToLlvm.getValue(llvmModule).staticData
val annotations = staticData.getGlobal("llvm.global.annotations")?.getInitializer()
@@ -172,8 +173,8 @@ internal fun checkLlvmModuleExternalCalls(context: Context) {
}.toList()
} ?: emptyList()
val checker = CallsChecker(context, goodFunctions)
getFunctions(context.llvmModule!!)
val checker = CallsChecker(context, llvmModule, goodFunctions)
getFunctions(llvmModule)
.filter { !it.isExternalFunction() && it.name !in ignoredFunctions }
.forEach(checker::processFunction)
// otherwise optimiser can inline it
@@ -183,10 +184,10 @@ internal fun checkLlvmModuleExternalCalls(context: Context) {
}
// this should be a separate pass, to handle DCE correctly
internal fun addFunctionsListSymbolForChecker(context: Context) {
val staticData = context.llvm.staticData
internal fun addFunctionsListSymbolForChecker(context: Context, llvmModule: LLVMModuleRef) {
val staticData = moduleToLlvm.getValue(llvmModule).staticData
val functions = getFunctions(context.llvmModule!!)
val functions = getFunctions(llvmModule)
.filter { !it.isExternalFunction() }
.map { constPointer(it).bitcast(int8TypePtr) }
.toList()

View File

@@ -57,37 +57,97 @@ internal fun produceCStubs(context: Context) {
private fun linkAllDependencies(context: Context, generatedBitcodeFiles: List<String>) {
val config = context.config
val llvmModule = context.llvmModule!!
programBitcode().forEach { fileBitcode ->
val failed = llvmLinkModules2(context, llvmModule, fileBitcode)
if (failed != 0) {
throw Error("failed to link x") // TODO: retrieve error message from LLVM.
}
}
val runtimeNativeLibraries = config.runtimeNativeLibraries
.takeIf { context.producedLlvmModuleContainsStdlib }.orEmpty()
val launcherNativeLibraries = config.launcherNativeLibraries
.takeIf { config.produce == CompilerOutputKind.PROGRAM }.orEmpty()
linkObjC(context)
linkObjC(context, llvmModule)
val nativeLibraries = config.nativeLibraries + runtimeNativeLibraries + launcherNativeLibraries
val bitcodeLibraries = context.llvm.bitcodeToLink.map { it.bitcodePaths }.flatten().filter { it.isBitcode }
val allLlvm = (programBitcode() + llvmModule)
.asSequence()
.map { moduleToLlvm.getValue(it).bitcodeToLink }
.flatten()
.map { it.bitcodePaths }
.flatten()
.filter { it.isBitcode }
.toList()
val bitcodeLibraries = allLlvm.toSet()
val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles
val exceptionsSupportNativeLibrary = config.exceptionsSupportNativeLibrary
val bitcodeFiles = (nativeLibraries + generatedBitcodeFiles + additionalBitcodeFilesToLink + bitcodeLibraries).toMutableSet()
if (config.produce == CompilerOutputKind.DYNAMIC_CACHE)
bitcodeFiles += exceptionsSupportNativeLibrary
val llvmModule = context.llvmModule!!
bitcodeFiles.forEach {
parseAndLinkBitcodeFile(context, llvmModule, it)
}
}
private fun computeClangInput(context: Context, generatedBitcodeFiles: List<String>) {
val config = context.config
val llvmModule = context.llvmModule!!
val (llvmModules, objectFiles) = context.separateCompilation.classifyModules(programBitcode() + llvmModule)
context.linkerInput += objectFiles
context.optimizerInput += llvmModules
val runtimeNativeLibraries = config.runtimeNativeLibraries
.takeIf { context.producedLlvmModuleContainsStdlib }.orEmpty()
val launcherNativeLibraries = config.launcherNativeLibraries
.takeIf { config.produce == CompilerOutputKind.PROGRAM }.orEmpty()
// link bitcode to make entry point pass work.
launcherNativeLibraries.forEach {
parseAndLinkBitcodeFile(context, llvmModule, it)
}
linkObjC(context, llvmModule)
val nativeLibraries = config.nativeLibraries + runtimeNativeLibraries
val allLlvm = programBitcode()
.asSequence()
.map { moduleToLlvm.getValue(it).bitcodeToLink }
.flatten()
.map { it.bitcodePaths }
.flatten()
.filter { it.isBitcode }
.toList()
val bitcodeLibraries = allLlvm.toSet()
val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles
val exceptionsSupportNativeLibrary = config.exceptionsSupportNativeLibrary
val bitcodeFiles = (nativeLibraries + generatedBitcodeFiles + additionalBitcodeFilesToLink + bitcodeLibraries).toMutableSet()
if (config.produce == CompilerOutputKind.DYNAMIC_CACHE)
bitcodeFiles += exceptionsSupportNativeLibrary
val (bitcodes, objects) = context.separateCompilation.classifyBitcode(bitcodeFiles.toList())
context.linkerInput += objects
context.bitcodeFiles += bitcodes
}
private fun insertAliasToEntryPoint(context: Context) {
val nomain = context.config.configuration.get(KonanConfigKeys.NOMAIN) ?: false
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
return
val module = context.llvmModule
val entryPoint = LLVMGetNamedFunction(module, "Konan_main")
?: error("Module doesn't contain `Konan_main`")
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
val module = context.llvmModule!!
LLVMGetNamedFunction(module, "Konan_main")?.let { entryPoint ->
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
}
}
internal fun linkBitcodeDependencies(context: Context) {
@@ -106,13 +166,13 @@ internal fun linkBitcodeDependencies(context: Context) {
if (produce == CompilerOutputKind.FRAMEWORK && context.config.produceStaticFramework) {
embedAppleLinkerOptionsToBitcode(context.llvm, context.config)
}
linkAllDependencies(context, generatedBitcodeFiles)
// linkAllDependencies(context, generatedBitcodeFiles)
computeClangInput(context, generatedBitcodeFiles)
}
internal fun produceOutput(context: Context) {
val config = context.config.configuration
val tempFiles = context.config.tempFiles
val produce = config.get(KonanConfigKeys.PRODUCE)
when (produce) {
@@ -122,12 +182,6 @@ internal fun produceOutput(context: Context) {
CompilerOutputKind.DYNAMIC_CACHE,
CompilerOutputKind.STATIC_CACHE,
CompilerOutputKind.PROGRAM -> {
val output = tempFiles.nativeBinaryFileName
context.bitcodeFileName = output
// Insert `_main` after pipeline so we won't worry about optimizations
// corrupting entry point.
insertAliasToEntryPoint(context)
LLVMWriteBitcodeToFile(context.llvmModule!!, output)
}
CompilerOutputKind.LIBRARY -> {
val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
@@ -157,7 +211,7 @@ internal fun produceOutput(context: Context) {
}
}
val library = buildLibrary(
buildLibrary(
context.config.nativeLibraries,
context.config.includeBinaries,
neededLibraries,
@@ -171,12 +225,9 @@ internal fun produceOutput(context: Context) {
shortLibraryName,
manifestProperties,
context.dataFlowGraph)
context.bitcodeFileName = library.mainBitcodeFileName
}
CompilerOutputKind.BITCODE -> {
val output = context.config.outputFile
context.bitcodeFileName = output
LLVMWriteBitcodeToFile(context.llvmModule!!, output)
}
null -> {}

View File

@@ -345,25 +345,29 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
throw Error("Another LLVMModule in the context.")
}
field = module!!
llvm = Llvm(this, module)
debugInfo = DebugInfo(this)
}
val separateCompilation by lazy { SeparateCompilation(this) }
val optimizerInput: MutableList<LLVMModuleRef> = mutableListOf()
val bitcodeFiles: MutableList<BitcodeFile> = mutableListOf()
lateinit var llvm: Llvm
val llvmImports: LlvmImports = Llvm.ImportsImpl(this)
lateinit var llvmDeclarations: LlvmDeclarations
lateinit var bitcodeFileName: String
val llvmImports: LlvmImports by lazy { Llvm.ImportsImpl(librariesWithDependencies.toSet()) }
lateinit var library: KonanLibraryLayout
private var llvmDisposed = false
fun disposeLlvm() {
if (llvmDisposed) return
if (::debugInfo.isInitialized)
LLVMDisposeDIBuilder(debugInfo.builder)
if (llvmModule != null)
LLVMDisposeModule(llvmModule)
moduleToLlvm.keys.forEach {
LLVMDisposeModule(it)
}
moduleToLlvmDeclarations.clear()
moduleToDebugInfo.clear()
// moduleToLlvm.clear()
irFileToModule.clear()
irFileToCodegenVisitor.clear()
if (::llvm.isInitialized) {
LLVMDisposeTargetData(llvm.runtime.targetData)
LLVMDisposeModule(llvm.runtime.llvmModule)
@@ -409,6 +413,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun verifyBitCode() {
if (llvmModule == null) return
verifyModule(llvmModule!!)
irFileToModule.values.forEach(::verifyModule)
}
fun printBitCode() {
@@ -441,8 +446,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun shouldProfilePhases() = config.phaseConfig.needProfiling
fun shouldContainDebugInfo() = config.debug
fun shouldContainLocationDebugInfo() = shouldContainDebugInfo() || config.lightDebug
fun shouldContainAnyDebugInfo() = shouldContainDebugInfo() || shouldContainLocationDebugInfo()
fun shouldContainLocationDebugInfo() = false // shouldContainDebugInfo() || config.lightDebug
fun shouldContainAnyDebugInfo() = false // shouldContainDebugInfo() || shouldContainLocationDebugInfo()
fun shouldOptimize() = config.configuration.getBoolean(KonanConfigKeys.OPTIMIZATION)
fun ghaEnabled() = ::globalHierarchyAnalysisResult.isInitialized
@@ -457,11 +462,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
}
}
lateinit var debugInfo: DebugInfo
var moduleDFG: ModuleDFG? = null
var externalModulesDFG: ExternalModulesDFG? = null
lateinit var lifetimes: MutableMap<IrElement, Lifetime>
lateinit var codegenVisitor: CodeGeneratorVisitor
var devirtualizationAnalysisResult: DevirtualizationAnalysis.AnalysisResult? = null
var referencedFunctions: Set<IrFunction>? = null
@@ -474,7 +476,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
internal val stdlibModule
get() = this.builtIns.any.module
lateinit var compilerOutput: List<ObjectFile>
val linkerInput: MutableSet<ObjectFile> = mutableSetOf()
val llvmModuleSpecification: LlvmModuleSpecification by lazy {
when {

View File

@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.ir.addFakeOverrides
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -31,10 +32,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
@@ -121,9 +119,9 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
this.isExternal = isExternal
}.also {
if (isExternal) {
context.internalAbi.reference(it, enumClass.module)
context.internalAbi.reference(it, enumClass.findPackage().fqName, enumClass.module)
} else {
context.internalAbi.declare(it, enumClass.module)
context.internalAbi.declare(it, enumClass.file)
}
}

View File

@@ -10,11 +10,10 @@ import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.ir.util.addFile
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import kotlin.random.Random
/**
* Sometimes we need to reference symbols that are not declared in metadata.
@@ -23,46 +22,39 @@ import org.jetbrains.kotlin.name.Name
* and we have to explicitly add an external declaration.
*/
internal class InternalAbi(private val context: Context) {
/**
* Files that stores all internal ABI declarations.
* We use per-module files so that global initializer will be stored
* in the appropriate modules.
*
* We have to store such declarations in top-level to avoid mangling that
* makes referencing harder.
* A bit better solution is to add files with proper packages, but it is impossible
* during FileLowering (hello, ConcurrentModificationException).
*/
private lateinit var internalAbiFiles: Map<ModuleDescriptor, IrFile>
/**
* Representation of ABI files from external modules.
*/
private val externalAbiFiles = mutableMapOf<ModuleDescriptor, IrFile>()
private val externalAbiFiles = mutableMapOf<FqName, IrFile>()
fun init(modules: List<IrModuleFragment>) {
internalAbiFiles = modules.associate { it.descriptor to createAbiFile(it) }
}
private val accumulator = mutableMapOf<IrFile, MutableList<IrFunction>>()
private fun createAbiFile(module: IrModuleFragment): IrFile =
module.addFile(NaiveSourceBasedFileEntryImpl("internal"), FqName("kotlin.native.caches.abi"))
private fun createAbiFile(module: IrModuleFragment, packageFqName: FqName): IrFile =
module.addFile(NaiveSourceBasedFileEntryImpl("internal_for_${module.name}"), packageFqName)
/**
* Adds external [function] from [module] to a list of external references.
*/
fun reference(function: IrFunction, module: ModuleDescriptor) {
fun reference(function: IrFunction, packageFqName: FqName, module: ModuleDescriptor) {
assert(function.isExternal) { "Function that represents external ABI should be marked as external" }
context.llvmImports.add(module.llvmSymbolOrigin)
externalAbiFiles.getOrPut(module) {
createAbiFile(IrModuleFragmentImpl(module, context.irBuiltIns))
externalAbiFiles.getOrPut(packageFqName) {
createAbiFile(IrModuleFragmentImpl(module, context.irBuiltIns), packageFqName)
}.addChild(function)
}
/**
* Adds [function] to a list of [module]'s publicly available symbols.
*/
fun declare(function: IrFunction, module: ModuleDescriptor) {
internalAbiFiles.getValue(module).addChild(function)
fun declare(function: IrFunction, irFile: IrFile) {
accumulator.getOrPut(irFile, ::mutableListOf) += function
}
fun commit(irFile: IrFile) {
accumulator[irFile]?.let { functions ->
irFile.addChildren(functions)
accumulator.remove(irFile)
}
}
companion object {
@@ -72,7 +64,7 @@ internal class InternalAbi(private val context: Context) {
val INTERNAL_ABI_ORIGIN = object : IrDeclarationOriginImpl("INTERNAL_ABI") {}
fun getCompanionObjectAccessorName(companion: IrClass): Name =
getMangledNameFor("globalAccessor", companion)
getMangledNameFor("companionAccessor", companion.parentAsClass)
fun getEnumValuesAccessorName(enum: IrClass): Name =
getMangledNameFor("getValues", enum)
@@ -80,8 +72,8 @@ internal class InternalAbi(private val context: Context) {
/**
* Generate name for declaration that will be a part of internal ABI.
*/
private fun getMangledNameFor(declarationName: String, parent: IrDeclarationParent): Name {
val prefix = parent.fqNameForIrSerialization
private fun getMangledNameFor(declarationName: String, parent: IrDeclaration): Name {
val prefix = parent.nameForIrSerialization
return "$prefix.$declarationName".synthesizedName
}
}

View File

@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.konan.llvm.moduleToLlvm
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.File
@@ -34,8 +35,9 @@ internal class Linker(val context: Context) {
private val optimize = context.shouldOptimize()
private val debug = context.config.debug || context.config.lightDebug
fun link(objectFiles: List<ObjectFile>) {
val nativeDependencies = context.llvm.nativeDependenciesToLink
fun link(objectFiles: Collection<ObjectFile>) {
val allLlvm = moduleToLlvm.values
val nativeDependencies = allLlvm.flatMap { it.nativeDependenciesToLink }.toSet()
val includedBinariesLibraries = if (context.config.produce.isCache) {
context.config.librariesToCache
@@ -44,14 +46,14 @@ internal class Linker(val context: Context) {
}
val includedBinaries = includedBinariesLibraries.map { (it as? KonanLibrary)?.includedPaths.orEmpty() }.flatten()
val libraryProvidedLinkerFlags = context.llvm.allNativeDependencies.map { it.linkerOpts }.flatten()
val libraryProvidedLinkerFlags = allLlvm.flatMap { it.allNativeDependencies }.toSet().map { it.linkerOpts }.flatten()
if (context.config.produce.isCache) {
context.config.outputFiles.tempCacheDirectory!!.mkdirs()
saveAdditionalInfoForCache()
}
runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
runLinker(objectFiles.toList(), includedBinaries, libraryProvidedLinkerFlags)
renameOutput()
}
@@ -141,10 +143,10 @@ internal class Linker(val context: Context) {
val linkerInput = determineLinkerInput(objectFiles, linkerOutput)
try {
File(executable).delete()
val linkerArgs = asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
val linkerArgs = asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS) +
BitcodeEmbedding.getLinkerOptions(context.config) +
linkerInput.caches.dynamic +
libraryProvidedLinkerFlags + additionalLinkerArgs
libraryProvidedLinkerFlags + additionalLinkerArgs)
val finalOutputCommands = linker.finalLinkCommands(
objectFiles = linkerInput.objectFiles,
@@ -219,7 +221,7 @@ private fun determineCachesToLink(context: Context): CachesToLink {
val staticCaches = mutableListOf<String>()
val dynamicCaches = mutableListOf<String>()
context.llvm.allCachedBitcodeDependencies.forEach { library ->
moduleToLlvm.values.flatMap { it.allCachedBitcodeDependencies }.toSet().forEach { library ->
val currentBinaryContainsLibrary = context.llvmModuleSpecification.containsLibrary(library)
val cache = context.config.cachedLibraries.getLibraryCache(library)
?: error("Library $library is expected to be cached")

View File

@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.library.KotlinLibrary
internal abstract class LlvmModuleSpecificationBase(protected val cachedLibraries: CachedLibraries) : LlvmModuleSpecification {

View File

@@ -111,8 +111,16 @@ private class LlvmPipelineConfiguration(context: Context) {
}
}
internal fun runLlvmOptimizationPipeline(context: Context) {
val llvmModule = context.llvmModule!!
private fun insertEntryPoint(context: Context, module: LLVMModuleRef) {
val nomain = context.config.configuration.get(KonanConfigKeys.NOMAIN) ?: false
if (context.config.produce != CompilerOutputKind.PROGRAM || nomain)
return
LLVMGetNamedFunction(module, "Konan_main")?.let { entryPoint ->
LLVMAddAlias(module, LLVMTypeOf(entryPoint)!!, entryPoint, "main")
}
}
internal fun runLlvmOptimizationPipeline(context: Context, llvmModule: LLVMModuleRef) {
val config = LlvmPipelineConfiguration(context)
context.log {
"""
@@ -153,7 +161,8 @@ internal fun runLlvmOptimizationPipeline(context: Context) {
if (context.llvmModuleSpecification.isFinal) {
// Since we are in a "closed world" internalization can be safely used
// to reduce size of a bitcode with global dce.
LLVMAddInternalizePass(modulePasses, 0)
// LLVMAddInternalizePass(modulePasses, 0)
makeVisibilityHiddenLikeLlvmInternalizePass(llvmModule)
} else if (context.config.produce == CompilerOutputKind.STATIC_CACHE) {
// Hidden visibility makes symbols internal when linking the binary.
// When producing dynamic library, this enables stripping unused symbols from binary with -dead_strip flag,
@@ -169,7 +178,7 @@ internal fun runLlvmOptimizationPipeline(context: Context) {
// Pipeline that is similar to `llvm-lto`.
// TODO: Add ObjC optimization passes.
LLVMPassManagerBuilderPopulateLTOPassManager(passBuilder, modulePasses, Internalize = 0, RunInliner = 1)
LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses)
LLVMRunPassManager(modulePasses, llvmModule)
LLVMPassManagerBuilderDispose(passBuilder)
@@ -179,6 +188,7 @@ internal fun runLlvmOptimizationPipeline(context: Context) {
if (shouldRunLateBitcodePasses(context)) {
runLateBitcodePasses(context, llvmModule)
}
insertEntryPoint(context, llvmModule)
}
internal fun RelocationModeFlags.currentRelocationMode(context: Context): RelocationModeFlags.Mode =

View File

@@ -202,7 +202,6 @@ internal fun Context.psiToIr(
// TODO: find out what should be done in the new builtins/symbols about it
if (this.stdlibModule in modulesWithoutDCE)
functionIrClassFactory.buildAllClasses()
internalAbi.init(irModules.values + irModule!!)
functionIrClassFactory.module = (modules.values + irModule!!).single { it.descriptor.isNativeStdlib() }
}

View File

@@ -7,7 +7,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
import org.jetbrains.kotlin.backend.konan.MemoryModel
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.ExpectToActualDefaultValueCopier
import org.jetbrains.kotlin.backend.konan.lower.SamSuperTypesChecker
@@ -104,7 +104,7 @@ internal val objCExportPhase = konanUnitPhase(
internal val buildCExportsPhase = konanUnitPhase(
op = {
if (this.isNativeLibrary) {
this.cAdapterGenerator = CAdapterGenerator(this).also {
this.cAdapterGenerator = CAdapterGenerator(this, this.llvmModule!!).also {
it.buildExports(this.symbolTable!!)
}
}
@@ -194,13 +194,13 @@ internal val serializerPhase = konanUnitPhase(
)
internal val objectFilesPhase = konanUnitPhase(
op = { compilerOutput = BitcodeCompiler(this).makeObjectFiles(bitcodeFileName) },
op = { linkerInput += BitcodeCompiler(this).makeObjectFiles(bitcodeFiles) },
name = "ObjectFiles",
description = "Bitcode to object file"
)
internal val linkerPhase = konanUnitPhase(
op = { Linker(this).link(compilerOutput) },
op = { Linker(this).link(linkerInput) },
name = "Linker",
description = "Linker"
)
@@ -330,10 +330,16 @@ internal val exportInternalAbiPhase = makeKonanModuleOpPhase(
prerequisite = emptySet(),
op = { context, module ->
val visitor = object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFile(declaration: IrFile) {
super.visitFile(declaration)
context.internalAbi.commit(declaration)
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
if (declaration.isCompanion) {
@@ -347,7 +353,7 @@ internal val exportInternalAbiPhase = makeKonanModuleOpPhase(
+irReturn(irGetObjectValue(declaration.defaultType, declaration.symbol))
}
}
context.internalAbi.declare(function, declaration.module)
context.internalAbi.declare(function, declaration.file)
}
}
@@ -363,9 +369,17 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
op = { context, module ->
val accessors = mutableMapOf<IrClass, IrSimpleFunction>()
val transformer = object : IrElementTransformerVoid() {
var currentFile: IrFile? = null
override fun visitFile(declaration: IrFile): IrFile {
currentFile = declaration
return super.visitFile(declaration)
}
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val irClass = expression.symbol.owner
if (!irClass.isCompanion || context.llvmModuleSpecification.containsDeclaration(irClass)) {
if (!irClass.isCompanion || (context.llvmModuleSpecification.containsModule(irClass.module) && irClass.file == currentFile)) {
return expression
}
val parent = irClass.parentAsClass
@@ -380,7 +394,7 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
origin = InternalAbi.INTERNAL_ABI_ORIGIN
isExternal = true
}.also {
context.internalAbi.reference(it, irClass.module)
context.internalAbi.reference(it, irClass.findPackage().fqName, irClass.module)
}
}
return IrCallImpl(expression.startOffset, expression.endOffset, expression.type, accessor.symbol, accessor.typeParameters.size, accessor.valueParameters.size)
@@ -477,7 +491,7 @@ internal fun PhaseConfig.konanPhasesConfig(config: KonanConfig) {
// Don't serialize anything to a final executable.
disableUnless(serializerPhase, config.produce == CompilerOutputKind.LIBRARY)
disableUnless(entryPointPhase, config.produce == CompilerOutputKind.PROGRAM)
disableUnless(exportInternalAbiPhase, config.produce.isCache)
// disableUnless(exportInternalAbiPhase, config.produce.isCache)
disableIf(backendCodegen, config.produce == CompilerOutputKind.LIBRARY)
disableUnless(bitcodeOptimizationPhase, config.produce.involvesLinkStage)
disableUnless(linkBitcodeDependenciesPhase, config.produce.involvesLinkStage)

View File

@@ -462,7 +462,7 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
if (irClass.hasAnnotation(FqName.fromSegments(listOf("kotlin", "native", "internal", "NoReorderFields"))))
return fields
return fields.sortedByDescending{ LLVMStoreSizeOfType(context.llvm.runtime.targetData, it.type.llvmType(context)) }
return fields.sortedByDescending{ LLVMStoreSizeOfType(context.llvm.runtime.targetData, it.type.llvmType(context.llvm)) }
}
private val IrClass.overridableOrOverridingMethods: List<IrSimpleFunction>

View File

@@ -118,6 +118,8 @@ internal class IrProviderForCEnumAndCStructStubs(
}
companion object {
const val cTypeDefinitionsFileName = "CTypeDefinitions"
val cTypeDefinitionsFileNamePrefix: String by lazy {
"CTypeDefinitions_"
}
}
}

View File

@@ -51,7 +51,7 @@ object KonanBinaryInterface {
private fun IrFunction.funSymbolNameImpl(): String {
if (!isExported(this)) {
throw AssertionError(render())
// throw AssertionError(render())
}
if (isExternal) {
@@ -88,7 +88,7 @@ internal val IrClass.writableTypeInfoSymbolName: String
internal val IrClass.globalObjectStorageSymbolName: String
get() {
assert (this.isExported())
// assert (this.isExported())
assert (this.kind.isSingleton)
assert (!this.isUnit())

View File

@@ -29,31 +29,57 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast
internal val contextLLVMSetupPhase = makeKonanModuleOpPhase(
name = "ContextLLVMSetup",
description = "Set up Context for LLVM Bitcode generation",
op = { context, _ ->
op = { context, irModule ->
// 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.
llvmContext = LLVMContextCreate()!!
irModule.files
.filter { it.declarations.isNotEmpty() }
.forEach { irFile ->
// TODO: Workaround windows path limitation
val moduleId = irFile.path.replace('/', '_')
val llvmModule = LLVMModuleCreateWithNameInContext(moduleId, llvmContext)!!
irFileToModule[irFile] = llvmModule
moduleToLlvm[llvmModule] = Llvm(context, llvmModule, FileLlvmModuleSpecification(irFile))
// 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 debugInfo = DebugInfo(context, llvmModule)
debugInfo.compilationUnit = if (context.shouldContainLocationDebugInfo()) DICreateCompilationUnit(
builder = debugInfo.builder,
lang = DWARF.language(context.config),
File = moduleId,
dir = "",
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion(context.config)).cast()
else null
moduleToDebugInfo[llvmModule] = debugInfo
}
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,
context.llvm = Llvm(context, llvmModule, RootSpec(irModule.files))
moduleToLlvm[llvmModule] = context.llvm
val path = context.config.outputFile
.toFileAndFolder(context)
val debugInfo = DebugInfo(context, llvmModule)
debugInfo.compilationUnit = if (context.shouldContainLocationDebugInfo()) DICreateCompilationUnit(
builder = debugInfo.builder,
lang = DWARF.language(context.config),
File = filePath,
File = path.path(),
dir = "",
producer = DWARF.producer,
isOptimized = 0,
flags = "",
rv = DWARF.runtimeVersion(context.config)).cast()
else null
moduleToDebugInfo[llvmModule] = debugInfo
}
)
@@ -61,10 +87,15 @@ internal val createLLVMDeclarationsPhase = makeKonanModuleOpPhase(
name = "CreateLLVMDeclarations",
description = "Map IR declarations to LLVM",
prerequisite = setOf(contextLLVMSetupPhase),
op = { context, _ ->
context.llvmDeclarations = createLlvmDeclarations(context)
op = { context, irModule ->
context.lifetimes = mutableMapOf()
context.codegenVisitor = CodeGeneratorVisitor(context, context.lifetimes)
irModule.files.filter { it.declarations.isNotEmpty() }.forEach { irFile ->
val module = irFileToModule[irFile]
?: error("${irFile.path} is missing")
moduleToLlvmDeclarations[module] = createLlvmDeclarations(context, irFile)
irFileToCodegenVisitor[irFile] = CodeGeneratorVisitor(context, context.lifetimes, module)
}
moduleToLlvmDeclarations[context.llvmModule!!] = LlvmDeclarations(emptyMap())
}
)
@@ -92,16 +123,24 @@ internal val RTTIPhase = makeKonanModuleOpPhase(
name = "RTTI",
description = "RTTI generation",
op = { context, irModule ->
val visitor = RTTIGeneratorVisitor(context)
irModule.acceptVoid(visitor)
visitor.dispose()
irModule.files.filter { it.declarations.isNotEmpty() }.forEach { irFile ->
val llvmModule = irFileToModule[irFile]
?: error("${irFile.path} is missing")
val visitor = RTTIGeneratorVisitor(context, llvmModule)
irFile.acceptVoid(visitor)
visitor.dispose()
}
}
)
internal val generateDebugInfoHeaderPhase = makeKonanModuleOpPhase(
name = "GenerateDebugInfoHeader",
description = "Generate debug info header",
op = { context, _ -> generateDebugInfoHeader(context) }
op = { context, _ ->
moduleToDebugInfo.entries.forEach { (llvmModule, debugInfo) ->
generateDebugInfoHeader(context, llvmModule, debugInfo)
}
}
)
internal val buildDFGPhase = makeKonanModuleOpPhase(
@@ -315,7 +354,11 @@ internal val codegenPhase = makeKonanModuleOpPhase(
name = "Codegen",
description = "Code generation",
op = { context, irModule ->
irModule.acceptVoid(context.codegenVisitor)
irModule.files.filter { it.declarations.isNotEmpty() }.forEach { irFile ->
val visitor = irFileToCodegenVisitor.getValue(irFile)
irFile.acceptVoid(visitor)
}
CodeGeneratorVisitor(context, context.lifetimes, context.llvmModule!!).visitModuleFragment(irModule)
}
)
@@ -324,7 +367,9 @@ internal val finalizeDebugInfoPhase = makeKonanModuleOpPhase(
description = "Finalize debug info",
op = { context, _ ->
if (context.shouldContainAnyDebugInfo()) {
DIFinalize(context.debugInfo.builder)
moduleToDebugInfo.values.forEach { debugInfo ->
DIFinalize(debugInfo.builder)
}
}
}
)
@@ -344,21 +389,32 @@ internal val linkBitcodeDependenciesPhase = makeKonanModuleOpPhase(
internal val checkExternalCallsPhase = makeKonanModuleOpPhase(
name = "CheckExternalCalls",
description = "Check external calls",
op = { context, _ -> checkLlvmModuleExternalCalls(context) }
op = { _, module ->
module.files.forEach {
// checkLlvmModuleExternalCalls(context, it)
}
}
)
internal val rewriteExternalCallsCheckerGlobals = makeKonanModuleOpPhase(
name = "RewriteExternalCallsCheckerGlobals",
description = "Rewrite globals for external calls checker after optimizer run",
op = { context, _ -> addFunctionsListSymbolForChecker(context) }
op = { _, _ ->
// addFunctionsListSymbolForChecker(context)
}
)
internal val bitcodeOptimizationPhase = makeKonanModuleOpPhase(
name = "BitcodeOptimization",
description = "Optimize bitcode",
op = { context, _ -> runLlvmOptimizationPipeline(context) }
op = { context, _ ->
context.optimizerInput.forEach { module ->
runLlvmOptimizationPipeline(context, module)
val output = context.config.tempFiles.create(stableModuleName(module), ".bc")
LLVMWriteBitcodeToFile(module, output.absolutePath)
context.bitcodeFiles += output.absolutePath
}
}
)
internal val produceOutputPhase = namedUnitPhase(

View File

@@ -47,7 +47,10 @@ internal fun IrClass.hasConstStateAndNoSideEffects(context: Context): Boolean {
this.constructors.all { it.isAutogeneratedSimpleConstructor(context) }
}
internal class CodeGenerator(override val context: Context) : ContextUtils {
internal class CodeGenerator(
override val context: Context,
override val llvmModule: LLVMModuleRef
) : ContextUtils {
fun llvmFunction(function: IrFunction): LLVMValueRef = llvmFunctionOrNull(function) ?: error("no function ${function.name} in ${function.file.fqName}")
fun llvmFunctionOrNull(function: IrFunction): LLVMValueRef? = function.llvmFunctionOrNull
@@ -77,10 +80,10 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
}
fun generateLocationInfo(locationInfo: LocationInfo): DILocationRef? = if (locationInfo.inlinedAt != null)
LLVMCreateLocationInlinedAt(LLVMGetModuleContext(context.llvmModule), locationInfo.line, locationInfo.column,
LLVMCreateLocationInlinedAt(LLVMGetModuleContext(llvmModule), locationInfo.line, locationInfo.column,
locationInfo.scope, generateLocationInfo(locationInfo.inlinedAt))
else
LLVMCreateLocation(LLVMGetModuleContext(context.llvmModule), locationInfo.line, locationInfo.column, locationInfo.scope)
LLVMCreateLocation(LLVMGetModuleContext(llvmModule), locationInfo.line, locationInfo.column, locationInfo.scope)
val objCDataGenerator = when {
context.config.target.family.isAppleFamily -> ObjCDataGenerator(this)
@@ -101,7 +104,7 @@ internal sealed class ExceptionHandler {
kotlinException: LLVMValueRef
): Unit = with(functionGenerationContext) {
call(
context.llvm.throwExceptionFunction,
codegen.llvm.throwExceptionFunction,
listOf(kotlinException),
Lifetime.IRRELEVANT,
this@ExceptionHandler
@@ -183,7 +186,7 @@ internal inline fun generateFunction(
): LLVMValueRef {
val function = addLlvmFunctionWithDefaultAttributes(
codegen.context,
codegen.context.llvmModule!!,
codegen.llvmModule,
name,
functionType
)
@@ -218,7 +221,7 @@ internal inline fun generateFunctionNoRuntime(
): LLVMValueRef {
val function = addLlvmFunctionWithDefaultAttributes(
codegen.context,
codegen.context.llvmModule!!,
codegen.llvmModule,
name,
functionType
)
@@ -266,7 +269,7 @@ internal class StackLocalsManagerImpl(
if (context.memoryModel == MemoryModel.EXPERIMENTAL) alloca(kObjHeaderPtr) else null
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 stackSlot = LLVMBuildAlloca(builder, type, "")!!
@@ -295,7 +298,7 @@ internal class StackLocalsManagerImpl(
// Create new type or get already created.
context.declaredLocalArrays.getOrPut(name) {
val fieldTypes = listOf(kArrayHeader, LLVMArrayType(arrayToElementType[irClass.symbol]!!, count))
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(llvmModule), name)!!
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, 1)
classType
}
@@ -348,11 +351,11 @@ internal class StackLocalsManagerImpl(
private fun clean(stackLocal: StackLocal, refsOnly: Boolean) = with(functionGenerationContext) {
if (stackLocal.isArray) {
if (stackLocal.irClass.symbol == context.ir.symbols.array)
call(context.llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
call(codegen.llvm.zeroArrayRefsFunction, listOf(stackLocal.objHeaderPtr))
} else {
val type = context.llvmDeclarations.forClass(stackLocal.irClass).bodyType
val type = llvmDeclarations.forClass(stackLocal.irClass).bodyType
for (field in context.getLayoutBuilder(stackLocal.irClass).fields) {
val fieldIndex = context.llvmDeclarations.forField(field).index
val fieldIndex = llvmDeclarations.forField(field).index
val fieldType = LLVMStructGetTypeAtIndex(type, fieldIndex)!!
if (isObjectType(fieldType)) {
@@ -360,7 +363,7 @@ internal class StackLocalsManagerImpl(
if (refsOnly)
storeHeapRef(kNullObjHeaderPtr, fieldPtr)
else
call(context.llvm.zeroHeapRefFunction, listOf(fieldPtr))
call(codegen.llvm.zeroHeapRefFunction, listOf(fieldPtr))
}
}
@@ -387,12 +390,16 @@ internal class StackLocalsManagerImpl(
}
}
internal class FunctionGenerationContext(val function: LLVMValueRef,
val codegen: CodeGenerator,
startLocation: LocationInfo?,
private val endLocation: LocationInfo?,
private val switchToRunnable: Boolean,
internal val irFunction: IrFunction? = null): ContextUtils {
internal class FunctionGenerationContext(
val function: LLVMValueRef,
val codegen: CodeGenerator,
startLocation: LocationInfo?,
private val endLocation: LocationInfo?,
private val switchToRunnable: Boolean,
internal val irFunction: IrFunction? = null
): ContextUtils {
override val llvmModule: LLVMModuleRef = codegen.llvmModule
override val context = codegen.context
val vars = VariableManager(this)
@@ -489,7 +496,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val slotAddress = LLVMBuildAlloca(builder, type, name)!!
variableLocation?.let {
DIInsertDeclaration(
builder = codegen.context.debugInfo.builder,
builder = codegen.debugInfo.builder,
value = slotAddress,
localVariable = it.localVariable,
location = it.location,
@@ -555,19 +562,19 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
fun freeze(value: LLVMValueRef, exceptionHandler: ExceptionHandler) {
if (isObjectRef(value))
call(context.llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler)
call(codegen.llvm.freezeSubgraph, listOf(value), Lifetime.IRRELEVANT, exceptionHandler)
}
fun checkGlobalsAccessible(exceptionHandler: ExceptionHandler) {
if (context.memoryModel == MemoryModel.STRICT)
call(context.llvm.checkGlobalsAccessible, emptyList(), Lifetime.IRRELEVANT, exceptionHandler)
call(codegen.llvm.checkGlobalsAccessible, emptyList(), Lifetime.IRRELEVANT, exceptionHandler)
}
private fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
if (context.memoryModel == MemoryModel.STRICT)
store(value, address)
else
call(context.llvm.updateReturnRefFunction, listOf(address, value))
call(codegen.llvm.updateReturnRefFunction, listOf(address, value))
}
private fun updateRef(value: LLVMValueRef, address: LLVMValueRef, onStack: Boolean) {
@@ -575,9 +582,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
if (context.memoryModel == MemoryModel.STRICT)
store(value, address)
else
call(context.llvm.updateStackRefFunction, listOf(address, value))
call(codegen.llvm.updateStackRefFunction, listOf(address, value))
} else {
call(context.llvm.updateHeapRefFunction, listOf(address, value))
call(codegen.llvm.updateHeapRefFunction, listOf(address, value))
}
}
@@ -591,13 +598,13 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
"Attempt to switch the thread state when runtime is forbidden"
}
when (state) {
Native -> call(context.llvm.Kotlin_mm_switchThreadStateNative, emptyList())
Runnable -> call(context.llvm.Kotlin_mm_switchThreadStateRunnable, emptyList())
Native -> call(codegen.llvm.Kotlin_mm_switchThreadStateNative, emptyList())
Runnable -> call(codegen.llvm.Kotlin_mm_switchThreadStateRunnable, emptyList())
}.let {} // Force exhaustive.
}
fun memset(pointer: LLVMValueRef, value: Byte, size: Int, isVolatile: Boolean = false) =
call(context.llvm.memsetFunction,
call(codegen.llvm.memsetFunction,
listOf(pointer,
Int8(value).llvm,
Int32(size).llvm,
@@ -695,7 +702,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime): LLVMValueRef =
call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime)
call(codegen.llvm.allocInstanceFunction, listOf(typeInfo), lifetime)
fun allocInstance(irClass: IrClass, lifetime: Lifetime, stackLocalsManager: StackLocalsManager) =
if (lifetime == Lifetime.STACK)
@@ -716,13 +723,13 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return if (lifetime == Lifetime.STACK) {
stackLocalsManager.allocArray(irClass, count)
} else {
call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime, exceptionHandler)
call(codegen.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime, exceptionHandler)
}
}
fun unreachable(): LLVMValueRef? {
if (context.config.debug) {
call(context.llvm.llvmTrap, emptyList())
call(codegen.llvm.llvmTrap, emptyList())
}
val res = LLVMBuildUnreachable(builder)
currentPositionHolder.setAfterTerminator()
@@ -823,7 +830,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
LLVMBuildExtractValue(builder, aggregate, index, name)!!
fun gxxLandingpad(numClauses: Int, name: String = ""): LLVMValueRef {
val personalityFunction = context.llvm.gxxPersonalityFunction
val personalityFunction = codegen.llvm.gxxPersonalityFunction
// Type of `landingpad` instruction result (depends on personality function):
val landingpadType = structType(int8TypePtr, int32Type)
@@ -863,7 +870,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val typeId = extractValue(landingpad, 1)
val isKotlinException = icmpEq(
typeId,
call(context.llvm.llvmEhTypeidFor, listOf(kotlinExceptionRtti.llvm))
call(codegen.llvm.llvmEhTypeidFor, listOf(kotlinExceptionRtti.llvm))
)
if (wrapExceptionMode) {
@@ -874,7 +881,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
appendingTo(foreignExceptionBlock) {
val isObjCException = icmpEq(
typeId,
call(context.llvm.llvmEhTypeidFor, listOf(objcNSExceptionRtti.llvm))
call(codegen.llvm.llvmEhTypeidFor, listOf(objcNSExceptionRtti.llvm))
)
condBr(isObjCException, forwardNativeExceptionBlock, fatalForeignExceptionBlock)
@@ -894,7 +901,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
appendingTo(fatalForeignExceptionBlock) {
val exceptionRecord = extractValue(landingpad, 0)
call(context.llvm.cxaBeginCatchFunction, listOf(exceptionRecord))
call(codegen.llvm.cxaBeginCatchFunction, listOf(exceptionRecord))
terminate()
}
@@ -907,7 +914,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
fun terminate() {
call(context.llvm.cxxStdTerminate, emptyList())
call(codegen.llvm.cxxStdTerminate, emptyList())
// Note: unreachable instruction to be generated here, but debug information is improper in this case.
val loopBlock = basicBlock("loop", position()?.start)
@@ -945,14 +952,14 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val exceptionRecord = extractValue(landingpadResult, 0, "er")
// __cxa_begin_catch returns pointer to C++ exception object.
val beginCatch = context.llvm.cxaBeginCatchFunction
val beginCatch = codegen.llvm.cxaBeginCatchFunction
val exceptionRawPtr = call(beginCatch, listOf(exceptionRecord))
// Pointer to Kotlin exception object:
val exceptionPtr = call(context.llvm.Kotlin_getExceptionObject, listOf(exceptionRawPtr), Lifetime.GLOBAL)
val exceptionPtr = call(codegen.llvm.Kotlin_getExceptionObject, listOf(exceptionRawPtr), Lifetime.GLOBAL)
// __cxa_end_catch performs some C++ cleanup, including calling `ExceptionObjHolder` class destructor.
val endCatch = context.llvm.cxaEndCatchFunction
val endCatch = codegen.llvm.cxaEndCatchFunction
call(endCatch, listOf())
return exceptionPtr
@@ -962,14 +969,14 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val exceptionRecord = extractValue(landingpadResult, 0, "er")
// __cxa_begin_catch returns pointer to C++ exception object.
val exceptionRawPtr = call(context.llvm.cxaBeginCatchFunction, listOf(exceptionRecord))
val exceptionRawPtr = call(codegen.llvm.cxaBeginCatchFunction, listOf(exceptionRecord))
// 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,
listOf(exceptionRawPtr),
Lifetime.GLOBAL, exceptionHandler)
call(context.llvm.cxaEndCatchFunction, listOf())
call(codegen.llvm.cxaEndCatchFunction, listOf())
return exception
}
@@ -1081,7 +1088,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
appendingTo(slowPathBB) {
val actualInterfaceTableSize = sub(kImmInt32Zero, interfaceTableSize) // -interfaceTableSize
val slowValue = call(context.llvm.lookupInterfaceTableRecord,
val slowValue = call(codegen.llvm.lookupInterfaceTableRecord,
listOf(interfaceTable, actualInterfaceTableSize, Int32(interfaceId).llvm))
br(takeResBB)
addPhiIncoming(resultPhi, currentBlock to slowValue)
@@ -1094,7 +1101,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
assert(LLVMTypeOf(receiver) == codegen.kObjHeaderPtr)
val typeInfoPtr: LLVMValueRef = if (irFunction.getObjCMethodInfo() != null)
call(context.llvm.getObjCKotlinTypeInfo, listOf(receiver))
call(codegen.llvm.getObjCKotlinTypeInfo, listOf(receiver))
else
loadTypeInfo(receiver)
@@ -1167,10 +1174,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
// If thread local object is imported - access it via getter function.
ObjectStorageKind.THREAD_LOCAL -> {
val valueGetterName = irClass.threadLocalObjectStorageGetterSymbolName
val valueGetterFunction = LLVMGetNamedFunction(context.llvmModule, valueGetterName)
val valueGetterFunction = LLVMGetNamedFunction(llvmModule, valueGetterName)
?: addLlvmFunctionWithDefaultAttributes(
context,
context.llvmModule!!,
llvmModule,
valueGetterName,
functionType(kObjHeaderPtrPtr, false)
)
@@ -1192,7 +1199,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
} else {
// Local globals and thread locals storage info is stored in our map.
val singleton = context.llvmDeclarations.forSingleton(irClass)
val singleton = codegen.llvmDeclarations.forSingleton(irClass)
val instanceAddress = singleton.instanceStorage
instanceAddress.getAddress(this)
}
@@ -1200,14 +1207,14 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
when (storageKind) {
ObjectStorageKind.SHARED ->
// If current file used a shared object, make file's (de)initializer function deinit it.
context.llvm.globalSharedObjects += objectPtr
codegen.llvm.globalSharedObjects += objectPtr
ObjectStorageKind.THREAD_LOCAL ->
// If current file used locally defined TLS objects, make file's (de)initializer function
// init and deinit TLS.
// 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.
if (!isExternal(irClass))
context.llvm.fileUsesThreadLocalObjects = true
codegen.llvm.fileUsesThreadLocalObjects = true
ObjectStorageKind.PERMANENT -> { /* Do nothing, no need to free such an instance. */ }
}
@@ -1227,9 +1234,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val ctor = codegen.llvmFunction(defaultConstructor)
val initFunction =
if (storageKind == ObjectStorageKind.SHARED && context.config.threadsAreAllowed) {
context.llvm.initSingletonFunction
codegen.llvm.initSingletonFunction
} else {
context.llvm.initThreadLocalSingleton
codegen.llvm.initThreadLocalSingleton
}
val args = listOf(objectPtr, typeInfo, ctor)
val newValue = call(initFunction, args, Lifetime.GLOBAL, exceptionHandler)
@@ -1277,7 +1284,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
val objCClass = getObjCClass(name, llvmSymbolOrigin)
val getClass = context.llvm.externalFunction(
val getClass = codegen.llvm.externalFunction(
"object_getClass",
functionType(int8TypePtr, false, int8TypePtr),
origin = context.standardLlvmSymbolsOrigin
@@ -1301,7 +1308,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return this.ifThenElse(storedClassIsNotNull, storedClass) {
call(
context.llvm.createKotlinObjCClass,
codegen.llvm.createKotlinObjCClass,
listOf(classInfo),
exceptionHandler = exceptionHandler
)
@@ -1310,7 +1317,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
fun getObjCClass(binaryName: String, llvmSymbolOrigin: CompiledKlibModuleOrigin): LLVMValueRef {
context.llvm.imports.add(llvmSymbolOrigin)
codegen.llvm.imports.add(llvmSymbolOrigin)
return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
}
@@ -1337,7 +1344,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
check(!forbidRuntime) { "Attempt to switch the thread state when runtime is forbidden" }
positionAtEnd(prologueBb)
// TODO: Do we need to do it for every c->kotlin bridge?
call(context.llvm.initRuntimeIfNeeded, emptyList())
call(codegen.llvm.initRuntimeIfNeeded, emptyList())
switchThreadState(Runnable)
}
@@ -1353,7 +1360,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
appendingTo(prologueBb) {
if (needsRuntimeInit && context.config.memoryModel != MemoryModel.EXPERIMENTAL) {
check(!forbidRuntime) { "Attempt to init runtime where runtime usage is forbidden" }
call(context.llvm.initRuntimeIfNeeded, emptyList())
call(codegen.llvm.initRuntimeIfNeeded, emptyList())
}
val slots = if (needSlotsPhi)
LLVMBuildArrayAlloca(builder, kObjHeaderPtr, Int32(slotCount).llvm, "")!!
@@ -1364,7 +1371,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
// Zero-init slots.
val slotsMem = bitcast(kInt8Ptr, slots)
memset(slotsMem, 0, slotCount * codegen.runtime.pointerSize)
call(context.llvm.enterFrameFunction, listOf(slots, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
call(codegen.llvm.enterFrameFunction, listOf(slots, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
}
addPhiIncoming(slotsPhi!!, prologueBb to slots)
memScoped {
@@ -1372,7 +1379,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
val expr = longArrayOf(DwarfOp.DW_OP_plus_uconst.value,
runtime.pointerSize * slot.toLong()).toCValues()
DIInsertDeclaration(
builder = codegen.context.debugInfo.builder,
builder = codegen.debugInfo.builder,
value = slots,
localVariable = variable.localVariable,
location = variable.location,
@@ -1397,7 +1404,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
returnType == voidType -> {
releaseVars()
assert(returnSlot == null)
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointFunctionEpilogue)
handleEpilogueForExperimentalMM(codegen.llvm.Kotlin_mm_safePointFunctionEpilogue)
LLVMBuildRetVoid(builder)
}
returns.isNotEmpty() -> {
@@ -1407,7 +1414,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
updateReturnRef(returnPhi, returnSlot!!)
}
releaseVars()
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointFunctionEpilogue)
handleEpilogueForExperimentalMM(codegen.llvm.Kotlin_mm_safePointFunctionEpilogue)
LLVMBuildRet(builder, returnPhi)
}
// Do nothing, all paths throw.
@@ -1443,7 +1450,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
appendingTo(bbUnexpected) {
val exceptionRecord = extractValue(landingpad, 0)
val beginCatch = context.llvm.cxaBeginCatchFunction
val beginCatch = codegen.llvm.cxaBeginCatchFunction
// So `terminator` is called from C++ catch block:
call(beginCatch, listOf(exceptionRecord))
call(terminator, emptyList())
@@ -1454,7 +1461,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
}
releaseVars()
handleEpilogueForExperimentalMM(context.llvm.Kotlin_mm_safePointExceptionUnwind)
handleEpilogueForExperimentalMM(codegen.llvm.Kotlin_mm_safePointExceptionUnwind)
LLVMBuildResume(builder, landingpad)
}
} else {
@@ -1619,7 +1626,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
private fun releaseVars() {
if (needSlots) {
check(!forbidRuntime) { "Attempt to leave a frame where runtime usage is forbidden" }
call(context.llvm.leaveFrameFunction,
call(codegen.llvm.leaveFrameFunction,
listOf(slotsPhi!!, Int32(vars.skipSlots).llvm, Int32(slotCount).llvm))
}
stackLocalsManager.clean(refsOnly = true) // Only bother about not leaving any dangling references.

View File

@@ -143,9 +143,15 @@ internal sealed class Lifetime(val slotType: SlotType) {
*/
internal interface ContextUtils : RuntimeAware {
val context: Context
val llvmModule: LLVMModuleRef
val llvm get() = moduleToLlvm.getValue(llvmModule)
val llvmDeclarations get() = moduleToLlvmDeclarations.getValue(llvmModule)
val debugInfo get() = moduleToDebugInfo.getValue(llvmModule)
val spec get() = llvm.spec
override val runtime: Runtime
get() = context.llvm.runtime
get() = llvm.runtime
/**
* Describes the target platform.
@@ -156,14 +162,14 @@ internal interface ContextUtils : RuntimeAware {
get() = runtime.targetData
val staticData: StaticData
get() = context.llvm.staticData
get() = llvm.staticData
/**
* TODO: maybe it'd be better to replace with [IrDeclaration::isEffectivelyExternal()],
* or just drop all [else] branches of corresponding conditionals.
*/
fun isExternal(declaration: IrDeclaration): Boolean {
return !context.llvmModuleSpecification.containsDeclaration(declaration)
return !spec.containsDeclaration(declaration)
}
/**
@@ -178,11 +184,11 @@ internal interface ContextUtils : RuntimeAware {
get() {
assert(this.isReal)
return if (isExternal(this)) {
runtime.addedLLVMExternalFunctions.getOrPut(this) { context.llvm.externalFunction(this.computeSymbolName(), getLlvmFunctionType(this),
origin = this.llvmSymbolOrigin) }
llvm.addedLLVMExternalFunctions.getOrPut(this) {
llvm.externalFunction(this.computeSymbolName(), getLlvmFunctionType(this), origin = this.llvmSymbolOrigin)
}
} else {
context.llvmDeclarations.forFunctionOrNull(this)?.llvmFunction
llvmDeclarations.forFunctionOrNull(this)?.llvmFunction
}
}
@@ -201,7 +207,7 @@ internal interface ContextUtils : RuntimeAware {
constPointer(importGlobal(this.computeTypeInfoSymbolName(), runtime.typeInfoType,
origin = this.llvmSymbolOrigin))
} else {
context.llvmDeclarations.forClass(this).typeInfo
llvmDeclarations.forClass(this).typeInfo
}
}
@@ -254,7 +260,7 @@ internal class InitializersGenerationState {
&& moduleGlobalInitializers.isEmpty() && moduleThreadLocalInitializers.isEmpty()
}
internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef, val spec: Spec) {
private fun importFunction(name: String, otherModule: LLVMModuleRef): LLVMValueRef {
if (LLVMGetNamedFunction(llvmModule, name) != null) {
@@ -310,6 +316,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
return result
}
val addedLLVMExternalFunctions: MutableMap<IrFunction, LLVMValueRef> = HashMap()
internal fun externalFunction(
name: String,
type: LLVMTypeRef,
@@ -353,17 +361,16 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val imports get() = context.llvmImports
class ImportsImpl(private val context: Context) : LlvmImports {
class ImportsImpl(private val allLibraries: Set<KonanLibrary>) : LlvmImports {
private val usedBitcode = mutableSetOf<KotlinLibrary>()
private val usedNativeDependencies = mutableSetOf<KotlinLibrary>()
private val allLibraries by lazy { context.librariesWithDependencies.toSet() }
override fun add(origin: CompiledKlibModuleOrigin, onlyBitcode: Boolean) {
val library = when (origin) {
CurrentKlibModuleOrigin -> return
is DeserializedKlibModuleOrigin -> origin.library
else -> error("AAAA")
}
if (library !in allLibraries) {
@@ -387,7 +394,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
.filter {
require(it is KonanLibrary)
(!it.isDefault && !context.config.purgeUserLibs) || imports.nativeDependenciesAreUsed(it)
}.cast<List<KonanLibrary>>()
}.cast()
}
private val immediateBitcodeDependencies: List<KonanLibrary> by lazy {
@@ -457,12 +464,30 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val additionalProducedBitcodeFiles = mutableListOf<String>()
val staticData = StaticData(context)
val staticData = StaticData(context, llvmModule)
private val target = context.config.target
val runtimeFile = context.config.distribution.runtime(target)
val runtime = Runtime(runtimeFile) // TODO: dispose
companion object {
var isSet = false
private var _runtime: Runtime? = null
set(value) {
if (isSet) return
isSet = true
field = value
}
get() = field
}
// Shared instance between all Llvms
val runtime: Runtime = run {
if (!isSet) {
val runtimeFile = context.config.distribution.runtime(target)
_runtime = Runtime(runtimeFile) // TODO: dispose
}
_runtime!!
}
val targetTriple = runtime.target
@@ -475,38 +500,38 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
private fun importRtGlobal(name: String) = importGlobal(name, runtime.llvmModule)
val allocInstanceFunction = importRtFunction("AllocInstance")
val allocArrayFunction = importRtFunction("AllocArrayInstance")
val initThreadLocalSingleton = importRtFunction("InitThreadLocalSingleton")
val initSingletonFunction = importRtFunction("InitSingleton")
val initAndRegisterGlobalFunction = importRtFunction("InitAndRegisterGlobal")
val updateHeapRefFunction = importRtFunction("UpdateHeapRef")
val updateStackRefFunction = importRtFunction("UpdateStackRef")
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
val zeroHeapRefFunction = importRtFunction("ZeroHeapRef")
val zeroArrayRefsFunction = importRtFunction("ZeroArrayRefs")
val enterFrameFunction = importRtFunction("EnterFrame")
val leaveFrameFunction = importRtFunction("LeaveFrame")
val lookupInterfaceTableRecord = importRtFunction("LookupInterfaceTableRecord")
val isInstanceFunction = importRtFunction("IsInstance")
val isInstanceOfClassFastFunction = importRtFunction("IsInstanceOfClassFast")
val throwExceptionFunction = importRtFunction("ThrowException")
val appendToInitalizersTail = importRtFunction("AppendToInitializersTail")
val callInitGlobalPossiblyLock = importRtFunction("CallInitGlobalPossiblyLock")
val callInitThreadLocal = importRtFunction("CallInitThreadLocal")
val addTLSRecord = importRtFunction("AddTLSRecord")
val lookupTLS = importRtFunction("LookupTLS")
val initRuntimeIfNeeded = importRtFunction("Kotlin_initRuntimeIfNeeded")
val mutationCheck = importRtFunction("MutationCheck")
val checkLifetimesConstraint = importRtFunction("CheckLifetimesConstraint")
val freezeSubgraph = importRtFunction("FreezeSubgraph")
val checkGlobalsAccessible = importRtFunction("CheckGlobalsAccessible")
val Kotlin_getExceptionObject = importRtFunction("Kotlin_getExceptionObject")
val allocInstanceFunction by lazy { importRtFunction("AllocInstance") }
val allocArrayFunction by lazy { importRtFunction("AllocArrayInstance") }
val initThreadLocalSingleton by lazy { importRtFunction("InitThreadLocalSingleton") }
val initSingletonFunction by lazy { importRtFunction("InitSingleton") }
val initAndRegisterGlobalFunction by lazy { importRtFunction("InitAndRegisterGlobal") }
val updateHeapRefFunction by lazy { importRtFunction("UpdateHeapRef") }
val updateStackRefFunction by lazy { importRtFunction("UpdateStackRef") }
val updateReturnRefFunction by lazy { importRtFunction("UpdateReturnRef") }
val zeroHeapRefFunction by lazy { importRtFunction("ZeroHeapRef") }
val zeroArrayRefsFunction by lazy { importRtFunction("ZeroArrayRefs") }
val enterFrameFunction by lazy { importRtFunction("EnterFrame") }
val leaveFrameFunction by lazy { importRtFunction("LeaveFrame") }
val lookupInterfaceTableRecord by lazy { importRtFunction("LookupInterfaceTableRecord") }
val isInstanceFunction by lazy { importRtFunction("IsInstance") }
val isInstanceOfClassFastFunction by lazy { importRtFunction("IsInstanceOfClassFast") }
val throwExceptionFunction by lazy { importRtFunction("ThrowException") }
val appendToInitalizersTail by lazy { importRtFunction("AppendToInitializersTail") }
val callInitGlobalPossiblyLock by lazy { importRtFunction("CallInitGlobalPossiblyLock") }
val callInitThreadLocal by lazy { importRtFunction("CallInitThreadLocal") }
val addTLSRecord by lazy { importRtFunction("AddTLSRecord") }
val lookupTLS by lazy { importRtFunction("LookupTLS") }
val initRuntimeIfNeeded by lazy { importRtFunction("Kotlin_initRuntimeIfNeeded") }
val mutationCheck by lazy { importRtFunction("MutationCheck") }
val checkLifetimesConstraint by lazy { importRtFunction("CheckLifetimesConstraint") }
val freezeSubgraph by lazy { importRtFunction("FreezeSubgraph") }
val checkGlobalsAccessible by lazy { importRtFunction("CheckGlobalsAccessible") }
val Kotlin_getExceptionObject by lazy { importRtFunction("Kotlin_getExceptionObject") }
val kRefSharedHolderInitLocal = importRtFunction("KRefSharedHolder_initLocal")
val kRefSharedHolderInit = importRtFunction("KRefSharedHolder_init")
val kRefSharedHolderDispose = importRtFunction("KRefSharedHolder_dispose")
val kRefSharedHolderRef = importRtFunction("KRefSharedHolder_ref")
val kRefSharedHolderInitLocal by lazy { importRtFunction("KRefSharedHolder_initLocal") }
val kRefSharedHolderInit by lazy { importRtFunction("KRefSharedHolder_init") }
val kRefSharedHolderDispose by lazy { importRtFunction("KRefSharedHolder_dispose") }
val kRefSharedHolderRef by lazy { importRtFunction("KRefSharedHolder_ref") }
val createKotlinObjCClass by lazy { importRtFunction("CreateKotlinObjCClass") }
val getObjCKotlinTypeInfo by lazy { importRtFunction("GetObjCKotlinTypeInfo") }
@@ -618,13 +643,26 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
}
}
val llvmInt8 = int8Type
val llvmInt16 = int16Type
val llvmInt32 = int32Type
val llvmInt64 = int64Type
val llvmFloat = floatType
val llvmDouble = doubleType
val llvmVector128 = vector128Type
val llvmInt8 by lazy { int8Type }
val llvmInt16 by lazy { int16Type }
val llvmInt32 by lazy { int32Type }
val llvmInt64 by lazy { int64Type }
val llvmFloat by lazy { floatType }
val llvmDouble by lazy { doubleType }
val llvmVector128 by lazy { vector128Type }
val otherLlvmType = LLVMPointerType(int64Type, 0)!!
val llvmTypes = mapOf(
context.irBuiltIns.booleanType to llvmInt8,
context.irBuiltIns.byteType to llvmInt8,
context.irBuiltIns.charType to llvmInt16,
context.irBuiltIns.shortType to llvmInt16,
context.irBuiltIns.intType to llvmInt32,
context.irBuiltIns.longType to llvmInt64,
context.irBuiltIns.floatType to llvmFloat,
context.irBuiltIns.doubleType to llvmDouble
)
private fun getSizeOfReturnTypeInBits(functionPointer: LLVMValueRef): Long {
// LLVMGetElementType is called because we need to dereference a pointer to function.

View File

@@ -60,29 +60,33 @@ internal object DWARF {
fun KonanConfig.debugInfoVersion():Int = configuration[KonanConfigKeys.DEBUG_INFO_VERSION] ?: 1
internal class DebugInfo internal constructor(override val context: Context):ContextUtils {
internal class DebugInfo internal constructor(
override val context: Context,
override val llvmModule: LLVMModuleRef
) : ContextUtils {
val files = mutableMapOf<String, DIFileRef>()
val subprograms = mutableMapOf<LLVMValueRef, DISubprogramRef>()
/* Some functions are inlined on all callsites and body is eliminated by DCE, so there's no LLVM value */
val inlinedSubprograms = mutableMapOf<IrFunction, DISubprogramRef>()
var builder: DIBuilderRef? = null
val builder: DIBuilderRef = LLVMCreateDIBuilder(llvmModule)!!
var module: DIModuleRef? = null
var compilationUnit: DIScopeOpaqueRef? = null
var objHeaderPointerType: DITypeOpaqueRef? = null
var types = mutableMapOf<IrType, DITypeOpaqueRef>()
val llvmTypes = mapOf<IrType, LLVMTypeRef>(
context.irBuiltIns.booleanType to context.llvm.llvmInt8,
context.irBuiltIns.byteType to context.llvm.llvmInt8,
context.irBuiltIns.charType to context.llvm.llvmInt16,
context.irBuiltIns.shortType to context.llvm.llvmInt16,
context.irBuiltIns.intType to context.llvm.llvmInt32,
context.irBuiltIns.longType to context.llvm.llvmInt64,
context.irBuiltIns.floatType to context.llvm.llvmFloat,
context.irBuiltIns.doubleType to context.llvm.llvmDouble)
val llvmTypes = mapOf(
context.irBuiltIns.booleanType to llvm.llvmInt8,
context.irBuiltIns.byteType to llvm.llvmInt8,
context.irBuiltIns.charType to llvm.llvmInt16,
context.irBuiltIns.shortType to llvm.llvmInt16,
context.irBuiltIns.intType to llvm.llvmInt32,
context.irBuiltIns.longType to llvm.llvmInt64,
context.irBuiltIns.floatType to llvm.llvmFloat,
context.irBuiltIns.doubleType to llvm.llvmDouble
)
val otherLlvmType = LLVMPointerType(int64Type, 0)!!
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 otherLlvmType = LLVMPointerType(int64Type, 0)!!
val otherTypeSize = LLVMSizeOfTypeInBits(llvmTargetData, otherLlvmType)
val otherTypeAlignment = LLVMPreferredAlignmentOfType(llvmTargetData, otherLlvmType)
@@ -131,13 +135,13 @@ internal fun String?.toFileAndFolder(context: Context):FileAndFolder {
return FileAndFolder(file.name, parent)
}
internal fun generateDebugInfoHeader(context: Context) {
internal fun generateDebugInfoHeader(context: Context, llvmModule: LLVMModuleRef, debugInfo: DebugInfo) {
if (context.shouldContainAnyDebugInfo()) {
val path = context.config.outputFile
.toFileAndFolder(context)
@Suppress("UNCHECKED_CAST")
context.debugInfo.module = DICreateModule(
builder = context.debugInfo.builder,
debugInfo.module = DICreateModule(
builder = debugInfo.builder,
scope = null,
name = path.path(),
configurationMacro = "",
@@ -167,10 +171,10 @@ internal fun generateDebugInfoHeader(context: Context) {
val dwarfVersion = node(llvmTwo, DWARF.dwarfVersionMetaDataNodeName, Int32(DWARF.dwarfVersion(context.config)).llvm)
val nodeDebugInfoVersion = node(llvmTwo, DWARF.dwarfDebugInfoMetaDataNodeName, Int32(DWARF.debugInfoVersion).llvm)
val llvmModuleFlags = "llvm.module.flags"
LLVMAddNamedMetadataOperand(context.llvmModule, llvmModuleFlags, dwarfVersion)
LLVMAddNamedMetadataOperand(context.llvmModule, llvmModuleFlags, nodeDebugInfoVersion)
LLVMAddNamedMetadataOperand(llvmModule, llvmModuleFlags, dwarfVersion)
LLVMAddNamedMetadataOperand(llvmModule, llvmModuleFlags, nodeDebugInfoVersion)
val objHeaderType = DICreateStructType(
refBuilder = context.debugInfo.builder,
refBuilder = debugInfo.builder,
// TODO: here should be DIFile as scope.
scope = null,
name = "ObjHeader",
@@ -183,33 +187,34 @@ internal fun generateDebugInfoHeader(context: Context) {
elements = null,
elementsCount = 0,
refPlace = null).cast<DITypeOpaqueRef>()
context.debugInfo.objHeaderPointerType = dwarfPointerType(context, objHeaderType)
debugInfo.objHeaderPointerType = dwarfPointerType(debugInfo, objHeaderType)
}
}
@Suppress("UNCHECKED_CAST")
internal fun IrType.dwarfType(context: Context, targetData: LLVMTargetDataRef): DITypeOpaqueRef {
internal fun IrType.dwarfType(debugInfo: DebugInfo, targetData: LLVMTargetDataRef): DITypeOpaqueRef {
when {
this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(context, targetData, this.render(), llvmType(context), encoding().value.toInt())
this.computePrimitiveBinaryTypeOrNull() != null -> return debugInfoBaseType(debugInfo, targetData, this.render(), llvmType(debugInfo.llvm), encoding().value.toInt())
else -> {
return when {
classOrNull != null || this.isTypeParameter() -> context.debugInfo.objHeaderPointerType!!
classOrNull != null || this.isTypeParameter() -> debugInfo.objHeaderPointerType!!
else -> TODO("$this: Does this case really exist?")
}
}
}
}
internal fun IrType.diType(context: Context, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
context.debugInfo.types.getOrPut(this) {
dwarfType(context, llvmTargetData)
internal fun IrType.diType(debugInfo: DebugInfo, llvmTargetData: LLVMTargetDataRef): DITypeOpaqueRef =
debugInfo.types.getOrPut(this) {
dwarfType(debugInfo, llvmTargetData)
}
@Suppress("UNCHECKED_CAST")
private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typeName:String, type:LLVMTypeRef, encoding:Int) = DICreateBasicType(
context.debugInfo.builder, typeName,
private fun debugInfoBaseType(debugInfo: DebugInfo, targetData: LLVMTargetDataRef, typeName: String, type: LLVMTypeRef, encoding: Int) = DICreateBasicType(
debugInfo.builder, typeName,
LLVMSizeOfTypeInBits(targetData, type),
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding) as DITypeOpaqueRef
LLVMPreferredAlignmentOfType(targetData, type).toLong(), encoding
) as DITypeOpaqueRef
internal val IrFunction.types:List<IrType>
get() {
@@ -217,20 +222,20 @@ internal val IrFunction.types:List<IrType>
return listOf(returnType, *parameters.toTypedArray())
}
internal fun IrType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize)
internal fun IrType.size(debugInfo: DebugInfo) = debugInfo.llvmTypeSizes.getOrDefault(this, debugInfo.otherTypeSize)
internal fun IrType.alignment(context:Context) = context.debugInfo.llvmTypeAlignments.getOrDefault(this, context.debugInfo.otherTypeAlignment).toLong()
internal fun IrType.alignment(debugInfo: DebugInfo) = debugInfo.llvmTypeAlignments.getOrDefault(this, debugInfo.otherTypeAlignment).toLong()
internal fun IrType.llvmType(context:Context): LLVMTypeRef = context.debugInfo.llvmTypes.getOrElse(this) {
internal fun IrType.llvmType(llvm: Llvm): LLVMTypeRef = llvm.llvmTypes.getOrElse(this) {
when(computePrimitiveBinaryTypeOrNull()) {
PrimitiveBinaryType.BYTE -> context.llvm.llvmInt8
PrimitiveBinaryType.SHORT -> context.llvm.llvmInt16
PrimitiveBinaryType.INT -> context.llvm.llvmInt32
PrimitiveBinaryType.LONG -> context.llvm.llvmInt64
PrimitiveBinaryType.FLOAT -> context.llvm.llvmFloat
PrimitiveBinaryType.DOUBLE -> context.llvm.llvmDouble
PrimitiveBinaryType.VECTOR128 -> context.llvm.llvmVector128
else -> context.debugInfo.otherLlvmType
PrimitiveBinaryType.BYTE -> llvm.llvmInt8
PrimitiveBinaryType.SHORT -> llvm.llvmInt16
PrimitiveBinaryType.INT -> llvm.llvmInt32
PrimitiveBinaryType.LONG -> llvm.llvmInt64
PrimitiveBinaryType.FLOAT -> llvm.llvmFloat
PrimitiveBinaryType.DOUBLE -> llvm.llvmDouble
PrimitiveBinaryType.VECTOR128 -> llvm.llvmVector128
else -> llvm.otherLlvmType
}
}
@@ -248,39 +253,40 @@ internal fun IrType.encoding(): DwarfTypeKind = when(computePrimitiveBinaryTypeO
internal fun alignTo(value:Long, align:Long):Long = (value + align - 1) / align * align
internal fun IrFunction.subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef): DISubroutineTypeRef {
internal fun IrFunction.subroutineType(debugInfo: DebugInfo, llvmTargetData: LLVMTargetDataRef): DISubroutineTypeRef {
val types = this@subroutineType.types
return subroutineType(context, llvmTargetData, types)
return subroutineType(debugInfo, llvmTargetData, types)
}
internal fun subroutineType(context: Context, llvmTargetData: LLVMTargetDataRef, types: List<IrType>): DISubroutineTypeRef {
internal fun subroutineType(debugInfo: DebugInfo, llvmTargetData: LLVMTargetDataRef, types: List<IrType>): DISubroutineTypeRef {
return memScoped {
DICreateSubroutineType(context.debugInfo.builder, allocArrayOf(
types.map { it.diType(context, llvmTargetData) }),
DICreateSubroutineType(debugInfo.builder, allocArrayOf(
types.map { it.diType(debugInfo, llvmTargetData) }),
types.size)!!
}
}
@Suppress("UNCHECKED_CAST")
private fun dwarfPointerType(context: Context, type: DITypeOpaqueRef) =
DICreatePointerType(context.debugInfo.builder, type) as DITypeOpaqueRef
private fun dwarfPointerType(debugInfo: DebugInfo, type: DITypeOpaqueRef) =
DICreatePointerType(debugInfo.builder, type) as DITypeOpaqueRef
internal fun setupBridgeDebugInfo(context: Context, function: LLVMValueRef): LocationInfo? {
internal fun setupBridgeDebugInfo(context: Context, debugInfo: DebugInfo, function: LLVMValueRef): LocationInfo? {
if (!context.shouldContainLocationDebugInfo()) {
return null
}
val file = context.debugInfo.compilerGeneratedFile
val file = debugInfo.compilerGeneratedFile
val llvm = moduleToLlvm.getValue(debugInfo.llvmModule)
// TODO: can we share the scope among all bridges?
val scope: DIScopeOpaqueRef = DICreateFunction(
builder = context.debugInfo.builder,
builder = debugInfo.builder,
scope = file.reinterpret(),
name = function.name,
linkageName = function.name,
file = file,
lineNo = 0,
type = subroutineType(context, context.llvm.runtime.targetData, emptyList()), // TODO: use proper type.
type = subroutineType(debugInfo, llvm.runtime.targetData, emptyList()), // TODO: use proper type.
isLocal = 0,
isDefinition = 1,
scopeLine = 0

View File

@@ -151,7 +151,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
IntrinsicType.IMMUTABLE_BLOB -> {
@Suppress("UNCHECKED_CAST")
val arg = callSite.getValueArgument(0) as IrConst<String>
context.llvm.staticData.createImmutableBlob(arg)
codegen.llvm.staticData.createImmutableBlob(arg)
}
IntrinsicType.OBJC_GET_SELECTOR -> {
val selector = (callSite.getValueArgument(0) as IrConst<*>).value as String
@@ -287,7 +287,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
// however `vararg` is immutable, and in current implementation it has type `Array<E>`,
// so let's ignore this mismatch currently for simplicity.
return context.llvm.staticData.createConstArrayList(array, length).llvm
return codegen.llvm.staticData.createConstArrayList(array, length).llvm
}
private fun FunctionGenerationContext.emitGetNativeNullPtr(): LLVMValueRef =
@@ -404,7 +404,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
or(bitsWithPadding, preservedBits)
}
llvm.LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned()
LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned()
return codegen.theUnitInstanceRef.llvm
}
@@ -454,12 +454,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr)
val libobjc = context.standardLlvmSymbolsOrigin
val normalMessenger = context.llvm.externalFunction(
val normalMessenger = codegen.llvm.externalFunction(
"objc_msgSend$messengerNameSuffix",
functionType,
origin = libobjc
)
val superMessenger = context.llvm.externalFunction(
val superMessenger = codegen.llvm.externalFunction(
"objc_msgSendSuper$messengerNameSuffix",
functionType,
origin = libobjc
@@ -481,13 +481,13 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
assert (first.type == second.type) { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" }
return when (val typeKind = LLVMGetTypeKind(first.type)) {
llvm.LLVMTypeKind.LLVMFloatTypeKind, llvm.LLVMTypeKind.LLVMDoubleTypeKind,
LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind,
LLVMTypeKind.LLVMVectorTypeKind -> {
// 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())!!
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)
}
}

View File

@@ -81,10 +81,10 @@ val IrField.isGlobalNonPrimitive get() = when {
else -> storageKind == FieldStorageKind.GLOBAL
}
internal class RTTIGeneratorVisitor(context: Context) : IrElementVisitorVoid {
val generator = RTTIGenerator(context)
internal class RTTIGeneratorVisitor(context: Context, llvmModule: LLVMModuleRef) : IrElementVisitorVoid {
val generator = RTTIGenerator(context, llvmModule)
val kotlinObjCClassInfoGenerator = KotlinObjCClassInfoGenerator(context)
val kotlinObjCClassInfoGenerator = KotlinObjCClassInfoGenerator(context, llvmModule)
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
@@ -189,9 +189,13 @@ 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>,
val llvmModule: LLVMModuleRef
) : IrElementVisitorVoid {
val codegen = CodeGenerator(context)
val codegen = CodeGenerator(context, llvmModule)
// TODO: consider eliminating mutable state
private var currentCodeContext: CodeContext = TopLevelCodeContext
@@ -326,12 +330,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun FunctionGenerationContext.initThreadLocalField(irField: IrField) {
val initializer = irField.initializer ?: return
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val address = codegen.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
storeAny(evaluateExpression(initializer.expression), address, false)
}
private fun FunctionGenerationContext.initGlobalField(irField: IrField) {
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val address = codegen.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(this)
val initialValue = if (irField.initializer?.expression !is IrConst<*>?) {
val initialization = evaluateExpression(irField.initializer!!.expression)
if (irField.storageKind == FieldStorageKind.SHARED_FROZEN)
@@ -346,7 +350,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
(initialValue != null || // which are initialized from heap object
!irField.isFinal) // or are not final
if (needRegistration) {
call(context.llvm.initAndRegisterGlobalFunction, listOf(address, initialValue
call(codegen.llvm.initAndRegisterGlobalFunction, listOf(address, initialValue
?: kNullObjHeaderPtr))
} else if (initialValue != null) {
storeAny(initialValue, address, false)
@@ -355,20 +359,20 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun runAndProcessInitializers(konanLibrary: KotlinLibrary?, f: () -> Unit) {
// TODO: collect those two in one place.
context.llvm.fileUsesThreadLocalObjects = false
context.llvm.globalSharedObjects.clear()
codegen.llvm.fileUsesThreadLocalObjects = false
codegen.llvm.globalSharedObjects.clear()
context.llvm.initializersGenerationState.reset()
codegen.llvm.initializersGenerationState.reset()
f()
context.llvm.initializersGenerationState.globalInitFunction?.let { fileInitFunction ->
codegen.llvm.initializersGenerationState.globalInitFunction?.let { fileInitFunction ->
generateFunction(codegen, fileInitFunction, null, null) {
using(FunctionScope(fileInitFunction, it)) {
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
using(parameterScope) usingParameterScope@{
using(VariableScope()) usingVariableScope@{
context.llvm.initializersGenerationState.topLevelFields
codegen.llvm.initializersGenerationState.topLevelFields
.filter { it.storageKind == FieldStorageKind.SHARED_FROZEN }
.forEach { initGlobalField(it) }
ret(null)
@@ -378,7 +382,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
context.llvm.initializersGenerationState.threadLocalInitFunction?.let { fileInitFunction ->
codegen.llvm.initializersGenerationState.threadLocalInitFunction?.let { fileInitFunction ->
generateFunction(codegen, fileInitFunction, null, null) {
using(FunctionScope(fileInitFunction, it)) {
val parameterScope = ParameterScope(fileInitFunction, functionGenerationContext)
@@ -388,12 +392,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val bbInitThreadLocals = basicBlock("label_init_thread_local", null, null)
condBr(param(0), bbInitGlobals, bbInitThreadLocals)
positionAtEnd(bbInitGlobals)
context.llvm.initializersGenerationState.topLevelFields
codegen.llvm.initializersGenerationState.topLevelFields
.filter { it.storageKind == FieldStorageKind.GLOBAL }
.forEach { initGlobalField(it) }
br(bbInitThreadLocals)
positionAtEnd(bbInitThreadLocals)
context.llvm.initializersGenerationState.topLevelFields
codegen.llvm.initializersGenerationState.topLevelFields
.filter { it.storageKind == FieldStorageKind.THREAD_LOCAL }
.forEach { initThreadLocalField(it) }
ret(null)
@@ -403,14 +407,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
if (!context.llvm.fileUsesThreadLocalObjects && context.llvm.globalSharedObjects.isEmpty()
&& context.llvm.initializersGenerationState.isEmpty()) {
if (!codegen.llvm.fileUsesThreadLocalObjects && codegen.llvm.globalSharedObjects.isEmpty()
&& codegen.llvm.initializersGenerationState.isEmpty()) {
return
}
// Create global initialization records.
val initNode = createInitNode(createInitBody())
context.llvm.irStaticInitializers.add(IrStaticInitializer(konanLibrary, createInitCtor(initNode)))
codegen.llvm.irStaticInitializers.add(IrStaticInitializer(konanLibrary, createInitCtor(initNode)))
}
//-------------------------------------------------------------------------//
@@ -425,20 +429,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.coverage.collectRegions(declaration)
initializeCachedBoxes(context)
declaration.acceptChildrenVoid(this)
initializeCachedBoxes(context, codegen)
// declaration.acceptChildrenVoid(this)
runAndProcessInitializers(null) {
// Note: it is here because it also generates some bitcode.
context.objCExport.generate(codegen)
codegen.objCDataGenerator?.finishModule()
context.coverage.writeRegionInfo()
setRuntimeConstGlobals()
overrideRuntimeGlobals()
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
if (context.isNativeLibrary) {
appendCAdapters()
}
@@ -449,10 +449,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
val kVoidFuncType = functionType(voidType)
val kNodeInitType = LLVMGetTypeByName(context.llvmModule, "struct.InitNode")!!
val kMemoryStateType = LLVMGetTypeByName(context.llvmModule, "struct.MemoryState")!!
val kInitFuncType = functionType(voidType, false, int32Type, pointerType(kMemoryStateType))
val kVoidFuncType by lazy { functionType(voidType) }
val kNodeInitType by lazy { context.llvm.runtime.kNodeInitType }
val kMemoryStateType by lazy { context.llvm.runtime.kMemoryStateType }
val kInitFuncType by lazy { functionType(voidType, false, int32Type, pointerType(kMemoryStateType)) }
//-------------------------------------------------------------------------//
@@ -468,7 +468,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun createInitBody(): LLVMValueRef {
val initFunction = addLlvmFunctionWithDefaultAttributes(
context,
context.llvmModule!!,
llvmModule,
"",
kInitFuncType
)
@@ -493,11 +493,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Globals initializers may contain accesses to objects, so visit them first.
appendingTo(bbInit) {
if (!context.useLazyFileInitializers()) {
context.llvm.initializersGenerationState.topLevelFields
codegen.llvm.initializersGenerationState.topLevelFields
.filterNot { it.storageKind == FieldStorageKind.THREAD_LOCAL }
.forEach { initGlobalField(it) }
}
context.llvm.initializersGenerationState.moduleGlobalInitializers.forEach {
codegen.llvm.initializersGenerationState.moduleGlobalInitializers.forEach {
if (context.shouldContainLocationDebugInfo())
debugLocation(it.startLocation!!, it.endLocation)
evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT)
@@ -506,17 +506,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
appendingTo(bbLocalInit) {
context.llvm.initializersGenerationState.threadLocalInitState?.let {
codegen.llvm.initializersGenerationState.threadLocalInitState?.let {
val address = it.getAddress(functionGenerationContext)
store(Int32(FILE_NOT_INITIALIZED).llvm, address)
LLVMSetInitializer(address, Int32(FILE_NOT_INITIALIZED).llvm)
}
if (!context.useLazyFileInitializers()) {
context.llvm.initializersGenerationState.topLevelFields
codegen.llvm.initializersGenerationState.topLevelFields
.filter { it.storageKind == FieldStorageKind.THREAD_LOCAL }
.forEach { initThreadLocalField(it) }
}
context.llvm.initializersGenerationState.moduleThreadLocalInitializers.forEach {
codegen.llvm.initializersGenerationState.moduleThreadLocalInitializers.forEach {
if (context.shouldContainLocationDebugInfo())
debugLocation(it.startLocation!!, it.endLocation)
evaluateSimpleFunctionCall(it, emptyList(), Lifetime.IRRELEVANT)
@@ -525,29 +525,29 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
appendingTo(bbLocalAlloc) {
if (context.llvm.tlsCount > 0) {
if (codegen.llvm.tlsCount > 0) {
val memory = LLVMGetParam(initFunction, 1)!!
call(context.llvm.addTLSRecord, listOf(memory, context.llvm.tlsKey,
Int32(context.llvm.tlsCount).llvm))
call(codegen.llvm.addTLSRecord, listOf(memory, codegen.llvm.tlsKey,
Int32(codegen.llvm.tlsCount).llvm))
}
ret(null)
}
appendingTo(bbGlobalDeinit) {
context.llvm.initializersGenerationState.topLevelFields
codegen.llvm.initializersGenerationState.topLevelFields
// Only if a subject for memory management.
.forEach { irField ->
if (irField.type.binaryTypeIsReference() && irField.storageKind != FieldStorageKind.THREAD_LOCAL) {
val address = context.llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
val address = llvmDeclarations.forStaticField(irField).storageAddressAccess.getAddress(
functionGenerationContext
)
storeHeapRef(codegen.kNullObjHeaderPtr, address)
}
}
context.llvm.globalSharedObjects.forEach { address ->
codegen.llvm.globalSharedObjects.forEach { address ->
storeHeapRef(codegen.kNullObjHeaderPtr, address)
}
context.llvm.initializersGenerationState.globalInitState?.let {
codegen.llvm.initializersGenerationState.globalInitState?.let {
store(Int32(FILE_NOT_INITIALIZED).llvm, it)
}
ret(null)
@@ -566,7 +566,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Create static object of class InitNode.
val initNode = LLVMConstNamedStruct(kNodeInitType, argList, 2)!!
// Create global variable with init record data.
return context.llvm.staticData.placeGlobal(
return codegen.llvm.staticData.placeGlobal(
"init_node", constPointer(initNode), isExported = false).llvmGlobal
}
@@ -574,7 +574,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun createInitCtor(initNodePtr: LLVMValueRef): LLVMValueRef {
val ctorFunction = generateFunctionNoRuntime(codegen, kVoidFuncType, "") {
call(context.llvm.appendToInitalizersTail, listOf(initNodePtr))
call(codegen.llvm.appendToInitalizersTail, listOf(initNodePtr))
ret(null)
}
LLVMSetLinkage(ctorFunction, LLVMLinkage.LLVMPrivateLinkage)
@@ -590,6 +590,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
declaration.acceptChildrenVoid(this)
}
}
context.coverage.writeRegionInfo(llvmModule)
appendLlvmUsed("llvm.used", codegen.llvm.usedFunctions + codegen.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", codegen.llvm.compilerUsedGlobals)
}
//-------------------------------------------------------------------------//
@@ -725,7 +728,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
val coverageInstrumentation: LLVMCoverageInstrumentation? =
context.coverage.tryGetInstrumentation(declaration) { function, args -> functionGenerationContext.call(function, args) }
context.coverage.tryGetInstrumentation(declaration, llvmModule) { function, args -> functionGenerationContext.call(function, args) }
private var name:String? = declaration?.name?.asString()
@@ -752,7 +755,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private val scope by lazy {
if (!context.shouldContainLocationDebugInfo())
return@lazy null
declaration?.scope() ?: llvmFunction!!.scope(0, subroutineType(context, codegen.llvmTargetData, listOf(context.irBuiltIns.intType)))
declaration?.scope() ?: llvmFunction!!.scope(0, subroutineType(codegen.debugInfo, codegen.llvmTargetData, listOf(context.irBuiltIns.intType)))
}
private val fileScope = (fileScope() as? FileScope)
@@ -776,14 +779,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
private fun getGlobalInitStateFor(file: IrFile): LLVMValueRef =
context.llvm.initializersGenerationState.fileGlobalInitStates.getOrPut(file) {
codegen.llvm.initializersGenerationState.fileGlobalInitStates.getOrPut(file) {
codegen.addGlobal("state_global$${file.fileEntry.name}", int32Type, false).also {
LLVMSetInitializer(it, Int32(FILE_NOT_INITIALIZED).llvm)
}
}
private fun getThreadLocalInitStateFor(file: IrFile): AddressAccess =
context.llvm.initializersGenerationState.fileThreadLocalInitStates.getOrPut(file) {
codegen.llvm.initializersGenerationState.fileThreadLocalInitStates.getOrPut(file) {
codegen.addKotlinThreadLocal("state_thread_local$${file.fileEntry.name}", int32Type)
}
@@ -793,31 +796,31 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val body = declaration.body
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(codegen.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(declaration.valueParameters.singleOrNull()?.type == context.irBuiltIns.booleanType) { "File initializer must take a single boolean parameter" }
require(declaration.returnsUnit()) { "File initializer must return Unit" }
context.llvm.initializersGenerationState.globalInitFunction = declaration
context.llvm.initializersGenerationState.globalInitState = getGlobalInitStateFor(declaration.parent as IrFile)
codegen.llvm.initializersGenerationState.globalInitFunction = declaration
codegen.llvm.initializersGenerationState.globalInitState = getGlobalInitStateFor(declaration.parent as IrFile)
}
if (declaration.origin == DECLARATION_ORIGIN_FILE_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(codegen.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(declaration.valueParameters.singleOrNull()?.type == context.irBuiltIns.booleanType) { "File initializer must take a single boolean parameter" }
require(declaration.returnsUnit()) { "File initializer must return Unit" }
context.llvm.initializersGenerationState.threadLocalInitFunction = declaration
context.llvm.initializersGenerationState.threadLocalInitState = getThreadLocalInitStateFor(declaration.parent as IrFile)
codegen.llvm.initializersGenerationState.threadLocalInitFunction = declaration
codegen.llvm.initializersGenerationState.threadLocalInitState = getThreadLocalInitStateFor(declaration.parent as IrFile)
}
if (declaration.origin == DECLARATION_ORIGIN_MODULE_GLOBAL_INITIALIZER) {
require(declaration.valueParameters.isEmpty()) { "Module initializer must be a parameterless function" }
require(declaration.returnsUnit()) { "Module initializer must return Unit" }
context.llvm.initializersGenerationState.moduleGlobalInitializers.add(declaration)
codegen.llvm.initializersGenerationState.moduleGlobalInitializers.add(declaration)
}
if (declaration.origin == DECLARATION_ORIGIN_MODULE_THREAD_LOCAL_INITIALIZER) {
require(declaration.valueParameters.isEmpty()) { "Module initializer must be a parameterless function" }
require(declaration.returnsUnit()) { "Module initializer must return Unit" }
context.llvm.initializersGenerationState.moduleThreadLocalInitializers.add(declaration)
codegen.llvm.initializersGenerationState.moduleThreadLocalInitializers.add(declaration)
}
if ((declaration as? IrSimpleFunction)?.modality == Modality.ABSTRACT
@@ -843,7 +846,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
recordCoverage(body)
if (declaration.isReifiedInline) {
callDirect(context.ir.symbols.throwIllegalStateExceptionWithMessage.owner,
listOf(context.llvm.staticData.kotlinStringLiteral(
listOf(codegen.llvm.staticData.kotlinStringLiteral(
"unsupported call of reified inlined function `${declaration.fqNameForIrSerialization}`").llvm),
Lifetime.IRRELEVANT)
return@usingVariableScope
@@ -862,11 +865,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (declaration.retainAnnotation(context.config.target)) {
context.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
codegen.llvm.usedFunctions.add(codegen.llvmFunction(declaration))
}
if (context.shouldVerifyBitCode())
verifyModule(context.llvmModule!!,
verifyModule(llvmModule,
"${declaration.descriptor.containingDeclaration}::${ir2string(declaration)}")
}
@@ -896,13 +899,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
if (declaration.kind.isSingleton && !declaration.isUnit()) {
val singleton = context.llvmDeclarations.forSingleton(declaration)
val singleton = codegen.llvmDeclarations.forSingleton(declaration)
val access = singleton.instanceStorage
if (access is GlobalAddressAccess) {
// 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.
LLVMSetInitializer(access.getAddress(null), if (declaration.storageKind(context) == ObjectStorageKind.PERMANENT)
context.llvm.staticData.createConstKotlinObject(declaration,
codegen.llvm.staticData.createConstKotlinObject(declaration,
*computeFields(declaration)).llvm else codegen.kNullObjHeaderPtr)
} else {
// Thread local objects are kept in a special map, so they need a getter function to be accessible
@@ -920,7 +923,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
// inits and deinits TLS.
context.llvm.fileUsesThreadLocalObjects = true
codegen.llvm.fileUsesThreadLocalObjects = true
}
}
}
@@ -947,7 +950,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
debugFieldDeclaration(declaration)
if (context.needGlobalInit(declaration)) {
val type = codegen.getLLVMType(declaration.type)
val globalPropertyAccess = context.llvmDeclarations.forStaticField(declaration).storageAddressAccess
val globalPropertyAccess = codegen.llvmDeclarations.forStaticField(declaration).storageAddressAccess
val initializer = declaration.initializer?.expression as? IrConst<*>
val globalProperty = (globalPropertyAccess as? GlobalAddressAccess)?.getAddress(null)
if (globalProperty != null) {
@@ -956,7 +959,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// (Cannot do this before the global is initialized).
LLVMSetLinkage(globalProperty, LLVMLinkage.LLVMInternalLinkage)
}
context.llvm.initializersGenerationState.topLevelFields.add(declaration)
codegen.llvm.initializersGenerationState.topLevelFields.add(declaration)
}
}
@@ -1350,7 +1353,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.positionAtEnd(loopBody)
if (context.memoryModel == MemoryModel.EXPERIMENTAL)
call(context.llvm.Kotlin_mm_safePointWhileLoopBody, emptyList())
call(codegen.llvm.Kotlin_mm_safePointWhileLoopBody, emptyList())
loop.body?.generate()
functionGenerationContext.br(loopScope.loopCheck)
@@ -1372,7 +1375,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.positionAtEnd(loopBody)
if (context.memoryModel == MemoryModel.EXPERIMENTAL)
call(context.llvm.Kotlin_mm_safePointWhileLoopBody, emptyList())
call(codegen.llvm.Kotlin_mm_safePointWhileLoopBody, emptyList())
loop.body?.generate()
functionGenerationContext.br(loopScope.loopCheck)
@@ -1413,18 +1416,18 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val file = (currentCodeContext.fileScope() as FileScope).file.file()
return when (element) {
is IrVariable -> if (shouldGenerateDebugInfo(element)) debugInfoLocalVariableLocation(
builder = context.debugInfo.builder,
builder = codegen.debugInfo.builder,
functionScope = locationInfo.scope,
diType = element.type.diType(context, codegen.llvmTargetData),
diType = element.type.diType(codegen.debugInfo, codegen.llvmTargetData),
name = element.debugNameConversion(),
file = file,
line = locationInfo.line,
location = location)
else null
is IrValueParameter -> debugInfoParameterLocation(
builder = context.debugInfo.builder,
builder = codegen.debugInfo.builder,
functionScope = locationInfo.scope,
diType = element.type.diType(context, codegen.llvmTargetData),
diType = element.type.diType(codegen.debugInfo, codegen.llvmTargetData),
name = element.debugNameConversion(),
argNo = function.allParameters.indexOf(element) + 1,
file = file,
@@ -1597,11 +1600,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val srcObjInfoPtr = functionGenerationContext.bitcast(codegen.kObjHeaderPtr, obj)
return if (!context.ghaEnabled()) {
call(context.llvm.isInstanceFunction, listOf(srcObjInfoPtr, codegen.typeInfoValue(dstClass)))
call(codegen.llvm.isInstanceFunction, listOf(srcObjInfoPtr, codegen.typeInfoValue(dstClass)))
} else {
val dstHierarchyInfo = context.getLayoutBuilder(dstClass).hierarchyInfo
if (!dstClass.isInterface) {
call(context.llvm.isInstanceOfClassFastFunction,
call(codegen.llvm.isInstanceOfClassFastFunction,
listOf(srcObjInfoPtr, Int32(dstHierarchyInfo.classIdLo).llvm, Int32(dstHierarchyInfo.classIdHi).llvm))
} else {
// Essentially: typeInfo.itable[place(interfaceId)].id == interfaceId
@@ -1626,7 +1629,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (dstClass.isInterface) {
val isMeta = if (dstClass.isObjCMetaClass()) kTrue else kFalse
call(
context.llvm.Kotlin_Interop_DoesObjectConformToProtocol,
codegen.llvm.Kotlin_Interop_DoesObjectConformToProtocol,
listOf(
objCObject,
genGetObjCProtocol(dstClass),
@@ -1635,7 +1638,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
)
} else {
call(
context.llvm.Kotlin_Interop_IsObjectKindOfClass,
codegen.llvm.Kotlin_Interop_IsObjectKindOfClass,
listOf(objCObject, genGetObjCClass(dstClass))
)
}.let {
@@ -1646,7 +1649,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} else {
// e.g. ObjCObject, ObjCObjectBase etc.
if (dstClass.isObjCMetaClass()) {
val isClass = context.llvm.externalFunction(
val isClass = codegen.llvm.externalFunction(
"object_isClass",
functionType(int8Type, false, int8TypePtr),
context.standardLlvmSymbolsOrigin
@@ -1661,7 +1664,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val protocolClass =
functionGenerationContext.getObjCClass("Protocol", context.standardLlvmSymbolsOrigin)
call(
context.llvm.Kotlin_Interop_IsObjectKindOfClass,
codegen.llvm.Kotlin_Interop_IsObjectKindOfClass,
listOf(objCObject, protocolClass)
)
} else {
@@ -1693,7 +1696,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (context.config.threadsAreAllowed && value.symbol.owner.isGlobalNonPrimitive) {
functionGenerationContext.checkGlobalsAccessible(currentCodeContext.exceptionHandler)
}
val ptr = context.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
val ptr = codegen.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext
)
functionGenerationContext.loadSlot(ptr, !value.symbol.owner.isFinal)
@@ -1746,17 +1749,17 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMPrintTypeToString(thisPtr.type)?.toKString().toString()
}
if (needMutationCheck(value.symbol.owner.parentAsClass)) {
functionGenerationContext.call(context.llvm.mutationCheck,
functionGenerationContext.call(codegen.llvm.mutationCheck,
listOf(functionGenerationContext.bitcast(codegen.kObjHeaderPtr, thisPtr)),
Lifetime.IRRELEVANT, currentCodeContext.exceptionHandler)
if (functionGenerationContext.isObjectType(valueToAssign.type))
functionGenerationContext.call(context.llvm.checkLifetimesConstraint, listOf(thisPtr, valueToAssign))
functionGenerationContext.call(codegen.llvm.checkLifetimesConstraint, listOf(thisPtr, valueToAssign))
}
functionGenerationContext.storeAny(valueToAssign, fieldPtrOfClass(thisPtr, value.symbol.owner), false)
} else {
assert(value.receiver == null)
val globalAddress = context.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
val globalAddress = codegen.llvmDeclarations.forStaticField(value.symbol.owner).storageAddressAccess.getAddress(
functionGenerationContext
)
if (context.config.threadsAreAllowed && value.symbol.owner.storageKind == FieldStorageKind.GLOBAL)
@@ -1777,7 +1780,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun fieldPtrOfClass(thisPtr: LLVMValueRef, value: IrField): LLVMValueRef {
val fieldInfo = context.llvmDeclarations.forField(value)
val fieldInfo = codegen.llvmDeclarations.forField(value)
val typePtr = pointerType(fieldInfo.classBodyType)
@@ -1788,7 +1791,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateStringConst(value: IrConst<String>) =
context.llvm.staticData.kotlinStringLiteral(value.value).llvm
codegen.llvm.staticData.kotlinStringLiteral(value.value).llvm
private fun evaluateConst(value: IrConst<*>): LLVMValueRef {
context.log{"evaluateConst : ${ir2string(value)}"}
@@ -1888,8 +1891,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private val scope by lazy {
if (!context.shouldContainLocationDebugInfo() || returnableBlock.startOffset == UNDEFINED_OFFSET)
return@lazy null
val lexicalBlockFile = DICreateLexicalBlockFile(context.debugInfo.builder, functionScope()!!.scope(), super.file.file())
DICreateLexicalBlock(context.debugInfo.builder, lexicalBlockFile, super.file.file(), returnableBlock.startLine(), returnableBlock.startColumn())!!
val lexicalBlockFile = DICreateLexicalBlockFile(codegen.debugInfo.builder, functionScope()!!.scope(), super.file.file())
DICreateLexicalBlock(codegen.debugInfo.builder, lexicalBlockFile, super.file.file(), returnableBlock.startLine(), returnableBlock.startColumn())!!
}
override fun scope() = scope
@@ -1922,7 +1925,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val members = mutableListOf<DIDerivedTypeRef>()
@Suppress("UNCHECKED_CAST")
val scope = if (isExported && context.shouldContainDebugInfo())
context.debugInfo.objHeaderPointerType
codegen.debugInfo.objHeaderPointerType
else null
override fun classScope(): CodeContext? = this
}
@@ -2037,15 +2040,15 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun debugFieldDeclaration(expression: IrField) {
val scope = currentCodeContext.classScope() as? ClassScope ?: return
if (!scope.isExported || !context.shouldContainDebugInfo()) return
if (!scope.isExported || true) return // !context.shouldContainDebugInfo()
val irFile = (currentCodeContext.fileScope() as FileScope).file
val sizeInBits = expression.type.size(context)
val sizeInBits = expression.type.size(codegen.debugInfo)
scope.offsetInBits += sizeInBits
val alignInBits = expression.type.alignment(context)
val alignInBits = expression.type.alignment(codegen.debugInfo)
scope.offsetInBits = alignTo(scope.offsetInBits, alignInBits)
@Suppress("UNCHECKED_CAST")
scope.members.add(DICreateMemberType(
refBuilder = context.debugInfo.builder,
refBuilder = codegen.debugInfo.builder,
refScope = scope.scope as DIScopeOpaqueRef,
name = expression.computeSymbolName(),
file = irFile.file(),
@@ -2054,16 +2057,16 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
alignInBits = alignInBits,
offsetInBits = scope.offsetInBits,
flags = 0,
type = expression.type.diType(context, codegen.llvmTargetData)
type = expression.type.diType(codegen.debugInfo, codegen.llvmTargetData)
)!!)
}
//-------------------------------------------------------------------------//
private fun IrFile.file(): DIFileRef {
return context.debugInfo.files.getOrPut(this.fileEntry.name) {
return codegen.debugInfo.files.getOrPut(this.fileEntry.name) {
val path = this.fileEntry.name.toFileAndFolder(context)
DICreateFile(context.debugInfo.builder, path.file, path.folder)!!
DICreateFile(codegen.debugInfo.builder, path.file, path.folder)!!
}
}
@@ -2093,9 +2096,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
else
codegen.llvmFunctionOrNull(this)
return if (!isReifiedInline && functionLlvmValue != null) {
context.debugInfo.subprograms.getOrPut(functionLlvmValue) {
codegen.debugInfo.subprograms.getOrPut(functionLlvmValue) {
memScoped {
val subroutineType = subroutineType(context, codegen.llvmTargetData)
val subroutineType = subroutineType(codegen.debugInfo, codegen.llvmTargetData)
val llvmFunnction = codegen.llvmFunction(this@scope)
diFunctionScope(name.asString(), llvmFunnction.name!!, startLine, subroutineType).also {
if (!this@scope.isInline)
@@ -2104,9 +2107,9 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
} as DIScopeOpaqueRef
} else {
context.debugInfo.inlinedSubprograms.getOrPut(this) {
codegen.debugInfo.inlinedSubprograms.getOrPut(this) {
memScoped {
val subroutineType = subroutineType(context, codegen.llvmTargetData)
val subroutineType = subroutineType(codegen.debugInfo, codegen.llvmTargetData)
diFunctionScope(name.asString(), "<inlined-out:$name>", startLine, subroutineType)
}
} as DIScopeOpaqueRef
@@ -2116,7 +2119,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
@Suppress("UNCHECKED_CAST")
private fun LLVMValueRef.scope(startLine:Int, subroutineType: DISubroutineTypeRef): DIScopeOpaqueRef? {
return context.debugInfo.subprograms.getOrPut(this) {
return codegen.debugInfo.subprograms.getOrPut(this) {
diFunctionScope(name!!, name!!, startLine, subroutineType).also {
DIFunctionAddSubprogram(this@scope, it)
}
@@ -2125,8 +2128,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
@Suppress("UNCHECKED_CAST")
private fun diFunctionScope(name: String, linkageName: String, startLine: Int, subroutineType: DISubroutineTypeRef) = DICreateFunction(
builder = context.debugInfo.builder,
scope = context.debugInfo.compilationUnit,
builder = codegen.debugInfo.builder,
scope = codegen.debugInfo.compilationUnit,
name = name,
linkageName = linkageName,
file = file().file(),
@@ -2294,7 +2297,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetVolatile(state, 1)
condBr(icmpEq(state, Int32(FILE_INITIALIZED).llvm), bbExit, bbInit)
positionAtEnd(bbInit)
call(context.llvm.callInitGlobalPossiblyLock, listOf(statePtr, initializerPtr),
call(codegen.llvm.callInitGlobalPossiblyLock, listOf(statePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler)
br(bbExit)
positionAtEnd(bbExit)
@@ -2318,7 +2321,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
positionAtEnd(bbCheckLocalState)
condBr(icmpNe(load(localStatePtr), Int32(FILE_INITIALIZED).llvm), bbInit, bbExit)
positionAtEnd(bbInit)
call(context.llvm.callInitThreadLocal, listOf(globalStatePtr, localStatePtr, initializerPtr),
call(codegen.llvm.callInitThreadLocal, listOf(globalStatePtr, localStatePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler)
br(bbExit)
positionAtEnd(bbExit)
@@ -2334,7 +2337,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val bbExit = basicBlock("label_continue", null)
condBr(icmpEq(load(statePtr), Int32(FILE_INITIALIZED).llvm), bbExit, bbInit)
positionAtEnd(bbInit)
call(context.llvm.callInitThreadLocal, listOf(kNullInt32Ptr, statePtr, initializerPtr),
call(codegen.llvm.callInitThreadLocal, listOf(kNullInt32Ptr, statePtr, initializerPtr),
exceptionHandler = currentCodeContext.exceptionHandler)
br(bbExit)
positionAtEnd(bbExit)
@@ -2398,7 +2401,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val annotation = irClass.annotations.findAnnotation(externalObjCClassFqName)!!
val protocolGetterName = annotation.getAnnotationStringValue("protocolGetter")
val protocolGetter = context.llvm.externalFunction(
val protocolGetter = codegen.llvm.externalFunction(
protocolGetterName,
functionType(int8TypePtr, false),
irClass.llvmSymbolOrigin,
@@ -2508,7 +2511,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun call(function: IrFunction, llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
check(!function.isTypedIntrinsic)
val needsNativeThreadState = function.needsNativeThreadState
val exceptionHandler = function.annotations.findAnnotation(RuntimeNames.filterExceptions)?.let {
val foreignExceptionMode = ForeignExceptionMode.byValue(it.getAnnotationValueOrNull<String>("mode"))
@@ -2525,6 +2527,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val result = call(llvmFunction, args, resultLifetime, exceptionHandler)
if (LLVMIsDeclaration(llvmFunction) != 0) {
val currentModule = LLVMGetGlobalParent(LLVMGetBasicBlockParent(LLVMGetInstructionParent(result)))
assert(LLVMGetGlobalParent(llvmFunction) == currentModule) {
"Error calling ${function.fqNameForIrSerialization} from different module!"
}
}
when {
!function.isSuspend && function.returnType.isNothing() ->
functionGenerationContext.unreachable()
@@ -2576,7 +2585,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val argsCasted = args.map { it -> constPointer(it).bitcast(int8TypePtr) }
val llvmUsedGlobal =
context.llvm.staticData.placeGlobalArray(name, int8TypePtr, argsCasted)
codegen.llvm.staticData.placeGlobalArray(name, int8TypePtr, argsCasted)
LLVMSetLinkage(llvmUsedGlobal.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
LLVMSetSection(llvmUsedGlobal.llvmGlobal, "llvm.metadata")
@@ -2585,7 +2594,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
// Globals set this way will be const, but can only be built into runtime-containing module. Which
// means they are set at stdlib-cache compilation time.
private fun setRuntimeConstGlobal(name: String, value: ConstValue) {
val global = context.llvm.staticData.placeGlobal(name, value)
val global = codegen.llvm.staticData.placeGlobal(name, value)
global.setConstant(true)
global.setLinkage(LLVMLinkage.LLVMExternalLinkage)
}
@@ -2612,14 +2621,14 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetLinkage(initializer, LLVMLinkage.LLVMPrivateLinkage)
context.llvm.otherStaticInitializers += initializer
codegen.llvm.otherStaticInitializers += initializer
} else {
context.llvmImports.add(context.standardLlvmSymbolsOrigin)
// 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 = codegen.llvm.staticData.placeGlobal(name, value, true)
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
context.llvm.usedGlobals += global.llvmGlobal
codegen.llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
}
}
@@ -2663,13 +2672,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
fun appendStaticInitializers() {
// 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 = (codegen.llvm.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */)
val libraryToInitializers = libraries.associateWith {
mutableListOf<LLVMValueRef>()
}
context.llvm.irStaticInitializers.forEach {
codegen.llvm.irStaticInitializers.forEach {
val library = it.konanLibrary
val initializers = libraryToInitializers[library]
?: error("initializer for not included library ${library?.libraryFile}")
@@ -2686,7 +2695,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val ctorFunction = addLlvmFunctionWithDefaultAttributes(
context,
context.llvmModule!!,
llvmModule,
ctorName,
kVoidFuncType
)
@@ -2696,7 +2705,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (library == null || context.llvmModuleSpecification.containsLibrary(library)) {
val otherInitializers =
context.llvm.otherStaticInitializers.takeIf { library == null }.orEmpty()
codegen.llvm.otherStaticInitializers.takeIf { library == null }.orEmpty()
appendStaticInitializers(ctorFunction, initializers + otherInitializers)
} else {
@@ -2714,7 +2723,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun appendStaticInitializers(ctorFunction: LLVMValueRef, initializers: List<LLVMValueRef>) {
generateFunctionNoRuntime(codegen, ctorFunction) {
val initGuardName = ctorFunction.name.orEmpty() + "_guard"
val initGuard = LLVMAddGlobal(context.llvmModule, int32Type, initGuardName)
val initGuard = LLVMAddGlobal(llvmModule, int32Type, initGuardName)
LLVMSetInitializer(initGuard, kImmZero)
LLVMSetLinkage(initGuard, LLVMLinkage.LLVMPrivateLinkage)
val bbInited = basicBlock("inited", null)
@@ -2754,7 +2763,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
LLVMSetLinkage(globalCtorFunction, LLVMLinkage.LLVMPrivateLinkage)
// Append initializers of global variables in "llvm.global_ctors" array.
val globalCtors = context.llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
val globalCtors = codegen.llvm.staticData.placeGlobalArray("llvm.global_ctors", kCtorType,
listOf(createGlobalCtor(globalCtorFunction)))
LLVMSetLinkage(globalCtors.llvmGlobal, LLVMLinkage.LLVMAppendingLinkage)
if (context.config.produce == CompilerOutputKind.PROGRAM) {

View File

@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMLinkage
import llvm.LLVMModuleRef
import llvm.LLVMSetLinkage
import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.konan.*
@@ -16,11 +17,14 @@ import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
internal class KotlinObjCClassInfoGenerator(override val context: Context) : ContextUtils {
internal class KotlinObjCClassInfoGenerator(
override val context: Context,
override val llvmModule: LLVMModuleRef
) : ContextUtils {
fun generate(irClass: IrClass) {
assert(irClass.isFinalClass)
val objCLLvmDeclarations = context.llvmDeclarations.forClass(irClass).objCDeclarations!!
val objCLLvmDeclarations = codegen.llvmDeclarations.forClass(irClass).objCDeclarations!!
val instanceMethods = generateInstanceMethodDescs(irClass)
@@ -28,11 +32,11 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
val classMethods = companionObject?.generateMethodDescs().orEmpty()
val superclassName = irClass.getSuperClassNotAny()!!.let {
context.llvm.imports.add(it.llvmSymbolOrigin)
codegen.llvm.imports.add(it.llvmSymbolOrigin)
it.descriptor.getExternalObjCClassBinaryName()
}
val protocolNames = irClass.getSuperInterfaces().map {
context.llvm.imports.add(it.llvmSymbolOrigin)
codegen.llvm.imports.add(it.llvmSymbolOrigin)
it.name.asString().removeSuffix("Protocol")
}
@@ -87,7 +91,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
.distinctBy { it.selector }
allInitMethodsInfo.mapTo(this) {
ObjCMethodDesc(it.selector, it.encoding, context.llvm.missingInitImp)
ObjCMethodDesc(it.selector, it.encoding, codegen.llvm.missingInitImp)
}
}
@@ -148,7 +152,7 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
return constPointer(function)
}
private val codegen = CodeGenerator(context)
private val codegen = CodeGenerator(context, llvmModule)
companion object {
const val createdClassFieldIndex = 11
@@ -164,6 +168,6 @@ internal fun CodeGenerator.kotlinObjCClassInfo(irClass: IrClass): LLVMValueRef {
origin = irClass.llvmSymbolOrigin
)
} else {
context.llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal
llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal
}
}

View File

@@ -21,9 +21,9 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import kotlin.collections.set
internal fun createLlvmDeclarations(context: Context): LlvmDeclarations {
val generator = DeclarationsGeneratorVisitor(context)
context.ir.irModule.acceptChildrenVoid(generator)
internal fun createLlvmDeclarations(context: Context, irFile: IrFile): LlvmDeclarations {
val generator = DeclarationsGeneratorVisitor(context, irFileToModule.getValue(irFile))
irFile.acceptChildrenVoid(generator)
return LlvmDeclarations(generator.uniques)
}
@@ -80,19 +80,21 @@ private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>
val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) }
// TODO: consider adding synthetic ObjHeader field to Any.
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(llvmModule), name)!!
// 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.
val hasBigAlignment = fields.any { LLVMABIAlignmentOfType(context.llvm.runtime.targetData, getLLVMType(it.type)) > 8 }
val hasBigAlignment = fields.any { LLVMABIAlignmentOfType(llvm.runtime.targetData, getLLVMType(it.type)) > 8 }
val packed = if (hasBigAlignment) 1 else 0
LLVMStructSetBody(classType, fieldTypes.toCValues(), fieldTypes.size, packed)
return classType
}
private class DeclarationsGeneratorVisitor(override val context: Context) :
IrElementVisitorVoid, ContextUtils {
private class DeclarationsGeneratorVisitor(
override val context: Context,
override val llvmModule: LLVMModuleRef
) : IrElementVisitorVoid, ContextUtils {
val uniques = mutableMapOf<UniqueKind, UniqueLlvmDeclarations>()
@@ -182,7 +184,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
typeInfoGlobal = staticData.createGlobal(typeInfoWithVtableType, typeInfoGlobalName, isExported = false)
val llvmTypeInfoPtr = LLVMAddAlias(context.llvmModule,
val llvmTypeInfoPtr = LLVMAddAlias(llvmModule,
kTypeInfoPtr,
typeInfoGlobal.pointer.getElementPtr(0).llvm,
typeInfoSymbolName)!!
@@ -261,16 +263,21 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val storageKind = irClass.storageKind(context)
val threadLocal = storageKind == ObjectStorageKind.THREAD_LOCAL
val isExported = irClass.isExported()
val symbolName = if (isExported) {
irClass.globalObjectStorageSymbolName
} else {
"kobjref:" + qualifyInternalName(irClass)
}
// val isExported = irClass.isExported()
// val symbolName = if (isExported) {
// irClass.globalObjectStorageSymbolName
// } else {
// "kobjref:" + qualifyInternalName(irClass)
// }
// TODO: Figure out a way to distinguish cross-module and cross-file visibility
val symbolName = irClass.globalObjectStorageSymbolName
val instanceAddress = if (threadLocal) {
addKotlinThreadLocal(symbolName, getLLVMType(irClass.defaultType))
} else {
addKotlinGlobal(symbolName, getLLVMType(irClass.defaultType), isExported)
// This global should be visible from other files in module
addKotlinGlobal(symbolName, getLLVMType(irClass.defaultType), isExported = true).also {
llvm.usedGlobals += it.address
}
}
return SingletonLlvmDeclarations(instanceAddress)
@@ -286,7 +293,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
"kobjcclassinfo:$internalName"
}
val classInfoGlobal = staticData.createGlobal(
context.llvm.runtime.kotlinObjCClassInfo,
llvm.runtime.kotlinObjCClassInfo,
classInfoSymbolName,
isExported = isExported
).apply {
@@ -343,14 +350,14 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
return
}
val llvmFunction = if (declaration.isExternal) {
val llvmFunction = if (declaration.isExternal || !spec.containsDeclaration(declaration)) {
if (declaration.isTypedIntrinsic || declaration.isObjCBridgeBased()
// All call-sites to external accessors to interop properties
// are lowered by InteropLowering.
|| (declaration.isAccessor && declaration.isFromInteropLibrary())
|| declaration.annotations.hasAnnotation(RuntimeNames.cCall)) return
context.llvm.externalFunction(declaration.computeSymbolName(), llvmFunctionType,
llvm.externalFunction(declaration.computeSymbolName(), llvmFunctionType,
// Assume that `external fun` is defined in native libs attached to this module:
origin = declaration.llvmSymbolOrigin,
independent = declaration.hasAnnotation(RuntimeNames.independent)
@@ -359,7 +366,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
val symbolName = if (declaration.isExported()) {
declaration.computeSymbolName().also {
if (declaration.name.asString() != "main") {
assert(LLVMGetNamedFunction(context.llvm.llvmModule, it) == null) { it }
assert(LLVMGetNamedFunction(llvm.llvmModule, it) == null) { it }
} else {
// As a workaround, allow `main` functions to clash because frontend accepts this.
// See [OverloadResolver.isTopLevelMainInDifferentFiles] usage.
@@ -371,7 +378,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
addLlvmFunctionWithDefaultAttributes(
context,
context.llvmModule!!,
llvmModule,
symbolName,
llvmFunctionType
).also {

View File

@@ -252,15 +252,15 @@ internal fun getGlobalType(ptrToGlobal: LLVMValueRef): LLVMTypeRef {
internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): LLVMValueRef {
if (isExported)
assert(LLVMGetNamedGlobal(context.llvmModule, name) == null)
return LLVMAddGlobal(context.llvmModule, type, name)!!
assert(LLVMGetNamedGlobal(llvmModule, name) == null)
return LLVMAddGlobal(llvmModule, type, name)!!
}
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin): LLVMValueRef {
context.llvm.imports.add(origin)
llvm.imports.add(origin)
val found = LLVMGetNamedGlobal(context.llvmModule, name)
val found = LLVMGetNamedGlobal(llvmModule, name)
return if (found != null) {
assert (getGlobalType(found) == type)
assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
@@ -274,34 +274,33 @@ internal abstract class AddressAccess {
abstract fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef
}
internal class GlobalAddressAccess(private val address: LLVMValueRef): AddressAccess() {
internal class GlobalAddressAccess(val address: LLVMValueRef): AddressAccess() {
override fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef = address
}
internal class TLSAddressAccess(
private val context: Context, private val index: Int): AddressAccess() {
private val llvm: Llvm, private val index: Int): AddressAccess() {
override fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef {
return generationContext!!.call(context.llvm.lookupTLS,
listOf(context.llvm.tlsKey, Int32(index).llvm))
return generationContext!!.call(llvm.lookupTLS, listOf(llvm.tlsKey, Int32(index).llvm))
}
}
internal fun ContextUtils.addKotlinThreadLocal(name: String, type: LLVMTypeRef): AddressAccess {
return if (isObjectType(type)) {
val index = context.llvm.tlsCount++
TLSAddressAccess(context, index)
val index = llvm.tlsCount++
TLSAddressAccess(llvm, index)
} else {
// TODO: This will break if Workers get decoupled from host threads.
GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also {
LLVMSetThreadLocalMode(it, context.llvm.tlsMode)
GlobalAddressAccess(LLVMAddGlobal(llvmModule, type, name)!!.also {
LLVMSetThreadLocalMode(it, llvm.tlsMode)
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
})
}
}
internal fun ContextUtils.addKotlinGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): AddressAccess {
return GlobalAddressAccess(LLVMAddGlobal(context.llvmModule, type, name)!!.also {
internal fun ContextUtils.addKotlinGlobal(name: String, type: LLVMTypeRef, isExported: Boolean): GlobalAddressAccess {
return GlobalAddressAccess(LLVMAddGlobal(llvmModule, type, name)!!.also {
if (!isExported)
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
})

View File

@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.FqName
internal class RTTIGenerator(override val context: Context) : ContextUtils {
internal class RTTIGenerator(override val context: Context, override val llvmModule: LLVMModuleRef) : ContextUtils {
private val acyclicCache = mutableMapOf<IrType, Boolean>()
private val safeAcyclicFieldTypes = setOf(
@@ -204,7 +204,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val className = irClass.fqNameForIrSerialization
val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
val llvmDeclarations = llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType
@@ -394,7 +394,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private val debugOperations: ConstValue by lazy {
if (debugRuntimeOrNull != null) {
val external = LLVMGetNamedGlobal(debugRuntimeOrNull, "Konan_debugOperationsList")!!
val local = LLVMAddGlobal(context.llvmModule, LLVMGetElementType(LLVMTypeOf(external)),"Konan_debugOperationsList")!!
val local = LLVMAddGlobal(llvmModule, LLVMGetElementType(LLVMTypeOf(external)),"Konan_debugOperationsList")!!
constPointer(LLVMConstBitCast(local, kInt8PtrPtr)!!)
} else {
Zero(kInt8PtrPtr)
@@ -415,7 +415,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
return NullPointer(runtime.extendedTypeInfoType)
val className = irClass.fqNameForIrSerialization.toString()
val llvmDeclarations = context.llvmDeclarations.forClass(irClass)
val llvmDeclarations = llvmDeclarations.forClass(irClass)
val bodyType = llvmDeclarations.bodyType
val elementType = getElementType(irClass)
@@ -458,7 +458,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
val associatedObjectTableRecords = associatedObjects.map { (key, value) ->
val associatedObjectGetter = generateFunction(
CodeGenerator(context),
CodeGenerator(context, llvmModule),
functionType(kObjHeaderPtr, false, kObjHeaderPtrPtr),
""
) {

View File

@@ -17,22 +17,23 @@ interface RuntimeAware {
class Runtime(bitcodeFile: String) {
val llvmModule: LLVMModuleRef = parseBitcodeFile(bitcodeFile)
val calculatedLLVMTypes: MutableMap<IrType, LLVMTypeRef> = HashMap()
val addedLLVMExternalFunctions: MutableMap<IrFunction, LLVMValueRef> = HashMap()
internal fun getStructTypeOrNull(name: String) = LLVMGetTypeByName(llvmModule, "struct.$name")
internal fun getStructType(name: String) = getStructTypeOrNull(name)
?: throw Error("struct.$name is not found in the Runtime module.")
val typeInfoType = getStructType("TypeInfo")
val extendedTypeInfoType = getStructType("ExtendedTypeInfo")
val writableTypeInfoType = getStructTypeOrNull("WritableTypeInfo")
val interfaceTableRecordType = getStructType("InterfaceTableRecord")
val associatedObjectTableRecordType = getStructType("AssociatedObjectTableRecord")
val typeInfoType by lazy { getStructType("TypeInfo") }
val extendedTypeInfoType by lazy { getStructType("ExtendedTypeInfo") }
val writableTypeInfoType by lazy { getStructTypeOrNull("WritableTypeInfo") }
val interfaceTableRecordType by lazy { getStructType("InterfaceTableRecord") }
val associatedObjectTableRecordType by lazy { getStructType("AssociatedObjectTableRecord") }
val kNodeInitType by lazy { getStructType("InitNode") }
val kMemoryStateType by lazy { getStructType("MemoryState") }
val objHeaderType = getStructType("ObjHeader")
val objHeaderPtrType = pointerType(objHeaderType)
val objHeaderPtrPtrType = pointerType(objHeaderType)
val arrayHeaderType = getStructType("ArrayHeader")
val objHeaderType by lazy { getStructType("ObjHeader") }
val objHeaderPtrType by lazy { pointerType(objHeaderType) }
val objHeaderPtrPtrType by lazy { pointerType(objHeaderType) }
val arrayHeaderType by lazy { getStructType("ArrayHeader") }
val frameOverlayType = getStructType("FrameOverlay")

View File

@@ -12,7 +12,10 @@ import org.jetbrains.kotlin.ir.expressions.IrConst
/**
* Provides utilities to create static data.
*/
internal class StaticData(override val context: Context): ContextUtils {
internal class StaticData(
override val context: Context,
override val llvmModule: LLVMModuleRef,
): ContextUtils {
/**
* Represents the LLVM global variable.
@@ -41,19 +44,19 @@ internal class StaticData(override val context: Context): ContextUtils {
}
fun create(staticData: StaticData, type: LLVMTypeRef, name: String, isExported: Boolean): Global {
val module = staticData.context.llvmModule
val module = staticData.llvmModule
val isUnnamed = (name == "") // LLVM will select the unique index and represent the global as `@idx`.
if (isUnnamed && isExported) {
throw IllegalArgumentException("unnamed global can't be exported")
}
val llvmGlobal = createLlvmGlobal(module!!, type, name, isExported)
val llvmGlobal = createLlvmGlobal(module, type, name, isExported)
return Global(staticData, llvmGlobal)
}
fun get(staticData: StaticData, name: String): Global? {
val llvmGlobal = LLVMGetNamedGlobal(staticData.context.llvmModule, name) ?: return null
val llvmGlobal = LLVMGetNamedGlobal(staticData.llvmModule, name) ?: return null
return Global(staticData, llvmGlobal)
}
}

View File

@@ -27,7 +27,7 @@ internal fun StaticData.placeGlobalConstArray(name: String,
}
internal fun StaticData.createAlias(name: String, aliasee: ConstPointer): ConstPointer {
val alias = LLVMAddAlias(context.llvmModule, aliasee.llvmType, aliasee.llvm, name)!!
val alias = LLVMAddAlias(llvmModule, aliasee.llvmType, aliasee.llvm, name)!!
return constPointer(alias)
}

View File

@@ -120,10 +120,10 @@ internal fun ContextUtils.unique(kind: UniqueKind): ConstPointer {
}
return if (isExternal(descriptor)) {
constPointer(importGlobal(
kind.llvmName, context.llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
kind.llvmName, llvm.runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
))
} else {
context.llvmDeclarations.forUnique(kind).pointer
llvmDeclarations.forUnique(kind).pointer
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2010-2021 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.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.BitcodeFile
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.ObjectFile
import org.jetbrains.kotlin.backend.konan.logMultiple
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.konan.file.File
internal val moduleToLlvm = mutableMapOf<LLVMModuleRef, Llvm>()
internal val moduleToDebugInfo = mutableMapOf<LLVMModuleRef, DebugInfo>()
internal val moduleToLlvmDeclarations = mutableMapOf<LLVMModuleRef, LlvmDeclarations>()
internal val irFileToModule = mutableMapOf<IrFile, LLVMModuleRef>()
internal val irFileToCodegenVisitor = mutableMapOf<IrFile, CodeGeneratorVisitor>()
internal fun programBitcode(): List<LLVMModuleRef> = irFileToModule.values.toList()
// TODO: Class, that accepts rule.
sealed class Spec {
abstract fun containsDeclaration(declaration: IrDeclaration): Boolean
}
internal class RootSpec(private val moduleFiles: List<IrFile>) : Spec() {
override fun containsDeclaration(declaration: IrDeclaration): Boolean {
return declaration.file !in moduleFiles
}
}
internal class FileLlvmModuleSpecification(
val irFile: IrFile,
) : Spec() {
override fun containsDeclaration(declaration: IrDeclaration): Boolean {
if (declaration.isEffectivelyExternal()) return false
return declaration.file == irFile
}
}
// TODO: Module name could be an absolute path, thus some logic may fail
fun stableModuleName(llvmModule: LLVMModuleRef): String = memScoped {
val sizeVar = alloc<size_tVar>()
LLVMGetModuleIdentifier(llvmModule, sizeVar.ptr)?.toKStringFromUtf8()!!.replace('/', '_')
}
internal class SeparateCompilation(val context: Context) {
fun classifyModules(modules: List<LLVMModuleRef>): Pair<List<LLVMModuleRef>, List<ObjectFile>> {
val (reuse, compile) = modules.partition { didNotChange(it) && getObjectFileFor(it) != null }
context.logMultiple {
+"Compiling LLVM modules:"
(compile).forEach {
+stableModuleName(it)
}
}
context.logMultiple {
+"Reusing LLVM modules:"
(reuse).forEach {
+stableModuleName(it)
}
}
return Pair(compile.onEach { storeHash(it) }, reuse.map { getObjectFileFor(it)!!.absolutePath })
}
fun classifyBitcode(files: List<BitcodeFile>): Pair<List<BitcodeFile>, List<ObjectFile>> {
val fileToModule = files.map { it to parseBitcodeFile(it) }
val (reuse, compile) = fileToModule.partition { didNotChange(it.second) && getObjectFileFor(it.second) != null }
val toCompile = compile.onEach { storeHash(it.second) }.map { it.first }
val toLink = reuse.map { getObjectFileFor(it.second)!!.absolutePath }
fileToModule.forEach { LLVMDisposeModule(it.second) }
return Pair(toCompile, toLink)
}
private fun getExistingHash(module: LLVMModuleRef): ByteArray? {
val moduleName = stableModuleName(module)
val file = context.config.tempFiles.lookup("$moduleName.md5")
?: return null
return file.readBytes()
}
private fun computeHash(llvmModule: LLVMModuleRef): ByteArray {
return memScoped {
val hash = allocArray<uint32_tVar>(5)
LLVMKotlinModuleHash(llvmModule, hash)
hash.readBytes(5 * 4)
}
}
private fun storeHash(module: LLVMModuleRef) {
val moduleName = stableModuleName(module)
val hash = computeHash(module)
val file = context.config.tempFiles.create(moduleName, ".md5")
file.writeBytes(hash)
}
private fun didNotChange(llvmModule: LLVMModuleRef): Boolean {
val oldHash = getExistingHash(llvmModule)
?: return true
val newHash = computeHash(llvmModule)
return oldHash.contentEquals(newHash)
}
private fun getObjectFileFor(llvmModule: LLVMModuleRef): File? {
val moduleName = stableModuleName(llvmModule)
return context.config.tempFiles.lookup("$moduleName.bc.o")
}
}

View File

@@ -83,9 +83,9 @@ internal class CoverageManager(val context: Context) {
/**
* @return [LLVMCoverageInstrumentation] instance if [irFunction] should be covered.
*/
fun tryGetInstrumentation(irFunction: IrFunction?, callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit) =
fun tryGetInstrumentation(irFunction: IrFunction?, llvmModule: LLVMModuleRef, callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit) =
if (enabled && irFunction != null) {
getFunctionRegions(irFunction)?.let { LLVMCoverageInstrumentation(context, it, callSitePlacer) }
getFunctionRegions(irFunction)?.let { LLVMCoverageInstrumentation(context, it, callSitePlacer, llvmModule) }
} else {
null
}
@@ -93,9 +93,9 @@ internal class CoverageManager(val context: Context) {
/**
* Add __llvm_coverage_mapping to the LLVM module.
*/
fun writeRegionInfo() {
fun writeRegionInfo(llvmModule: LLVMModuleRef) {
if (enabled) {
LLVMCoverageWriter(context, filesRegionsInfo).write()
LLVMCoverageWriter(context, filesRegionsInfo, llvmModule).write()
}
}

View File

@@ -4,10 +4,7 @@
*/
package org.jetbrains.kotlin.backend.konan.llvm.coverage
import llvm.LLVMConstBitCast
import llvm.LLVMCreatePGOFunctionNameVar
import llvm.LLVMInstrProfIncrement
import llvm.LLVMValueRef
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.ir.IrElement
@@ -20,7 +17,8 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
internal class LLVMCoverageInstrumentation(
override val context: Context,
private val functionRegions: FunctionRegions,
private val callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit
private val callSitePlacer: (function: LLVMValueRef, args: List<LLVMValueRef>) -> Unit,
override val llvmModule: LLVMModuleRef
) : ContextUtils {
private val functionNameGlobal = createFunctionNameGlobal(functionRegions.function)
@@ -41,7 +39,7 @@ internal class LLVMCoverageInstrumentation(
val numberOfRegions = Int32(functionRegions.regions.size).llvm
val regionNumber = Int32(functionRegions.regionEnumeration.getValue(region)).llvm
val args = listOf(functionNameGlobal, functionHash, numberOfRegions, regionNumber)
callSitePlacer(LLVMInstrProfIncrement(context.llvmModule)!!, args)
callSitePlacer(LLVMInstrProfIncrement(llvmModule)!!, args)
}
// Each profiled function should have a global with its name in a specific format.

View File

@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.backend.konan.llvm.coverage
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.llvm.moduleToLlvm
import org.jetbrains.kotlin.backend.konan.llvm.moduleToLlvmDeclarations
import org.jetbrains.kotlin.backend.konan.llvm.name
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.path
@@ -30,18 +32,17 @@ 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 [module].
* See http://llvm.org/docs/CoverageMappingFormat.html for the format description.
*/
internal class LLVMCoverageWriter(
private val context: Context,
private val filesRegionsInfo: List<FileRegionInfo>
private val filesRegionsInfo: List<FileRegionInfo>,
private val module: LLVMModuleRef
) {
fun write() {
if (filesRegionsInfo.isEmpty()) return
val module = context.llvmModule
?: error("LLVM module should be initialized.")
val filesIndex = filesRegionsInfo.mapIndexed { index, fileRegionInfo -> fileRegionInfo.file to index }.toMap()
val coverageGlobal = memScoped {
@@ -54,8 +55,8 @@ internal class LLVMCoverageWriter(
fileIds.toCValues(), fileIds.size.signExtend(),
regions.toCValues(), regions.size.signExtend())
val functionName = context.llvmDeclarations.forFunction(functionRegions.function).llvmFunction.name
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(context.llvmModule),
val functionName = moduleToLlvmDeclarations.getValue(module).forFunction(functionRegions.function).llvmFunction.name
val functionMappingRecord = LLVMAddFunctionMappingRecord(LLVMGetModuleContext(module),
functionName, functionRegions.structuralHash, functionCoverage)!!
Pair(functionMappingRecord, functionCoverage)
@@ -70,6 +71,6 @@ internal class LLVMCoverageWriter(
retval
}
context.llvm.usedGlobals.add(coverageGlobal)
moduleToLlvm.getValue(module).usedGlobals.add(coverageGlobal)
}
}

View File

@@ -22,14 +22,14 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
}
private val objcMsgSend = constPointer(
context.llvm.externalFunction(
codegen.llvm.externalFunction(
"objc_msgSend",
functionType(int8TypePtr, true, int8TypePtr, int8TypePtr),
context.stdlibModule.llvmSymbolOrigin
)
)
val objcRelease = context.llvm.externalFunction(
val objcRelease = codegen.llvm.externalFunction(
"objc_release",
functionType(voidType, false, int8TypePtr),
context.stdlibModule.llvmSymbolOrigin

View File

@@ -18,8 +18,6 @@ import org.jetbrains.kotlin.descriptors.konan.CurrentKlibModuleOrigin
*/
internal class ObjCDataGenerator(val codegen: CodeGenerator) {
val context = codegen.context
fun finishModule() {
addModuleClassList(
definedClasses,
@@ -39,7 +37,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
global.setAlignment(codegen.runtime.pointerAlignment)
global.setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip")
context.llvm.compilerUsedGlobals += global.llvmGlobal
codegen.llvm.compilerUsedGlobals += global.llvmGlobal
global.pointer
}
@@ -52,7 +50,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
it.setAlignment(codegen.runtime.pointerAlignment)
}
context.llvm.compilerUsedGlobals += global.pointer.llvm
codegen.llvm.compilerUsedGlobals += global.pointer.llvm
global.pointer.bitcast(pointerType(int8TypePtr))
}
@@ -60,8 +58,8 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
val classObjectType = codegen.runtime.getStructType("_class_t")
fun exportClass(name: String) {
context.llvm.usedGlobals += getClassGlobal(name, isMetaclass = false).llvm
context.llvm.usedGlobals += getClassGlobal(name, isMetaclass = true).llvm
codegen.llvm.usedGlobals += getClassGlobal(name, isMetaclass = false).llvm
codegen.llvm.usedGlobals += getClassGlobal(name, isMetaclass = true).llvm
}
private fun getClassGlobal(name: String, isMetaclass: Boolean): ConstPointer {
@@ -74,7 +72,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
val globalName = prefix + name
// TODO: refactor usages and use [Global] class.
val llvmGlobal = LLVMGetNamedGlobal(context.llvmModule, globalName) ?:
val llvmGlobal = LLVMGetNamedGlobal(codegen.llvmModule, globalName) ?:
codegen.importGlobal(globalName, classObjectType, CurrentKlibModuleOrigin)
return constPointer(llvmGlobal)
@@ -95,7 +93,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
class Method(val selector: String, val encoding: String, val imp: ConstPointer)
fun emitClass(name: String, superName: String, instanceMethods: List<Method>) {
val runtime = context.llvm.runtime
val runtime = codegen.llvm.runtime
fun struct(name: String) = runtime.getStructType(name)
val classRoType = struct("_class_ro_t")
@@ -121,13 +119,13 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
)
val globalName = "\u0001l_OBJC_\$_INSTANCE_METHODS_$name"
val global = context.llvm.staticData.placeGlobal(globalName, methodList).also {
val global = codegen.llvm.staticData.placeGlobal(globalName, methodList).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const")
}
context.llvm.compilerUsedGlobals += global.llvmGlobal
codegen.llvm.compilerUsedGlobals += global.llvmGlobal
return global.pointer.bitcast(pointerType(methodListType))
}
@@ -170,7 +168,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
"\u0001l_OBJC_CLASS_RO_\$_"
} + name
val roGlobal = context.llvm.staticData.placeGlobal(roLabel, roValue).also {
val roGlobal = codegen.llvm.staticData.placeGlobal(roLabel, roValue).also {
it.setLinkage(LLVMLinkage.LLVMPrivateLinkage)
it.setAlignment(runtime.pointerAlignment)
it.setSection("__DATA, __objc_const")
@@ -201,7 +199,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
LLVMSetSection(classGlobal.llvm, "__DATA, __objc_data")
LLVMSetAlignment(classGlobal.llvm, LLVMABIAlignmentOfType(runtime.targetData, classObjectType))
context.llvm.usedGlobals.add(classGlobal.llvm)
codegen.llvm.usedGlobals.add(classGlobal.llvm)
return classGlobal
}
@@ -228,7 +226,7 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private fun addModuleClassList(elements: List<ConstPointer>, name: String, section: String) {
if (elements.isEmpty()) return
val global = context.llvm.staticData.placeGlobalArray(
val global = codegen.llvm.staticData.placeGlobalArray(
name,
int8TypePtr,
elements.map { it.bitcast(int8TypePtr) }
@@ -236,14 +234,14 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
global.setAlignment(
LLVMABIAlignmentOfType(
context.llvm.runtime.targetData,
codegen.llvm.runtime.targetData,
LLVMGetInitializer(global.llvmGlobal)!!.type
)
)
global.setSection(section)
context.llvm.compilerUsedGlobals += global.llvmGlobal
codegen.llvm.compilerUsedGlobals += global.llvmGlobal
}
private val classNames = CStringLiteralsTable(classNameGenerator)
@@ -257,8 +255,8 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
private val literals = mutableMapOf<String, ConstPointer>()
fun get(value: String) = literals.getOrPut(value) {
val globalPointer = generator.generate(context.llvmModule!!, value)
context.llvm.compilerUsedGlobals += globalPointer.llvm
val globalPointer = generator.generate(codegen.llvmModule, value)
codegen.llvm.compilerUsedGlobals += globalPointer.llvm
globalPointer.getElementPtr(0)
}
}

View File

@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.objcexport.NSNumberKind
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExportNamer
internal fun linkObjC(context: Context) {
internal fun linkObjC(context: Context, target: LLVMModuleRef) {
val config = context.config
if (!(config.produce.isFinalBinary && config.target.family.isAppleFamily)) return
@@ -25,7 +25,7 @@ internal fun linkObjC(context: Context) {
patchBuilder.buildAndApply(parsedModule)
val failed = llvmLinkModules2(context, context.llvmModule!!, parsedModule)
val failed = llvmLinkModules2(context, target, parsedModule)
if (failed != 0) {
throw Error("failed to link $bitcodeFile")
}

View File

@@ -47,7 +47,7 @@ internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
thisRef
}
val blockPtr = callFromBridge(
context.llvm.Kotlin_ObjCExport_GetAssociatedObject,
codegen.llvm.Kotlin_ObjCExport_GetAssociatedObject,
listOf(associatedObjectHolder)
)
@@ -118,7 +118,7 @@ private fun FunctionGenerationContext.allocInstanceWithAssociatedObject(
associatedObject: LLVMValueRef,
resultLifetime: Lifetime
): LLVMValueRef = call(
context.llvm.Kotlin_ObjCExport_AllocInstanceWithAssociatedObject,
codegen.llvm.Kotlin_ObjCExport_AllocInstanceWithAssociatedObject,
listOf(typeInfo.llvm, associatedObject),
resultLifetime
)
@@ -159,7 +159,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
) {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
val refHolder = structGep(blockPtr, 1)
call(context.llvm.kRefSharedHolderDispose, listOf(refHolder))
call(codegen.llvm.kRefSharedHolderDispose, listOf(refHolder))
ret(null)
}.also {
@@ -181,20 +181,20 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
// so it is technically not necessary to check owner.
// However this is not guaranteed by Objective-C runtime, so keep it suboptimal but reliable:
val ref = call(
context.llvm.kRefSharedHolderRef,
codegen.llvm.kRefSharedHolderRef,
listOf(srcRefHolder),
exceptionHandler = ExceptionHandler.Caller,
verbatim = true
)
call(context.llvm.kRefSharedHolderInit, listOf(dstRefHolder, ref))
call(codegen.llvm.kRefSharedHolderInit, listOf(dstRefHolder, ref))
ret(null)
}.also {
LLVMSetLinkage(it, LLVMLinkage.LLVMInternalLinkage)
}
fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) =
fun CodeGenerator.LongInt(value: Long) =
when (val longWidth = llvm.longTypeWidth) {
32L -> Int32(value.toInt())
64L -> Int64(value)
@@ -220,8 +220,8 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
}
return Struct(blockDescriptorType,
codegen.context.LongInt(0L),
codegen.context.LongInt(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)),
codegen.LongInt(0L),
codegen.LongInt(LLVMStoreSizeOfType(codegen.runtime.targetData, blockLiteralType)),
constPointer(copyHelper),
constPointer(disposeHelper),
codegen.staticData.cStringLiteral(signature),
@@ -238,7 +238,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
val result = generateFunction(codegen, blockType.blockInvokeLlvmType, invokeName, switchToRunnable = true) {
val blockPtr = bitcast(pointerType(blockLiteralType), param(0))
val kotlinObject = call(
context.llvm.kRefSharedHolderRef,
codegen.llvm.kRefSharedHolderRef,
listOf(structGep(blockPtr, 1)),
exceptionHandler = ExceptionHandler.Caller,
verbatim = true
@@ -325,11 +325,11 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
store(value, structGep(blockOnStackBase, index))
}
call(context.llvm.kRefSharedHolderInitLocal, listOf(refHolder, kotlinRef))
call(codegen.llvm.kRefSharedHolderInitLocal, listOf(refHolder, kotlinRef))
val copiedBlock = callFromBridge(retainBlock, listOf(bitcast(int8TypePtr, blockOnStack)))
val autoreleaseReturnValue = context.llvm.externalFunction(
val autoreleaseReturnValue = codegen.llvm.externalFunction(
"objc_autoreleaseReturnValue",
functionType(int8TypePtr, false, int8TypePtr),
CurrentKlibModuleOrigin
@@ -342,7 +342,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
}
}
private val ObjCExportCodeGeneratorBase.retainBlock get() = context.llvm.externalFunction(
private val ObjCExportCodeGeneratorBase.retainBlock get() = codegen.llvm.externalFunction(
"objc_retainBlock",
functionType(int8TypePtr, false, int8TypePtr),
CurrentKlibModuleOrigin

View File

@@ -52,10 +52,10 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
val runtime get() = codegen.runtime
val staticData get() = codegen.staticData
val rttiGenerator = RTTIGenerator(context)
val rttiGenerator = RTTIGenerator(context, codegen.llvmModule)
private val objcTerminate: LLVMValueRef by lazy {
context.llvm.externalFunction(
codegen.llvm.externalFunction(
"objc_terminate",
functionType(voidType, false),
CurrentKlibModuleOrigin
@@ -103,10 +103,10 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
}
fun FunctionGenerationContext.kotlinReferenceToObjC(value: LLVMValueRef) =
callFromBridge(context.llvm.Kotlin_ObjCExport_refToObjC, listOf(value))
callFromBridge(codegen.llvm.Kotlin_ObjCExport_refToObjC, listOf(value))
fun FunctionGenerationContext.objCReferenceToKotlin(value: LLVMValueRef, resultLifetime: Lifetime) =
callFromBridge(context.llvm.Kotlin_ObjCExport_refFromObjC, listOf(value), resultLifetime)
callFromBridge(codegen.llvm.Kotlin_ObjCExport_refFromObjC, listOf(value), resultLifetime)
private val blockToKotlinFunctionConverterCache = mutableMapOf<BlockPointerBridge, LLVMValueRef>()
@@ -388,7 +388,7 @@ internal class ObjCExportCodeGenerator(
LLVMSetLinkage(initializer, LLVMLinkage.LLVMInternalLinkage)
context.llvm.otherStaticInitializers += initializer
codegen.llvm.otherStaticInitializers += initializer
}
private fun emitKt42254Hint() {
@@ -403,7 +403,7 @@ internal class ObjCExportCodeGenerator(
val name = "See https://youtrack.jetbrains.com/issue/KT-42254"
val global = staticData.placeGlobal(name, Int8(0), isExported = true)
context.llvm.usedGlobals += global.llvmGlobal
codegen.llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
}
}
@@ -549,7 +549,7 @@ private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(
if (context.llvmModuleSpecification.importsKotlinDeclarationsFromOtherObjectFiles()) {
// Note: actually this is required only if global's weak/common definition is in another object file,
// but it is simpler to do this for all globals, considering that all usages can't be removed by DCE anyway.
context.llvm.usedGlobals += global.llvmGlobal
codegen.llvm.usedGlobals += global.llvmGlobal
LLVMSetVisibility(global.llvmGlobal, LLVMVisibility.LLVMHiddenVisibility)
// See also [emitKt42254Hint].
@@ -582,8 +582,8 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
}
private fun ObjCExportCodeGeneratorBase.setOwnWritableTypeInfo(irClass: IrClass, writableTypeInfoValue: Struct) {
require(!codegen.isExternal(irClass))
val writeableTypeInfoGlobal = context.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!
// require(!codegen.isExternal(irClass))
val writeableTypeInfoGlobal = codegen.llvmDeclarations.forClass(irClass).writableTypeInfoGlobal!!
writeableTypeInfoGlobal.setLinkage(LLVMLinkage.LLVMExternalLinkage)
writeableTypeInfoGlobal.setInitializer(writableTypeInfoValue)
}
@@ -665,7 +665,7 @@ private fun ObjCExportCodeGenerator.generateContinuationToCompletionConverter(
invokeName = "invokeCompletion"
) { continuation, arguments ->
check(arguments.size == 2)
callFromBridge(context.llvm.Kotlin_ObjCExport_resumeContinuation, listOf(continuation) + arguments)
callFromBridge(codegen.llvm.Kotlin_ObjCExport_resumeContinuation, listOf(continuation) + arguments)
ret(null)
}
}
@@ -713,7 +713,7 @@ private fun ObjCExportBlockCodeGenerator.emitBlockToKotlinFunctionConverters() {
private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
setObjCExportTypeInfo(
symbols.string.owner,
constPointer(context.llvm.Kotlin_ObjCExport_CreateNSStringFromKString)
constPointer(codegen.llvm.Kotlin_ObjCExport_CreateNSStringFromKString)
)
emitCollectionConverters()
@@ -723,7 +723,7 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
private fun ObjCExportCodeGenerator.emitCollectionConverters() {
fun importConverter(name: String): ConstPointer = constPointer(context.llvm.externalFunction(
fun importConverter(name: String): ConstPointer = constPointer(codegen.llvm.externalFunction(
name,
kotlinToObjCFunctionType,
CurrentKlibModuleOrigin
@@ -767,13 +767,13 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
): LLVMValueRef {
val result = addLlvmFunctionWithDefaultAttributes(
context,
context.llvmModule!!,
codegen.llvmModule,
"objc2kotlin",
objCFunctionType(context, methodBridge)
)
val location = if (debugInfo) {
setupBridgeDebugInfo(context, result)
val location = if (debugInfo && false) {
setupBridgeDebugInfo(context, codegen.debugInfo, result)
} else {
null
}
@@ -789,7 +789,7 @@ private inline fun ObjCExportCodeGenerator.generateObjCImpBy(
private fun ObjCExportCodeGenerator.generateAbstractObjCImp(methodBridge: MethodBridge): LLVMValueRef =
generateObjCImpBy(methodBridge) {
callFromBridge(
context.llvm.Kotlin_ObjCExport_AbstractMethodCalled,
codegen.llvm.Kotlin_ObjCExport_AbstractMethodCalled,
listOf(param(0), param(1))
)
unreachable()
@@ -864,7 +864,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
MethodBridgeValueParameter.SuspendCompletion -> {
callFromBridge(
context.llvm.Kotlin_ObjCExport_createContinuationArgument,
codegen.llvm.Kotlin_ObjCExport_createContinuationArgument,
listOf(parameter, generateExceptionTypeInfoArray(baseMethod!!)),
Lifetime.ARGUMENT
).also {
@@ -878,7 +878,7 @@ private fun ObjCExportCodeGenerator.generateObjCImp(
val exceptionHandler = when {
errorOutPtr != null -> kotlinExceptionHandler { exception ->
callFromBridge(
context.llvm.Kotlin_ObjCExport_RethrowExceptionAsNSError,
codegen.llvm.Kotlin_ObjCExport_RethrowExceptionAsNSError,
listOf(exception, errorOutPtr!!, generateExceptionTypeInfoArray(baseMethod!!))
)
@@ -995,7 +995,7 @@ private fun ObjCExportCodeGenerator.generateObjCImpForArrayConstructor(
methodBridge: MethodBridge
): LLVMValueRef = generateObjCImp(methodBridge, isDirect = true) { args, resultLifetime, exceptionHandler ->
val arrayInstance = callFromBridge(
context.llvm.allocArrayFunction,
codegen.llvm.allocArrayFunction,
listOf(target.constructedClass.llvmTypeInfoPtr, args.first()),
resultLifetime = Lifetime.ARGUMENT
)
@@ -1076,7 +1076,7 @@ private fun ObjCExportCodeGenerator.generateKotlinToObjCBridge(
fun rethrow() {
val error = load(errorOutPtr!!)
callFromBridge(context.llvm.Kotlin_ObjCExport_RethrowNSErrorAsException, listOf(error))
callFromBridge(codegen.llvm.Kotlin_ObjCExport_RethrowNSErrorAsException, listOf(error))
unreachable()
}
@@ -1550,7 +1550,7 @@ private fun ObjCExportCodeGenerator.createUnitInstanceAdapter(selector: String)
// Note: generateObjCToKotlinSyntheticGetter switches to Runnable, which is probably not required here and thus suboptimal.
initRuntimeIfNeeded() // For instance methods it gets called when allocating.
ret(callFromBridge(context.llvm.Kotlin_ObjCExport_convertUnit, listOf(codegen.theUnitInstanceRef.llvm)))
ret(callFromBridge(codegen.llvm.Kotlin_ObjCExport_convertUnit, listOf(codegen.theUnitInstanceRef.llvm)))
}
private fun ObjCExportCodeGenerator.createObjectInstanceAdapter(
@@ -1603,7 +1603,7 @@ private fun ObjCExportCodeGenerator.createThrowableAsErrorAdapter(): ObjCExportC
val imp = generateObjCImpBy(methodBridge) {
val exception = objCReferenceToKotlin(param(0), Lifetime.ARGUMENT)
ret(callFromBridge(context.llvm.Kotlin_ObjCExport_WrapExceptionToNSError, listOf(exception)))
ret(callFromBridge(codegen.llvm.Kotlin_ObjCExport_WrapExceptionToNSError, listOf(exception)))
}
val selector = ObjCExportNamer.kotlinThrowableAsErrorMethodName

View File

@@ -2,7 +2,6 @@ package org.jetbrains.kotlin.backend.konan.serialization
import org.jetbrains.kotlin.backend.common.serialization.CompatibilityMode
import org.jetbrains.kotlin.backend.common.serialization.IrModuleSerializer
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrBuiltIns
@@ -27,7 +26,7 @@ class KonanIrModuleSerializer(
// We may switch from IR generation to LazyIR later (at least for structs; enums are tricky)
// without changing kotlin libraries that depend on interop libraries.
override fun backendSpecificFileFilter(file: IrFile): Boolean =
file.fileEntry.name != IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileName
!file.fileEntry.name.startsWith(IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileNamePrefix)
override fun createSerializerForFile(file: IrFile): KonanIrFileSerializer =
KonanIrFileSerializer(messageLogger, KonanDeclarationTable(globalDeclarationTable), expectDescriptorToSymbol, skipExpects = skipExpects, compatibilityMode = compatibilityMode)

View File

@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.descriptors.konan.klibModuleOrigin
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.types.IrTypeSystemContextImpl
@@ -141,16 +140,15 @@ internal class KonanIrLinker(
private fun DeclarationDescriptor.isCEnumsOrCStruct(): Boolean = cenumsProvider.isCEnumOrCStruct(this)
private val fileMap = mutableMapOf<PackageFragmentDescriptor, IrFile>()
private val fileMap = mutableMapOf<FqName, IrFile>()
private fun getIrFile(packageFragment: PackageFragmentDescriptor): IrFile = fileMap.getOrPut(packageFragment) {
IrFileImpl(NaiveSourceBasedFileEntryImpl(IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileName), packageFragment).also {
moduleFragment.files.add(it)
}
private fun getIrFile(fqName: FqName): IrFile = fileMap.getOrPut(fqName) {
val fileName = "${IrProviderForCEnumAndCStructStubs.cTypeDefinitionsFileNamePrefix}_${fqName.asString().replace('.', '_')}"
moduleFragment.addFile(NaiveSourceBasedFileEntryImpl(fileName), fqName)
}
private fun resolveCEnumsOrStruct(descriptor: DeclarationDescriptor, idSig: IdSignature, symbolKind: BinarySymbolData.SymbolKind): IrSymbol {
val file = getIrFile(descriptor.findPackage())
val file = getIrFile(descriptor.findPackage().fqName)
return cenumsProvider.getDeclaration(descriptor, idSig, file, symbolKind).symbol
}

View File

@@ -5,6 +5,7 @@ import org.gradle.api.Task
import org.gradle.api.tasks.Exec
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.util.visibleName
import org.jetbrains.kotlin.konan.target.HostManager
class CacheTesting(val buildCacheTask: Task, val compilerArgs: List<String>, val isDynamic: Boolean)
@@ -36,9 +37,13 @@ fun configureCacheTesting(project: Project): CacheTesting? {
}
dependsOnDist()
val konanc = if (HostManager.hostIsMingw) {
"$dist/bin/konanc.bat"
} else {
"$dist/bin/konanc"
}
commandLine(
"$dist/bin/konanc",
konanc,
"-p", cacheKind.visibleName,
"-o", "$cacheDir/stdlib-cache",
"-Xmake-cache=$stdlib",

View File

@@ -511,7 +511,7 @@ open class KonanDynamicTest : KonanStandaloneTest() {
// rpath is meaningless on Windows (and isn't supported by LLD).
// --allow-multiple-definition is needed because finalLinkCommands statically links a lot of MinGW-specific libraries,
// that are already included in DLL produced by Kotlin/Native.
Family.MINGW -> listOf("-L", artifactsDir, "-Wl,--allow-multiple-definition")
Family.MINGW -> listOf("-L", artifactsDir, "--allow-multiple-definition")
else -> listOf("-L", artifactsDir, "-rpath", artifactsDir)
}
val commands = linker.finalLinkCommands(

View File

@@ -74,15 +74,13 @@ llvmVersion.mingw_x64 = 11.1.0
llvmVersion.macos_x64 = 11.1.0
llvmVersion.macos_arm64 = 11.1.0
cacheableTargets.macos_x64 = \
macos_x64 \
ios_x64 \
ios_arm64
cacheableTargets.macos_x64 =
cacheableTargets.linux_x64 = \
linux_x64
cacheableTargets.mingw_x64 =
cacheableTargets.mingw_x64 = \
mingw_x64
cacheableTargets.macos_arm64 = \
macos_arm64 \
@@ -879,7 +877,7 @@ targetToolchain.mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.
libffiDir.mingw_x64 = libffi-3.3-windows-x64-1
windowsKitParts.mingw_x64 = windows-kit-x64-v1-alpha2
msvcParts.mingw_x64 = msvc-x64-v1-alpha2
lldLocation.mingw_x64 = lld-12.0.1-windows-x64/ld.lld.exe
linker.mingw_x64 = lld-12.0.1-windows-x64/ld.lld.exe
windows-kit-x64-v1-alpha2.default = \
remote:internal
@@ -903,21 +901,26 @@ targetCpuFeatures.mingw_x64 = +cx8,+fxsr,+mmx,+sse,+sse2,+x87
# See https://youtrack.jetbrains.com/issue/KT-27654.
# TODO: remove, once fixed in mingw, check with the bug testcase.
clangFlags.mingw_x64 = -cc1 -emit-obj -disable-llvm-passes -x ir -femulated-tls -target-cpu $targetCpu.mingw_x64
clangOptFlags.mingw_x64 = -O3 -ffunction-sections
clangOptFlags.mingw_x64 = -O3 -ffunction-sections -fdata-sections
clangNooptFlags.mingw_x64 = -O1
linkerNoDebugFlags.mingw_x64 = -Wl,-S
linkerNoDebugFlags.mingw_x64 = -S
linkerDynamicFlags.mingw_x64 = -shared
linkerKonanFlags.mingw_x64 =-static-libgcc -static-libstdc++ \
-Wl,--dynamicbase \
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic
linkerOptimizationFlags.mingw_x64 = -Wl,--gc-sections
crtFilesLocation.mingw_x64 = $targetSysRoot.mingw_x64/x86_64-w64-mingw32/lib
# sysroot-relative.
defaultLinkDirectories.mingw_x64 = lib x86_64-w64-mingw32/lib lib/gcc/x86_64-w64-mingw32/9.2.0
linkerKonanFlags.mingw_x64 = \
--dynamicbase --gc-sections \
-Bstatic --whole-archive -lwinpthread --no-whole-archive \
-Bstatic -lstdc++ \
-Bdynamic -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32
linkerOptimizationFlags.mingw_x64 =
mimallocLinkerDependencies.mingw_x64 = -lbcrypt
runtimeDefinitions.mingw_x64 = USE_GCC_UNWIND=1 USE_PE_COFF_SYMBOLS=1 KONAN_WINDOWS=1 \
UNICODE KONAN_X64=1 KONAN_NO_MEMMEM=1
# Windows i686, based on mingw-w64.
targetToolchain.mingw_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1
lldLocation.mingw_x86 = lld-12.0.1-windows-x64/ld.lld.exe
linker.mingw_x86 = lld-12.0.1-windows-x64/ld.lld.exe
dependencies.mingw_x64-mingw_x86 = \
msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 \
lld-12.0.1-windows-x64
@@ -941,13 +944,18 @@ targetCpu.mingw_x86 = pentium4
clangFlags.mingw_x86 = -cc1 -emit-obj -disable-llvm-passes -x ir -femulated-tls -target-cpu $targetCpu.mingw_x86
clangOptFlags.mingw_x86 = -O3 -ffunction-sections
clangNooptFlags.mingw_x86 = -O1
linkerNoDebugFlags.mingw_x86 = -Wl,-S
linkerNoDebugFlags.mingw_x86 = -S
linkerDynamicFlags.mingw_x86 = -shared
linkerKonanFlags.mingw_x86 = -static-libgcc -static-libstdc++ \
-Wl,--dynamicbase \
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic
crtFilesLocation.mingw_x86 = $targetSysRoot.mingw_x64/i686-w64-mingw32/lib
# sysroot-relative.
defaultLinkDirectories.mingw_x86 = lib i686-w64-mingw32/lib lib/gcc/i686-w64-mingw32/9.2.0
linkerKonanFlags.mingw_x86 = \
--dynamicbase \
-Bstatic --whole-archive -lwinpthread --no-whole-archive \
-Bstatic -lstdc++ \
-Bdynamic -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32
mimallocLinkerDependencies.mingw_x86 = -lbcrypt
linkerOptimizationFlags.mingw_x86 = -Wl,--gc-sections
linkerOptimizationFlags.mingw_x86 = --gc-sections
runtimeDefinitions.mingw_x86 = USE_GCC_UNWIND=1 USE_PE_COFF_SYMBOLS=1 KONAN_WINDOWS=1 \
UNICODE KONAN_X86=1 KONAN_NO_MEMMEM=1

View File

@@ -21,6 +21,7 @@
#include <llvm/Transforms/Instrumentation.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
#include <llvm/Bitcode/BitcodeWriter.h>
#include <utility>
#include <string>
#include <vector>
@@ -230,6 +231,18 @@ void LLVMKotlinAddTargetLibraryInfoWrapperPass(LLVMPassManagerRef passManagerRef
passManager->add(new TargetLibraryInfoWrapperPass(Triple(targetTriple)));
}
void LLVMKotlinModuleHash(LLVMModuleRef moduleRef, uint32_t hashResult[5]) {
SmallVector<char, 0> Buffer;
Buffer.reserve(256*1024);
BitcodeWriter bitcodeWriter(Buffer);
Module &module = *unwrap(moduleRef);
ModuleHash moduleHash;
bitcodeWriter.writeModule(module, false, nullptr, true, &moduleHash);
for (int i = 0; i < 5; ++i) {
hashResult[i] = moduleHash[i];
}
}
void LLVMKotlinInitializeTargets() {
#define INIT_LLVM_TARGET(TargetName) \
LLVMInitialize##TargetName##TargetInfo();\

View File

@@ -76,6 +76,8 @@ void LLVMKotlinAddTargetLibraryInfoWrapperPass(LLVMPassManagerRef passManagerRef
void LLVMKotlinInitializeTargets();
void LLVMKotlinModuleHash(LLVMModuleRef, uint32_t hashResult[5]);
# ifdef __cplusplus
}
# endif

View File

@@ -59,8 +59,8 @@ internal fun interceptedContinuation(continuation: Continuation<Any?>): Continua
@FilterExceptions
@SymbolName("Kotlin_ObjCExport_runCompletionSuccess")
private external fun runCompletionSuccess(completionHolder: Any, result: Any?)
private fun runCompletionSuccess(completionHolder: Any, result: Any?) {}
@FilterExceptions
@SymbolName("Kotlin_ObjCExport_runCompletionFailure")
private external fun runCompletionFailure(completionHolder: Any, exception: Throwable, exceptionTypes: NativePtr)
private fun runCompletionFailure(completionHolder: Any, exception: Throwable, exceptionTypes: NativePtr) {}

View File

@@ -58,5 +58,8 @@ class TempFiles(outputPath: String, pathToTemporaryDir: String? = null) {
File(dir, "$prefix$suffix").also {
if (deleteOnExit) it.deleteOnExit()
}
fun lookup(name: String): File? =
if (File(dir, name).exists) File(dir, name) else null
}

View File

@@ -105,14 +105,18 @@ interface AppleConfigurables : Configurables, ClangFlags {
}
interface MingwConfigurables : Configurables, ClangFlags {
val lldLocation get() = targetString("lldLocation")!!
val absoluteLldLocation get() = absolute(lldLocation)
val linker get() = targetString("linker")!!
val absoluteLinker get() = absolute(linker)
val windowsKit: WindowsKit
val msvc: Msvc
val windowsKitParts get() = hostString("windowsKitParts")!!
val msvcParts get() = hostString("msvcParts")!!
val crtFilesLocation get() = targetString("crtFilesLocation")!!
val absoluteCrtFilesLocation get() = absolute(crtFilesLocation)
val defaultLinkDirectories get() = targetList("defaultLinkDirectories")
}
interface GccConfigurables : Configurables, ClangFlags {

View File

@@ -372,7 +372,8 @@ class GccBasedLinker(targetProperties: GccConfigurables)
// TODO: Can we extract more to the konan.configurables?
return listOf(Command(absoluteLinker).apply {
+"--sysroot=${absoluteTargetSysRoot}"
+"-export-dynamic"
// TODO: Do we need it in other cases?
if (dynamic) +"-export-dynamic"
+"-z"
+"relro"
+"--build-id"
@@ -422,10 +423,9 @@ class GccBasedLinker(targetProperties: GccConfigurables)
class MingwLinker(targetProperties: MingwConfigurables)
: LinkerFlags(targetProperties), MingwConfigurables by targetProperties {
private val ar = "$absoluteTargetToolchain/bin/ar"
private val linker = "$absoluteLlvmHome/bin/clang++"
private val ar = "$absoluteLlvmHome/bin/llvm-ar"
override val useCompilerDriverAsLinker: Boolean get() = true
override val useCompilerDriverAsLinker: Boolean get() = false
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isWindowsStaticLib || it.isUnixStaticLib }
@@ -455,14 +455,29 @@ class MingwLinker(targetProperties: MingwConfigurables)
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
val mode = if (target.architecture == Architecture.X64) {
"i386pep"
} else {
"i386pe"
}
val crt2 = if (dynamic) "$absoluteCrtFilesLocation/dllcrt2.o" else "$absoluteCrtFilesLocation/crt2.o"
val crtbegin = "$absoluteCrtFilesLocation/crtbegin.o"
val crtend = "$absoluteCrtFilesLocation/crtend.o"
val defaultLinkDirectories = defaultLinkDirectories.map { "-L$absoluteTargetSysRoot/$it" }
fun Command.constructLinkerArguments(
additionalArguments: List<String> = listOf(),
skipDefaultArguments: List<String> = listOf()
): Command = apply {
+listOf("--sysroot", absoluteTargetSysRoot)
+listOf("-target", targetTriple.toString())
+listOf("--sysroot=$absoluteTargetSysRoot")
+listOf("-m", mode)
if (dynamic) +listOf("-e", "DllMainCRTStartup", "--enable-auto-image-base")
+listOf("-o", executable)
+listOf(crt2, crtbegin)
+objectFiles
+defaultLinkDirectories
// --gc-sections flag may affect profiling.
// See https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#drawbacks-and-limitations.
// TODO: switching to lld may help.
@@ -475,14 +490,10 @@ class MingwLinker(targetProperties: MingwConfigurables)
+linkerKonanFlags.filterNot { it in skipDefaultArguments }
if (mimallocEnabled) +mimallocLinkerDependencies
+additionalArguments
+listOf(crtend)
}
return listOf(when {
HostManager.hostIsMingw -> Command(linker)
else -> Command("wine64", "$linker.exe")
}.constructLinkerArguments(
additionalArguments = listOf("-fuse-ld=$absoluteLldLocation")
))
return listOf(Command(absoluteLinker).constructLinkerArguments())
}
}

View File

@@ -44,8 +44,7 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String>? {
val cinteropArgsToCompiler = interop(flavor, args,
InternalInteropOptions(generatedDir.absolutePath,
nativesDir.absolutePath,manifest.path,
cstubsName.takeIf { flavor == "native" }
nativesDir.absolutePath,manifest.path
)
) ?: return null // There is no need in compiler invocation if we're generating only metadata.