mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-23 15:51:59 +00:00
Compare commits
10 Commits
master
...
ssb/separa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7fd140329 | ||
|
|
4bfa5ad532 | ||
|
|
b694fcdac6 | ||
|
|
b991d3cd4c | ||
|
|
f95c1a0996 | ||
|
|
216e306e58 | ||
|
|
1b6ff4d8bd | ||
|
|
65358742dd | ||
|
|
e05c139668 | ||
|
|
d7283d2983 |
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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}!")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 })
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 -> {}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -118,6 +118,8 @@ internal class IrProviderForCEnumAndCStructStubs(
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val cTypeDefinitionsFileName = "CTypeDefinitions"
|
||||
val cTypeDefinitionsFileNamePrefix: String by lazy {
|
||||
"CTypeDefinitions_"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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),
|
||||
""
|
||||
) {
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();\
|
||||
|
||||
@@ -76,6 +76,8 @@ void LLVMKotlinAddTargetLibraryInfoWrapperPass(LLVMPassManagerRef passManagerRef
|
||||
|
||||
void LLVMKotlinInitializeTargets();
|
||||
|
||||
void LLVMKotlinModuleHash(LLVMModuleRef, uint32_t hashResult[5]);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -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) {}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user