[K/N][IR][codegen] Build per-file dependencies for caches
This commit is contained in:
+12
@@ -35,3 +35,15 @@ val ModuleDescriptor.klibModuleOrigin get() = this.getCapability(KlibModuleOrigi
|
|||||||
val ModuleDescriptor.kotlinLibrary get() =
|
val ModuleDescriptor.kotlinLibrary get() =
|
||||||
(this.klibModuleOrigin as DeserializedKlibModuleOrigin)
|
(this.klibModuleOrigin as DeserializedKlibModuleOrigin)
|
||||||
.library
|
.library
|
||||||
|
|
||||||
|
sealed class CompiledKlibFileOrigin {
|
||||||
|
object CurrentFile : CompiledKlibFileOrigin() // No dependency should be added.
|
||||||
|
|
||||||
|
object StdlibRuntime : CompiledKlibFileOrigin()
|
||||||
|
|
||||||
|
object StdlibKFunctionImpl : CompiledKlibFileOrigin()
|
||||||
|
|
||||||
|
class EntireModule(val library: KotlinLibrary) : CompiledKlibFileOrigin()
|
||||||
|
|
||||||
|
class CertainFile(val library: KotlinLibrary, val fqName: String, val filePath: String) : CompiledKlibFileOrigin()
|
||||||
|
}
|
||||||
+2
@@ -69,6 +69,7 @@ internal fun Context.getBoxFunction(inlinedClass: IrClass): IrSimpleFunction = m
|
|||||||
returnType = boxedType
|
returnType = boxedType
|
||||||
}.also { function ->
|
}.also { function ->
|
||||||
function.parent = parent
|
function.parent = parent
|
||||||
|
function.attributeOwnerId = inlinedClass // To be able to get the file.
|
||||||
|
|
||||||
function.addValueParameter {
|
function.addValueParameter {
|
||||||
startOffset = inlinedClass.startOffset
|
startOffset = inlinedClass.startOffset
|
||||||
@@ -103,6 +104,7 @@ internal fun Context.getUnboxFunction(inlinedClass: IrClass): IrSimpleFunction =
|
|||||||
returnType = unboxedType
|
returnType = unboxedType
|
||||||
}.also { function ->
|
}.also { function ->
|
||||||
function.parent = parent
|
function.parent = parent
|
||||||
|
function.attributeOwnerId = inlinedClass // To be able to get the file.
|
||||||
|
|
||||||
function.addValueParameter {
|
function.addValueParameter {
|
||||||
startOffset = inlinedClass.startOffset
|
startOffset = inlinedClass.startOffset
|
||||||
|
|||||||
+2
-2
@@ -125,7 +125,7 @@ class CacheSupport(
|
|||||||
val libraryToAddToCacheFile = File(it)
|
val libraryToAddToCacheFile = File(it)
|
||||||
val libraryToAddToCache = getLibrary(libraryToAddToCacheFile)
|
val libraryToAddToCache = getLibrary(libraryToAddToCacheFile)
|
||||||
val libraryCache = cachedLibraries.getLibraryCache(libraryToAddToCache)
|
val libraryCache = cachedLibraries.getLibraryCache(libraryToAddToCache)
|
||||||
if (libraryCache != null && libraryCache.granularity == CachedLibraries.Granularity.MODULE)
|
if (libraryCache is CachedLibraries.Cache.Monolithic)
|
||||||
null
|
null
|
||||||
else {
|
else {
|
||||||
val filesToCache = configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
val filesToCache = configuration.get(KonanConfigKeys.FILES_TO_CACHE)
|
||||||
@@ -183,7 +183,7 @@ class CacheSupport(
|
|||||||
// Ensure not making cache for libraries that are already cached:
|
// Ensure not making cache for libraries that are already cached:
|
||||||
libraryToCache?.klib?.let {
|
libraryToCache?.klib?.let {
|
||||||
val cache = cachedLibraries.getLibraryCache(it)
|
val cache = cachedLibraries.getLibraryCache(it)
|
||||||
if (cache != null && cache.granularity == CachedLibraries.Granularity.MODULE) {
|
if (cache is CachedLibraries.Cache.Monolithic) {
|
||||||
configuration.reportCompilationError("can't cache library '${it.libraryName}' " +
|
configuration.reportCompilationError("can't cache library '${it.libraryName}' " +
|
||||||
"that is already cached in '${cache.path}'")
|
"that is already cached in '${cache.path}'")
|
||||||
}
|
}
|
||||||
|
|||||||
+109
-58
@@ -5,16 +5,18 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.konan.serialization.*
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
|
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
|
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
import org.jetbrains.kotlin.library.uniqueName
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
|
|
||||||
|
private fun getArtifactName(target: KonanTarget, baseName: String, kind: CompilerOutputKind) =
|
||||||
|
"${kind.prefix(target)}$baseName${kind.suffix(target)}"
|
||||||
|
|
||||||
class CachedLibraries(
|
class CachedLibraries(
|
||||||
private val target: KonanTarget,
|
private val target: KonanTarget,
|
||||||
allLibraries: List<KotlinLibrary>,
|
allLibraries: List<KotlinLibrary>,
|
||||||
@@ -22,68 +24,117 @@ class CachedLibraries(
|
|||||||
implicitCacheDirectories: List<File>
|
implicitCacheDirectories: List<File>
|
||||||
) {
|
) {
|
||||||
enum class Kind { DYNAMIC, STATIC }
|
enum class Kind { DYNAMIC, STATIC }
|
||||||
enum class Granularity { MODULE, FILE }
|
|
||||||
|
|
||||||
private fun Kind.toCompilerOutputKind(): CompilerOutputKind = when (this) {
|
sealed class BitcodeDependency(val libName: String) {
|
||||||
Kind.DYNAMIC -> CompilerOutputKind.DYNAMIC_CACHE
|
class WholeModule(libName: String) : BitcodeDependency(libName)
|
||||||
Kind.STATIC -> CompilerOutputKind.STATIC_CACHE
|
|
||||||
|
class CertainFiles(libName: String, val files: List<String>) : BitcodeDependency(libName)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class Cache(val kind: Kind, val granularity: Granularity, val path: String) {
|
sealed class Cache(protected val target: KonanTarget, val kind: Kind, val path: String) {
|
||||||
val fileDirs by lazy { File(path).listFiles.filter { it.isDirectory }.sortedBy { it.name } }
|
val bitcodeDependencies by lazy { computeBitcodeDependencies() }
|
||||||
|
val binariesPaths by lazy { computeBinariesPaths() }
|
||||||
|
val serializedInlineFunctionBodies by lazy { computeSerializedInlineFunctionBodies() }
|
||||||
|
val serializedClassFields by lazy { computeSerializedClassFields() }
|
||||||
|
val serializedEagerInitializedFiles by lazy { computeSerializedEagerInitializedFiles() }
|
||||||
|
|
||||||
val bitcodeDependencies by lazy {
|
protected abstract fun computeBitcodeDependencies(): List<BitcodeDependency>
|
||||||
when (granularity) {
|
protected abstract fun computeBinariesPaths(): List<String>
|
||||||
Granularity.MODULE -> File(path).parentFile.child(BITCODE_DEPENDENCIES_FILE_NAME).readStrings()
|
protected abstract fun computeSerializedInlineFunctionBodies(): List<SerializedInlineFunctionReference>
|
||||||
Granularity.FILE -> fileDirs.flatMap {
|
protected abstract fun computeSerializedClassFields(): List<SerializedClassFields>
|
||||||
it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(BITCODE_DEPENDENCIES_FILE_NAME).readStrings()
|
protected abstract fun computeSerializedEagerInitializedFiles(): List<SerializedEagerInitializedFile>
|
||||||
}.distinct()
|
|
||||||
|
protected fun Kind.toCompilerOutputKind(): CompilerOutputKind = when (this) {
|
||||||
|
Kind.DYNAMIC -> CompilerOutputKind.DYNAMIC_CACHE
|
||||||
|
Kind.STATIC -> CompilerOutputKind.STATIC_CACHE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun parseDependencies(dependencies: List<String>): List<BitcodeDependency> {
|
||||||
|
val wholeModuleDependencies = mutableListOf<String>()
|
||||||
|
val fileDependencies = mutableMapOf<String, MutableList<String>>()
|
||||||
|
for (dependency in dependencies) {
|
||||||
|
val delimiterIndex = dependency.lastIndexOf(DEPENDENCIES_DELIMITER)
|
||||||
|
require(delimiterIndex >= 0) { "Invalid dependency $dependency of library $path" }
|
||||||
|
val libName = dependency.substring(0, delimiterIndex)
|
||||||
|
val file = dependency.substring(delimiterIndex + 1, dependency.length)
|
||||||
|
if (file.isEmpty())
|
||||||
|
wholeModuleDependencies.add(libName)
|
||||||
|
else
|
||||||
|
fileDependencies.getOrPut(libName) { mutableListOf() }.add(file)
|
||||||
|
}
|
||||||
|
return wholeModuleDependencies.map { BitcodeDependency.WholeModule(it) } +
|
||||||
|
fileDependencies.map { (libName, files) -> BitcodeDependency.CertainFiles(libName, files) }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Monolithic(target: KonanTarget, kind: Kind, path: String) : Cache(target, kind, path) {
|
||||||
|
override fun computeBitcodeDependencies() =
|
||||||
|
parseDependencies(File(path).parentFile.child(BITCODE_DEPENDENCIES_FILE_NAME).readStrings())
|
||||||
|
|
||||||
|
override fun computeBinariesPaths() = listOf(path)
|
||||||
|
|
||||||
|
override fun computeSerializedInlineFunctionBodies() = mutableListOf<SerializedInlineFunctionReference>().also {
|
||||||
|
val directory = File(path).absoluteFile.parentFile.parentFile
|
||||||
|
val data = directory.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
|
||||||
|
InlineFunctionBodyReferenceSerializer.deserializeTo(data, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeSerializedClassFields() = mutableListOf<SerializedClassFields>().also {
|
||||||
|
val directory = File(path).absoluteFile.parentFile.parentFile
|
||||||
|
val data = directory.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(CLASS_FIELDS_FILE_NAME).readBytes()
|
||||||
|
ClassFieldsSerializer.deserializeTo(data, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeSerializedEagerInitializedFiles() = mutableListOf<SerializedEagerInitializedFile>().also {
|
||||||
|
val directory = File(path).absoluteFile.parentFile.parentFile
|
||||||
|
val data = directory.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(EAGER_INITIALIZED_PROPERTIES_FILE_NAME).readBytes()
|
||||||
|
EagerInitializedPropertySerializer.deserializeTo(data, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val binariesPaths by lazy {
|
class PerFile(target: KonanTarget, kind: Kind, path: String) : Cache(target, kind, path) {
|
||||||
when (granularity) {
|
private val fileDirs by lazy { File(path).listFiles.filter { it.isDirectory }.sortedBy { it.name } }
|
||||||
Granularity.MODULE -> listOf(path)
|
|
||||||
Granularity.FILE -> fileDirs.map {
|
private val perFileBitcodeDependencies by lazy {
|
||||||
it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(getArtifactName(it.name, kind.toCompilerOutputKind())).absolutePath
|
fileDirs.associate {
|
||||||
|
it.name to parseDependencies(it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(BITCODE_DEPENDENCIES_FILE_NAME).readStrings())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val serializedInlineFunctionBodies by lazy {
|
fun getFileDependencies(file: String) =
|
||||||
val result = mutableListOf<SerializedInlineFunctionReference>()
|
perFileBitcodeDependencies[file] ?: error("File $file is not found in cache $path")
|
||||||
when (granularity) {
|
|
||||||
Granularity.MODULE -> {
|
fun getFileBinaryPath(file: String) =
|
||||||
val directory = File(path).absoluteFile.parentFile.parentFile
|
File(path).child(file).child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(getArtifactName(target, file, kind.toCompilerOutputKind())).let {
|
||||||
val data = directory.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
|
require(it.exists) { "File $file is not found in cache $path" }
|
||||||
InlineFunctionBodyReferenceSerializer.deserializeTo(data, result)
|
it.absolutePath
|
||||||
}
|
|
||||||
Granularity.FILE -> {
|
|
||||||
fileDirs.forEach { fileDir ->
|
|
||||||
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
|
|
||||||
InlineFunctionBodyReferenceSerializer.deserializeTo(data, result)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
val serializedClassFields by lazy {
|
override fun computeBitcodeDependencies() = perFileBitcodeDependencies.values.flatten()
|
||||||
val result = mutableListOf<SerializedClassFields>()
|
|
||||||
when (granularity) {
|
override fun computeBinariesPaths() = fileDirs.map {
|
||||||
Granularity.MODULE -> {
|
it.child(PER_FILE_CACHE_BINARY_LEVEL_DIR_NAME).child(getArtifactName(target, it.name, kind.toCompilerOutputKind())).absolutePath
|
||||||
val directory = File(path).absoluteFile.parentFile.parentFile
|
}
|
||||||
val data = directory.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(CLASS_FIELDS_FILE_NAME).readBytes()
|
|
||||||
ClassFieldsSerializer.deserializeTo(data, result)
|
override fun computeSerializedInlineFunctionBodies() = mutableListOf<SerializedInlineFunctionReference>().also {
|
||||||
}
|
fileDirs.forEach { fileDir ->
|
||||||
Granularity.FILE -> {
|
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(INLINE_FUNCTION_BODIES_FILE_NAME).readBytes()
|
||||||
fileDirs.forEach { fileDir ->
|
InlineFunctionBodyReferenceSerializer.deserializeTo(data, it)
|
||||||
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(CLASS_FIELDS_FILE_NAME).readBytes()
|
}
|
||||||
ClassFieldsSerializer.deserializeTo(data, result)
|
}
|
||||||
}
|
|
||||||
|
override fun computeSerializedClassFields() = mutableListOf<SerializedClassFields>().also {
|
||||||
|
fileDirs.forEach { fileDir ->
|
||||||
|
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(CLASS_FIELDS_FILE_NAME).readBytes()
|
||||||
|
ClassFieldsSerializer.deserializeTo(data, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun computeSerializedEagerInitializedFiles() = mutableListOf<SerializedEagerInitializedFile>().also {
|
||||||
|
fileDirs.forEach { fileDir ->
|
||||||
|
val data = fileDir.child(PER_FILE_CACHE_IR_LEVEL_DIR_NAME).child(EAGER_INITIALIZED_PROPERTIES_FILE_NAME).readBytes()
|
||||||
|
EagerInitializedPropertySerializer.deserializeTo(data, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,16 +151,16 @@ class CachedLibraries(
|
|||||||
cacheBinaryPartDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
cacheBinaryPartDir.listFilesOrEmpty.map { it.absolutePath }.toSet()
|
||||||
}
|
}
|
||||||
val baseName = getCachedLibraryName(library)
|
val baseName = getCachedLibraryName(library)
|
||||||
val dynamicFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.DYNAMIC_CACHE))
|
val dynamicFile = cacheBinaryPartDir.child(getArtifactName(target, baseName, CompilerOutputKind.DYNAMIC_CACHE))
|
||||||
val staticFile = cacheBinaryPartDir.child(getArtifactName(baseName, CompilerOutputKind.STATIC_CACHE))
|
val staticFile = cacheBinaryPartDir.child(getArtifactName(target, baseName, CompilerOutputKind.STATIC_CACHE))
|
||||||
|
|
||||||
if (dynamicFile.absolutePath in cacheBinaryPartDirContents && staticFile.absolutePath in cacheBinaryPartDirContents)
|
if (dynamicFile.absolutePath in cacheBinaryPartDirContents && staticFile.absolutePath in cacheBinaryPartDirContents)
|
||||||
error("Both dynamic and static caches files cannot be in the same directory." +
|
error("Both dynamic and static caches files cannot be in the same directory." +
|
||||||
" Library: ${library.libraryName}, path to cache: ${cacheDir.absolutePath}")
|
" Library: ${library.libraryName}, path to cache: ${cacheDir.absolutePath}")
|
||||||
return when {
|
return when {
|
||||||
dynamicFile.absolutePath in cacheBinaryPartDirContents -> Cache(Kind.DYNAMIC, Granularity.MODULE, dynamicFile.absolutePath)
|
dynamicFile.absolutePath in cacheBinaryPartDirContents -> Cache.Monolithic(target, Kind.DYNAMIC, dynamicFile.absolutePath)
|
||||||
staticFile.absolutePath in cacheBinaryPartDirContents -> Cache(Kind.STATIC, Granularity.MODULE, staticFile.absolutePath)
|
staticFile.absolutePath in cacheBinaryPartDirContents -> Cache.Monolithic(target, Kind.STATIC, staticFile.absolutePath)
|
||||||
else -> Cache(Kind.STATIC, Granularity.FILE, cacheDir.absolutePath)
|
else -> Cache.PerFile(target, Kind.STATIC, cacheDir.absolutePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +180,6 @@ class CachedLibraries(
|
|||||||
cache?.let { library to it }
|
cache?.let { library to it }
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
private fun getArtifactName(baseName: String, kind: CompilerOutputKind) =
|
|
||||||
"${kind.prefix(target)}$baseName${kind.suffix(target)}"
|
|
||||||
|
|
||||||
fun isLibraryCached(library: KotlinLibrary): Boolean =
|
fun isLibraryCached(library: KotlinLibrary): Boolean =
|
||||||
getLibraryCache(library) != null
|
getLibraryCache(library) != null
|
||||||
|
|
||||||
@@ -163,5 +211,8 @@ class CachedLibraries(
|
|||||||
const val BITCODE_DEPENDENCIES_FILE_NAME = "bitcode_deps"
|
const val BITCODE_DEPENDENCIES_FILE_NAME = "bitcode_deps"
|
||||||
const val INLINE_FUNCTION_BODIES_FILE_NAME = "inline_bodies"
|
const val INLINE_FUNCTION_BODIES_FILE_NAME = "inline_bodies"
|
||||||
const val CLASS_FIELDS_FILE_NAME = "class_fields"
|
const val CLASS_FIELDS_FILE_NAME = "class_fields"
|
||||||
|
const val EAGER_INITIALIZED_PROPERTIES_FILE_NAME = "eager_init"
|
||||||
|
|
||||||
|
const val DEPENDENCIES_DELIMITER = '|'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-9
@@ -37,25 +37,22 @@ private class CallsChecker(generationState: NativeGenerationState, goodFunctions
|
|||||||
private fun moduleFunction(name: String) =
|
private fun moduleFunction(name: String) =
|
||||||
LLVMGetNamedFunction(llvm.module, name) ?: throw IllegalStateException("$name function is not available")
|
LLVMGetNamedFunction(llvm.module, name) ?: throw IllegalStateException("$name function is not available")
|
||||||
|
|
||||||
val getMethodImpl = llvm.externalFunction(LlvmFunctionProto(
|
val getMethodImpl = llvm.externalNativeRuntimeFunction(
|
||||||
"class_getMethodImplementation",
|
"class_getMethodImplementation",
|
||||||
LlvmRetType(pointerType(functionType(llvm.voidType, false))),
|
LlvmRetType(pointerType(functionType(llvm.voidType, false))),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType))
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val getClass = llvm.externalFunction(LlvmFunctionProto(
|
val getClass = llvm.externalNativeRuntimeFunction(
|
||||||
"object_getClass",
|
"object_getClass",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType))
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val getSuperClass = llvm.externalFunction(LlvmFunctionProto(
|
val getSuperClass = llvm.externalNativeRuntimeFunction(
|
||||||
"class_getSuperclass",
|
"class_getSuperclass",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType))
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val checkerFunction = moduleFunction("Kotlin_mm_checkStateAtExternalFunctionCall")
|
val checkerFunction = moduleFunction("Kotlin_mm_checkStateAtExternalFunctionCall")
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@ internal val NativeGenerationState.shouldDefineCachedBoxes: Boolean
|
|||||||
|
|
||||||
internal val NativeGenerationState.shouldLinkRuntimeNativeLibraries: Boolean
|
internal val NativeGenerationState.shouldLinkRuntimeNativeLibraries: Boolean
|
||||||
get() = producedLlvmModuleContainsStdlib &&
|
get() = producedLlvmModuleContainsStdlib &&
|
||||||
cacheDeserializationStrategy?.contains(KonanFqNames.packageName, "Runtime.kt") != false
|
cacheDeserializationStrategy?.contains(KonanFqNames.internalPackageName, "Runtime.kt") != false
|
||||||
|
|
||||||
val KonanConfig.involvesLinkStage: Boolean
|
val KonanConfig.involvesLinkStage: Boolean
|
||||||
get() = when (this.produce) {
|
get() = when (this.produce) {
|
||||||
|
|||||||
+34
-8
@@ -1,7 +1,9 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
|
import org.jetbrains.kotlin.backend.konan.driver.PhaseContext
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.ClassFieldsSerializer
|
||||||
|
import org.jetbrains.kotlin.backend.konan.serialization.EagerInitializedPropertySerializer
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
|
import org.jetbrains.kotlin.backend.konan.serialization.InlineFunctionBodyReferenceSerializer
|
||||||
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
|
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
|
||||||
import org.jetbrains.kotlin.konan.exec.Command
|
import org.jetbrains.kotlin.konan.exec.Command
|
||||||
@@ -55,17 +57,33 @@ internal class CacheStorage(val generationState: NativeGenerationState) {
|
|||||||
saveCacheBitcodeDependencies()
|
saveCacheBitcodeDependencies()
|
||||||
saveInlineFunctionBodies()
|
saveInlineFunctionBodies()
|
||||||
saveClassFields()
|
saveClassFields()
|
||||||
|
saveEagerInitializedProperties()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveCacheBitcodeDependencies() {
|
private fun saveCacheBitcodeDependencies() {
|
||||||
val bitcodeDependencies = config.resolvedLibraries
|
val libraryToCache = config.cacheSupport.libraryToCache!!
|
||||||
|
val usedBitcode = generationState.llvmImports.usedBitcode().groupBy { it.library }
|
||||||
|
val bitcodeModuleDependencies = mutableListOf<String>()
|
||||||
|
val bitcodeFileDependencies = mutableListOf<String>()
|
||||||
|
val strategy = libraryToCache.strategy as? CacheDeserializationStrategy.SingleFile
|
||||||
|
config.resolvedLibraries
|
||||||
.getFullList(TopologicalLibraryOrder)
|
.getFullList(TopologicalLibraryOrder)
|
||||||
.map { it as KonanLibrary }
|
.forEach { library ->
|
||||||
.filter {
|
require(library is KonanLibrary)
|
||||||
generationState.llvmImports.bitcodeIsUsed(it)
|
val filesUsed = usedBitcode[library]
|
||||||
&& it != config.cacheSupport.libraryToCache?.klib // Skip loops.
|
if (filesUsed == null && generationState.llvmImports.bitcodeIsUsed(library)
|
||||||
|
&& library != libraryToCache.klib /* Skip loops */) {
|
||||||
|
// Dependency on the entire library.
|
||||||
|
bitcodeModuleDependencies.add("${library.uniqueName}${CachedLibraries.DEPENDENCIES_DELIMITER}")
|
||||||
|
}
|
||||||
|
filesUsed?.forEach { libraryFile ->
|
||||||
|
if (library != libraryToCache.klib || strategy?.filePath != libraryFile.filePath /* Skip loops */) {
|
||||||
|
val fileId = CacheSupport.cacheFileId(libraryFile.fqName, libraryFile.filePath)
|
||||||
|
bitcodeFileDependencies.add("${library.uniqueName}${CachedLibraries.DEPENDENCIES_DELIMITER}$fileId")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
outputFiles.bitcodeDependenciesFile!!.writeLines(bitcodeDependencies.map { it.uniqueName })
|
outputFiles.bitcodeDependenciesFile!!.writeLines(bitcodeModuleDependencies + bitcodeFileDependencies)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveInlineFunctionBodies() {
|
private fun saveInlineFunctionBodies() {
|
||||||
@@ -77,6 +95,11 @@ internal class CacheStorage(val generationState: NativeGenerationState) {
|
|||||||
outputFiles.classFieldsFile!!.writeBytes(
|
outputFiles.classFieldsFile!!.writeBytes(
|
||||||
ClassFieldsSerializer.serialize(generationState.classFields))
|
ClassFieldsSerializer.serialize(generationState.classFields))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun saveEagerInitializedProperties() {
|
||||||
|
outputFiles.eagerInitializedPropertiesFile!!.writeBytes(
|
||||||
|
EagerInitializedPropertySerializer.serialize(generationState.eagerInitializedFiles))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We have a Linker.kt file in the shared module.
|
// TODO: We have a Linker.kt file in the shared module.
|
||||||
@@ -239,7 +262,8 @@ private fun determineCachesToLink(generationState: NativeGenerationState): Cache
|
|||||||
val staticCaches = mutableListOf<String>()
|
val staticCaches = mutableListOf<String>()
|
||||||
val dynamicCaches = mutableListOf<String>()
|
val dynamicCaches = mutableListOf<String>()
|
||||||
|
|
||||||
generationState.llvm.allCachedBitcodeDependencies.forEach { library ->
|
generationState.llvm.allCachedBitcodeDependencies.forEach { dependency ->
|
||||||
|
val library = dependency.library
|
||||||
val currentBinaryContainsLibrary = generationState.llvmModuleSpecification.containsLibrary(library)
|
val currentBinaryContainsLibrary = generationState.llvmModuleSpecification.containsLibrary(library)
|
||||||
val cache = generationState.config.cachedLibraries.getLibraryCache(library)
|
val cache = generationState.config.cachedLibraries.getLibraryCache(library)
|
||||||
?: error("Library $library is expected to be cached")
|
?: error("Library $library is expected to be cached")
|
||||||
@@ -253,7 +277,9 @@ private fun determineCachesToLink(generationState: NativeGenerationState): Cache
|
|||||||
CachedLibraries.Kind.STATIC -> staticCaches
|
CachedLibraries.Kind.STATIC -> staticCaches
|
||||||
}
|
}
|
||||||
|
|
||||||
list += cache.binariesPaths
|
list += if (dependency is Llvm.CachedBitcodeDependency.CertainFiles && cache is CachedLibraries.Cache.PerFile)
|
||||||
|
dependency.files.map { cache.getFileBinaryPath(it) }
|
||||||
|
else cache.binariesPaths
|
||||||
}
|
}
|
||||||
return CachesToLink(static = staticCaches, dynamic = dynamicCaches)
|
return CachesToLink(static = staticCaches, dynamic = dynamicCaches)
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-4
@@ -6,18 +6,22 @@
|
|||||||
package org.jetbrains.kotlin.backend.konan
|
package org.jetbrains.kotlin.backend.konan
|
||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.isFromInteropLibrary
|
||||||
import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext
|
import org.jetbrains.kotlin.backend.konan.driver.BasicPhaseContext
|
||||||
|
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
|
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
|
||||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
|
import org.jetbrains.kotlin.backend.konan.serialization.SerializedClassFields
|
||||||
|
import org.jetbrains.kotlin.backend.konan.serialization.SerializedEagerInitializedFile
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
|
import org.jetbrains.kotlin.backend.konan.serialization.SerializedInlineFunctionReference
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|
||||||
import org.jetbrains.kotlin.konan.TempFiles
|
import org.jetbrains.kotlin.konan.TempFiles
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
||||||
|
|
||||||
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
|
internal class InlineFunctionOriginInfo(val irFunction: IrFunction, val irFile: IrFile, val startOffset: Int, val endOffset: Int)
|
||||||
|
|
||||||
@@ -61,6 +65,7 @@ internal class NativeGenerationState(
|
|||||||
|
|
||||||
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
|
val inlineFunctionBodies = mutableListOf<SerializedInlineFunctionReference>()
|
||||||
val classFields = mutableListOf<SerializedClassFields>()
|
val classFields = mutableListOf<SerializedClassFields>()
|
||||||
|
val eagerInitializedFiles = mutableListOf<SerializedEagerInitializedFile>()
|
||||||
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
|
val calledFromExportedInlineFunctions = mutableSetOf<IrFunction>()
|
||||||
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
|
val constructedFromExportedInlineFunctions = mutableSetOf<IrClass>()
|
||||||
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
val loweredInlineFunctions = mutableMapOf<IrFunction, InlineFunctionOriginInfo>()
|
||||||
@@ -105,6 +110,25 @@ internal class NativeGenerationState(
|
|||||||
|
|
||||||
lateinit var objCExport: ObjCExport
|
lateinit var objCExport: ObjCExport
|
||||||
|
|
||||||
|
fun computeOrigin(declaration: IrDeclaration): CompiledKlibFileOrigin {
|
||||||
|
val packageFragment = declaration.getPackageFragment()
|
||||||
|
return if (packageFragment.isFunctionInterfaceFile)
|
||||||
|
CompiledKlibFileOrigin.StdlibKFunctionImpl
|
||||||
|
else {
|
||||||
|
val library = when (val origin = declaration.llvmSymbolOrigin) {
|
||||||
|
CurrentKlibModuleOrigin -> config.libraryToCache?.klib?.takeIf { config.producePerFileCache }
|
||||||
|
else -> (origin as DeserializedKlibModuleOrigin).library
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
library == null -> CompiledKlibFileOrigin.CurrentFile
|
||||||
|
packageFragment.packageFragmentDescriptor.containingDeclaration.isFromInteropLibrary() ->
|
||||||
|
CompiledKlibFileOrigin.EntireModule(library)
|
||||||
|
else -> CompiledKlibFileOrigin.CertainFile(library, packageFragment.fqName.asString(),
|
||||||
|
context.irLinker.getExternalDeclarationFileName(declaration))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun hasDebugInfo() = debugInfoDelegate.isInitialized()
|
fun hasDebugInfo() = debugInfoDelegate.isInitialized()
|
||||||
|
|
||||||
fun verifyBitCode() {
|
fun verifyBitCode() {
|
||||||
|
|||||||
+2
@@ -73,6 +73,8 @@ class OutputFiles(val outputName: String, target: KonanTarget, val produce: Comp
|
|||||||
|
|
||||||
val classFieldsFile = tempCacheDirectory?.cacheIrPart()?.child(CachedLibraries.CLASS_FIELDS_FILE_NAME)
|
val classFieldsFile = tempCacheDirectory?.cacheIrPart()?.child(CachedLibraries.CLASS_FIELDS_FILE_NAME)
|
||||||
|
|
||||||
|
val eagerInitializedPropertiesFile = tempCacheDirectory?.cacheIrPart()?.child(CachedLibraries.EAGER_INITIALIZED_PROPERTIES_FILE_NAME)
|
||||||
|
|
||||||
private fun String.fullOutputName() = prefixBaseNameIfNeeded(prefix).suffixIfNeeded(suffix)
|
private fun String.fullOutputName() = prefixBaseNameIfNeeded(prefix).suffixIfNeeded(suffix)
|
||||||
|
|
||||||
private fun String.prefixBaseNameIfNeeded(prefix: String) =
|
private fun String.prefixBaseNameIfNeeded(prefix: String) =
|
||||||
|
|||||||
+1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFile
|
|||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
|
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
|
||||||
internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) {
|
internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) {
|
||||||
|
|||||||
+31
-3
@@ -11,11 +11,17 @@ import org.jetbrains.kotlin.backend.konan.driver.PhaseEngine
|
|||||||
import org.jetbrains.kotlin.backend.konan.driver.runPhaseInParentContext
|
import org.jetbrains.kotlin.backend.konan.driver.runPhaseInParentContext
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.linkBitcodeDependenciesPhase
|
import org.jetbrains.kotlin.backend.konan.llvm.linkBitcodeDependenciesPhase
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.printBitcodePhase
|
import org.jetbrains.kotlin.backend.konan.llvm.printBitcodePhase
|
||||||
|
import org.jetbrains.kotlin.backend.konan.llvm.standardLlvmSymbolsOrigin
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.verifyBitcodePhase
|
import org.jetbrains.kotlin.backend.konan.llvm.verifyBitcodePhase
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.declarations.path
|
import org.jetbrains.kotlin.ir.declarations.path
|
||||||
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
||||||
|
|
||||||
internal fun PhaseEngine<PhaseContext>.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? {
|
internal fun PhaseEngine<PhaseContext>.runFrontend(config: KonanConfig, environment: KotlinCoreEnvironment): FrontendPhaseOutput.Full? {
|
||||||
val frontendOutput = useContext(FrontendContextImpl(config)) { it.runFrontend(environment) }
|
val frontendOutput = useContext(FrontendContextImpl(config)) { it.runFrontend(environment) }
|
||||||
@@ -57,6 +63,14 @@ internal fun <C : PhaseContext> PhaseEngine<C>.runBackend(backendContext: Contex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isReferencedByNativeRuntime(declarations: List<IrDeclaration>): Boolean =
|
||||||
|
declarations.any {
|
||||||
|
it.hasAnnotation(RuntimeNames.exportTypeInfoAnnotation)
|
||||||
|
|| it.hasAnnotation(RuntimeNames.exportForCppRuntime)
|
||||||
|
} || declarations.any {
|
||||||
|
it is IrClass && isReferencedByNativeRuntime(it.declarations)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun PhaseEngine<out Context>.processModuleFragments(
|
internal fun PhaseEngine<out Context>.processModuleFragments(
|
||||||
input: IrModuleFragment,
|
input: IrModuleFragment,
|
||||||
action: (NativeGenerationState, IrModuleFragment) -> Unit
|
action: (NativeGenerationState, IrModuleFragment) -> Unit
|
||||||
@@ -66,21 +80,35 @@ internal fun PhaseEngine<out Context>.processModuleFragments(
|
|||||||
|
|
||||||
val files = module.files.toList()
|
val files = module.files.toList()
|
||||||
module.files.clear()
|
module.files.clear()
|
||||||
val functionInterfaceFiles = files.filter { it.isFunctionInterfaceFile }
|
|
||||||
|
val stdlibIsBeingCached = module.descriptor == context.stdlibModule
|
||||||
|
val functionInterfaceFiles = files.takeIf { stdlibIsBeingCached }
|
||||||
|
?.filter { it.isFunctionInterfaceFile }.orEmpty()
|
||||||
|
val filesReferencedByNativeRuntime = files.takeIf { stdlibIsBeingCached }
|
||||||
|
?.filter { isReferencedByNativeRuntime(it.declarations) }.orEmpty()
|
||||||
|
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
if (file.isFunctionInterfaceFile) continue
|
if (file.isFunctionInterfaceFile) continue
|
||||||
|
|
||||||
context.generationState = NativeGenerationState(
|
val generationState = NativeGenerationState(
|
||||||
context.config,
|
context.config,
|
||||||
context,
|
context,
|
||||||
CacheDeserializationStrategy.SingleFile(file.path, file.fqName.asString())
|
CacheDeserializationStrategy.SingleFile(file.path, file.fqName.asString())
|
||||||
)
|
)
|
||||||
|
context.generationState = generationState
|
||||||
|
|
||||||
module.files += file
|
module.files += file
|
||||||
if (context.generationState.shouldDefineFunctionClasses)
|
if (generationState.shouldDefineFunctionClasses)
|
||||||
module.files += functionInterfaceFiles
|
module.files += functionInterfaceFiles
|
||||||
|
|
||||||
|
if (generationState.shouldLinkRuntimeNativeLibraries) {
|
||||||
|
val stdlib = (context.standardLlvmSymbolsOrigin as DeserializedKlibModuleOrigin).library
|
||||||
|
filesReferencedByNativeRuntime.forEach {
|
||||||
|
generationState.llvmImports.add(
|
||||||
|
CompiledKlibFileOrigin.CertainFile(stdlib, it.fqName.asString(), it.path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
action(context.generationState, input)
|
action(context.generationState, input)
|
||||||
|
|
||||||
module.files.clear()
|
module.files.clear()
|
||||||
|
|||||||
+13
-16
@@ -17,11 +17,11 @@ import org.jetbrains.kotlin.backend.konan.llvm.ThreadState.Runnable
|
|||||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
|
import org.jetbrains.kotlin.backend.konan.llvm.objc.*
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.konan.ForeignExceptionMode
|
import org.jetbrains.kotlin.konan.ForeignExceptionMode
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
|
||||||
|
|
||||||
|
|
||||||
internal class CodeGenerator(override val generationState: NativeGenerationState) : ContextUtils {
|
internal class CodeGenerator(override val generationState: NativeGenerationState) : ContextUtils {
|
||||||
@@ -1265,21 +1265,20 @@ internal abstract class FunctionGenerationContext(
|
|||||||
assert(!irClass.isInterface)
|
assert(!irClass.isInterface)
|
||||||
|
|
||||||
return if (irClass.isExternalObjCClass()) {
|
return if (irClass.isExternalObjCClass()) {
|
||||||
val llvmSymbolOrigin = irClass.llvmSymbolOrigin
|
val origin = generationState.computeOrigin(irClass)
|
||||||
|
|
||||||
if (irClass.isObjCMetaClass()) {
|
if (irClass.isObjCMetaClass()) {
|
||||||
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
|
val name = irClass.descriptor.getExternalObjCMetaClassBinaryName()
|
||||||
val objCClass = getObjCClass(name, llvmSymbolOrigin)
|
val objCClass = getObjCClass(name, origin)
|
||||||
|
|
||||||
val getClass = llvm.externalFunction(LlvmFunctionProto(
|
val getClass = llvm.externalNativeRuntimeFunction(
|
||||||
"object_getClass",
|
"object_getClass",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType))
|
||||||
origin = context.standardLlvmSymbolsOrigin
|
)
|
||||||
))
|
|
||||||
call(getClass, listOf(objCClass), exceptionHandler = exceptionHandler)
|
call(getClass, listOf(objCClass), exceptionHandler = exceptionHandler)
|
||||||
} else {
|
} else {
|
||||||
getObjCClass(irClass.descriptor.getExternalObjCClassBinaryName(), llvmSymbolOrigin)
|
getObjCClass(irClass.descriptor.getExternalObjCClassBinaryName(), origin)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (irClass.isObjCMetaClass()) {
|
if (irClass.isObjCMetaClass()) {
|
||||||
@@ -1303,8 +1302,8 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getObjCClass(binaryName: String, llvmSymbolOrigin: CompiledKlibModuleOrigin): LLVMValueRef {
|
fun getObjCClass(binaryName: String, origin: CompiledKlibFileOrigin): LLVMValueRef {
|
||||||
llvm.imports.add(llvmSymbolOrigin)
|
llvm.imports.add(origin)
|
||||||
return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
|
return load(codegen.objCDataGenerator!!.genClassRef(binaryName).llvm)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1467,17 +1466,15 @@ internal abstract class FunctionGenerationContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val kotlinExceptionRtti: ConstPointer
|
private val kotlinExceptionRtti: ConstPointer
|
||||||
get() = constPointer(importGlobal(
|
get() = constPointer(importNativeRuntimeGlobal(
|
||||||
"_ZTI18ExceptionObjHolder", // typeinfo for ObjHolder
|
"_ZTI18ExceptionObjHolder", // typeinfo for ObjHolder
|
||||||
llvm.int8PtrType,
|
llvm.int8PtrType
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
|
||||||
)).bitcast(llvm.int8PtrType)
|
)).bitcast(llvm.int8PtrType)
|
||||||
|
|
||||||
private val objcNSExceptionRtti: ConstPointer by lazy {
|
private val objcNSExceptionRtti: ConstPointer by lazy {
|
||||||
constPointer(importGlobal(
|
constPointer(importNativeRuntimeGlobal(
|
||||||
"OBJC_EHTYPE_\$_NSException", // typeinfo for NSException*
|
"OBJC_EHTYPE_\$_NSException", // typeinfo for NSException*
|
||||||
llvm.int8PtrType,
|
llvm.int8PtrType
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
|
||||||
)).bitcast(llvm.int8PtrType)
|
)).bitcast(llvm.int8PtrType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+157
-50
@@ -8,18 +8,24 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
import kotlinx.cinterop.toCValues
|
import kotlinx.cinterop.toCValues
|
||||||
import kotlinx.cinterop.toKString
|
import kotlinx.cinterop.toKString
|
||||||
import llvm.*
|
import llvm.*
|
||||||
|
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||||
import org.jetbrains.kotlin.backend.konan.*
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
|
||||||
|
import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
||||||
|
import org.jetbrains.kotlin.descriptors.konan.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin
|
import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.library.metadata.resolver.TopologicalLibraryOrder
|
|
||||||
import org.jetbrains.kotlin.library.uniqueName
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@@ -215,8 +221,7 @@ internal interface ContextUtils : RuntimeAware {
|
|||||||
this.computePrivateTypeInfoSymbolName(context.irLinker.getExternalDeclarationFileName(this))
|
this.computePrivateTypeInfoSymbolName(context.irLinker.getExternalDeclarationFileName(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType,
|
constPointer(importGlobal(typeInfoSymbolName, runtime.typeInfoType, generationState.computeOrigin(this)))
|
||||||
origin = this.llvmSymbolOrigin))
|
|
||||||
} else {
|
} else {
|
||||||
generationState.llvmDeclarations.forClass(this).typeInfo
|
generationState.llvmDeclarations.forClass(this).typeInfo
|
||||||
}
|
}
|
||||||
@@ -359,6 +364,21 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun externalNativeRuntimeFunction(
|
||||||
|
name: String,
|
||||||
|
returnType: LlvmRetType,
|
||||||
|
parameterTypes: List<LlvmParamType> = emptyList(),
|
||||||
|
functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
|
||||||
|
isVararg: Boolean = false
|
||||||
|
) = externalFunction(
|
||||||
|
LlvmFunctionProto(name, returnType, parameterTypes, functionAttributes,
|
||||||
|
origin = CompiledKlibFileOrigin.StdlibRuntime,
|
||||||
|
isVararg, independent = false)
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun externalNativeRuntimeFunction(name: String, signature: LlvmFunctionSignature) =
|
||||||
|
externalNativeRuntimeFunction(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, signature.isVararg)
|
||||||
|
|
||||||
val imports get() = generationState.llvmImports
|
val imports get() = generationState.llvmImports
|
||||||
|
|
||||||
class ImportsImpl(private val context: Context) : LlvmImports {
|
class ImportsImpl(private val context: Context) : LlvmImports {
|
||||||
@@ -366,27 +386,48 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
|
|||||||
private val usedBitcode = mutableSetOf<KotlinLibrary>()
|
private val usedBitcode = mutableSetOf<KotlinLibrary>()
|
||||||
private val usedNativeDependencies = mutableSetOf<KotlinLibrary>()
|
private val usedNativeDependencies = mutableSetOf<KotlinLibrary>()
|
||||||
|
|
||||||
|
private val usedBitcodeOfFile = mutableSetOf<LlvmImports.LibraryFile>()
|
||||||
|
|
||||||
private val allLibraries by lazy { context.librariesWithDependencies.toSet() }
|
private val allLibraries by lazy { context.librariesWithDependencies.toSet() }
|
||||||
|
|
||||||
override fun add(origin: CompiledKlibModuleOrigin, onlyBitcode: Boolean) {
|
private fun findStdlibFile(fqName: FqName, fileName: String): LlvmImports.LibraryFile {
|
||||||
val library = when (origin) {
|
val stdlib = (context.standardLlvmSymbolsOrigin as? DeserializedKlibModuleOrigin)?.library
|
||||||
CurrentKlibModuleOrigin -> return
|
?: error("Can't find stdlib")
|
||||||
is DeserializedKlibModuleOrigin -> origin.library
|
val stdlibDeserializer = context.irLinker.moduleDeserializers[context.stdlibModule]
|
||||||
}
|
?: error("No deserializer for stdlib")
|
||||||
|
val file = stdlibDeserializer.files.atMostOne { it.fqName == fqName && it.name == fileName }
|
||||||
|
?: error("Can't find $fqName:$fileName in stdlib")
|
||||||
|
return LlvmImports.LibraryFile(stdlib, file.fqName.asString(), file.path)
|
||||||
|
}
|
||||||
|
|
||||||
if (library !in allLibraries) {
|
private val stdlibRuntime by lazy { findStdlibFile(KonanFqNames.internalPackageName, "Runtime.kt") }
|
||||||
error("Library (${library.libraryName}) is used but not requested.\nRequested libraries: ${allLibraries.joinToString { it.libraryName }}")
|
private val stdlibKFunctionImpl by lazy { findStdlibFile(KonanFqNames.internalPackageName, "KFunctionImpl.kt") }
|
||||||
|
|
||||||
|
override fun add(origin: CompiledKlibFileOrigin, onlyBitcode: Boolean) {
|
||||||
|
val libraryFile = when (origin) {
|
||||||
|
CompiledKlibFileOrigin.CurrentFile -> return
|
||||||
|
is CompiledKlibFileOrigin.EntireModule -> null
|
||||||
|
is CompiledKlibFileOrigin.CertainFile -> LlvmImports.LibraryFile(origin.library, origin.fqName, origin.filePath)
|
||||||
|
CompiledKlibFileOrigin.StdlibRuntime -> stdlibRuntime
|
||||||
|
CompiledKlibFileOrigin.StdlibKFunctionImpl -> stdlibKFunctionImpl
|
||||||
}
|
}
|
||||||
|
val library = libraryFile?.library ?: (origin as CompiledKlibFileOrigin.EntireModule).library
|
||||||
|
if (library !in allLibraries)
|
||||||
|
error("Library (${library.libraryName}) is used but not requested.\nRequested libraries: ${allLibraries.joinToString { it.libraryName }}")
|
||||||
|
|
||||||
usedBitcode.add(library)
|
usedBitcode.add(library)
|
||||||
if (!onlyBitcode) {
|
if (!onlyBitcode) {
|
||||||
usedNativeDependencies.add(library)
|
usedNativeDependencies.add(library)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
libraryFile?.let { usedBitcodeOfFile.add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bitcodeIsUsed(library: KonanLibrary) = library in usedBitcode
|
override fun bitcodeIsUsed(library: KonanLibrary) = library in usedBitcode
|
||||||
|
|
||||||
override fun nativeDependenciesAreUsed(library: KonanLibrary) = library in usedNativeDependencies
|
override fun nativeDependenciesAreUsed(library: KonanLibrary) = library in usedNativeDependencies
|
||||||
|
|
||||||
|
override fun usedBitcode(): List<LlvmImports.LibraryFile> = usedBitcodeOfFile.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val nativeDependenciesToLink: List<KonanLibrary> by lazy {
|
val nativeDependenciesToLink: List<KonanLibrary> by lazy {
|
||||||
@@ -403,47 +444,117 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
|
|||||||
.filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.bitcodeIsUsed(it) }
|
.filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.bitcodeIsUsed(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val allCachedBitcodeDependencies: List<KonanLibrary> by lazy {
|
sealed class CachedBitcodeDependency(val library: KonanLibrary) {
|
||||||
val allLibraries = context.config.resolvedLibraries.getFullList().associateBy { it.uniqueName }
|
class WholeModule(library: KonanLibrary) : CachedBitcodeDependency(library)
|
||||||
val result = mutableSetOf<KonanLibrary>()
|
|
||||||
|
|
||||||
fun addDependencies(cachedLibrary: CachedLibraries.Cache) {
|
class CertainFiles(library: KonanLibrary, val files: List<String>) : CachedBitcodeDependency(library)
|
||||||
cachedLibrary.bitcodeDependencies.forEach {
|
}
|
||||||
val library = allLibraries[it] ?: error("Bitcode dependency to an unknown library: $it")
|
|
||||||
result.add(library as KonanLibrary)
|
private inner class CachedBitcodeDependenciesComputer {
|
||||||
addDependencies(context.config.cachedLibraries.getLibraryCache(library)
|
private val allLibraries = context.config.resolvedLibraries.getFullList().associateBy { it.uniqueName }
|
||||||
?: error("Library $it is expected to be cached"))
|
private val usedBitcode = imports.usedBitcode().groupBy { it.library }
|
||||||
|
|
||||||
|
private val moduleDependencies = mutableSetOf<KonanLibrary>()
|
||||||
|
private val fileDependencies = mutableMapOf<KonanLibrary, MutableSet<String>>()
|
||||||
|
|
||||||
|
val allDependencies: List<CachedBitcodeDependency>
|
||||||
|
|
||||||
|
init {
|
||||||
|
val moduleDeserializers = context.irLinker.moduleDeserializers.values.associateBy { it.klib }
|
||||||
|
for (library in immediateBitcodeDependencies) {
|
||||||
|
if (library == context.config.libraryToCache?.klib) continue
|
||||||
|
val cache = context.config.cachedLibraries.getLibraryCache(library)
|
||||||
|
|
||||||
|
if (cache != null) {
|
||||||
|
val filesUsed = buildList {
|
||||||
|
usedBitcode[library]?.forEach {
|
||||||
|
add(CacheSupport.cacheFileId(it.fqName, it.filePath))
|
||||||
|
}
|
||||||
|
val moduleDeserializer = moduleDeserializers[library]
|
||||||
|
if (moduleDeserializer == null) {
|
||||||
|
require(library.isInteropLibrary()) { "No module deserializer for cached library ${library.uniqueName}" }
|
||||||
|
} else {
|
||||||
|
moduleDeserializer.eagerInitializedFiles.forEach {
|
||||||
|
add(CacheSupport.cacheFileId(it.fqName.asString(), it.path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filesUsed.isEmpty()) {
|
||||||
|
// This is the case when we depend on the whole module rather than on a number of files.
|
||||||
|
moduleDependencies.add(library)
|
||||||
|
addAllDependencies(cache)
|
||||||
|
} else {
|
||||||
|
fileDependencies.getOrPut(library) { mutableSetOf() }.addAll(filesUsed)
|
||||||
|
addDependencies(cache, filesUsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allDependencies = moduleDependencies.map { CachedBitcodeDependency.WholeModule(it) } +
|
||||||
|
fileDependencies.filterNot { it.key in moduleDependencies }
|
||||||
|
.map { (library, files) -> CachedBitcodeDependency.CertainFiles(library, files.toList()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (library in immediateBitcodeDependencies) {
|
private fun addAllDependencies(cachedLibrary: CachedLibraries.Cache) {
|
||||||
if (library == context.config.libraryToCache?.klib) continue
|
cachedLibrary.bitcodeDependencies.forEach { addDependency(it) }
|
||||||
val cache = context.config.cachedLibraries.getLibraryCache(library)
|
|
||||||
if (cache != null) {
|
|
||||||
result += library
|
|
||||||
addDependencies(cache)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.toList()
|
private fun addDependencies(cachedLibrary: CachedLibraries.Cache, files: List<String>) = when (cachedLibrary) {
|
||||||
|
is CachedLibraries.Cache.Monolithic -> addAllDependencies(cachedLibrary)
|
||||||
|
|
||||||
|
is CachedLibraries.Cache.PerFile ->
|
||||||
|
files.forEach { file ->
|
||||||
|
cachedLibrary.getFileDependencies(file).forEach { addDependency(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addDependency(dependency: CachedLibraries.BitcodeDependency) {
|
||||||
|
val dependencyLib = (allLibraries[dependency.libName]
|
||||||
|
?: error("Bitcode dependency to an unknown library: ${dependency.libName}")) as KonanLibrary
|
||||||
|
if (dependencyLib in moduleDependencies) return
|
||||||
|
val cachedDependency = context.config.cachedLibraries.getLibraryCache(dependencyLib)
|
||||||
|
?: error("Library ${dependency.libName} is expected to be cached")
|
||||||
|
|
||||||
|
when (dependency) {
|
||||||
|
is CachedLibraries.BitcodeDependency.WholeModule -> {
|
||||||
|
moduleDependencies.add(dependencyLib)
|
||||||
|
addAllDependencies(cachedDependency)
|
||||||
|
}
|
||||||
|
is CachedLibraries.BitcodeDependency.CertainFiles -> {
|
||||||
|
val handledFiles = fileDependencies.getOrPut(dependencyLib) { mutableSetOf() }
|
||||||
|
val notHandledFiles = dependency.files.toMutableSet()
|
||||||
|
notHandledFiles.removeAll(handledFiles)
|
||||||
|
handledFiles.addAll(notHandledFiles)
|
||||||
|
if (notHandledFiles.isNotEmpty())
|
||||||
|
addDependencies(cachedDependency, notHandledFiles.toList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val allCachedBitcodeDependencies: List<CachedBitcodeDependency> by lazy {
|
||||||
|
CachedBitcodeDependenciesComputer().allDependencies
|
||||||
}
|
}
|
||||||
|
|
||||||
val allNativeDependencies: List<KonanLibrary> by lazy {
|
val allNativeDependencies: List<KonanLibrary> by lazy {
|
||||||
(nativeDependenciesToLink + allCachedBitcodeDependencies).distinct()
|
(nativeDependenciesToLink + allCachedBitcodeDependencies.map { it.library } /* Native dependencies are per library */).distinct()
|
||||||
}
|
}
|
||||||
|
|
||||||
val allBitcodeDependencies: List<KonanLibrary> by lazy {
|
val allBitcodeDependencies: List<CachedBitcodeDependency> by lazy {
|
||||||
val allNonCachedDependencies = context.librariesWithDependencies.filter {
|
val allBitcodeDependencies = mutableMapOf<KonanLibrary, CachedBitcodeDependency>()
|
||||||
context.config.cachedLibraries.getLibraryCache(it) == null || it == context.config.libraryToCache?.klib
|
for (library in context.librariesWithDependencies) {
|
||||||
|
if (context.config.cachedLibraries.getLibraryCache(library) == null || library == context.config.libraryToCache?.klib)
|
||||||
|
allBitcodeDependencies[library] = CachedBitcodeDependency.WholeModule(library)
|
||||||
}
|
}
|
||||||
val set = (allNonCachedDependencies + allCachedBitcodeDependencies).toSet()
|
for (dependency in allCachedBitcodeDependencies)
|
||||||
|
allBitcodeDependencies[dependency.library] = dependency
|
||||||
// This list is used in particular to build the libraries' initializers chain.
|
// This list is used in particular to build the libraries' initializers chain.
|
||||||
// The initializers must be called in the topological order, so make sure that the
|
// The initializers must be called in the topological order, so make sure that the
|
||||||
// libraries list being returned is also toposorted.
|
// libraries list being returned is also toposorted.
|
||||||
context.config.resolvedLibraries
|
context.config.resolvedLibraries
|
||||||
.getFullList(TopologicalLibraryOrder)
|
.getFullList(TopologicalLibraryOrder)
|
||||||
.map { it as KonanLibrary }
|
.mapNotNull { allBitcodeDependencies[it as KonanLibrary] }
|
||||||
.filter { it in set }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val bitcodeToLink: List<KonanLibrary> by lazy {
|
val bitcodeToLink: List<KonanLibrary> by lazy {
|
||||||
@@ -663,35 +774,31 @@ internal class Llvm(private val generationState: NativeGenerationState, val modu
|
|||||||
else -> "__gxx_personality_v0"
|
else -> "__gxx_personality_v0"
|
||||||
}
|
}
|
||||||
|
|
||||||
val cxxStdTerminate = externalFunction(LlvmFunctionProto(
|
val cxxStdTerminate = externalNativeRuntimeFunction(
|
||||||
"_ZSt9terminatev", // mangled C++ 'std::terminate'
|
"_ZSt9terminatev", // mangled C++ 'std::terminate'
|
||||||
returnType = LlvmRetType(voidType),
|
returnType = LlvmRetType(voidType),
|
||||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind)
|
||||||
origin = context.standardLlvmSymbolsOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val gxxPersonalityFunction = externalFunction(LlvmFunctionProto(
|
val gxxPersonalityFunction = externalNativeRuntimeFunction(
|
||||||
personalityFunctionName,
|
personalityFunctionName,
|
||||||
returnType = LlvmRetType(int32Type),
|
returnType = LlvmRetType(int32Type),
|
||||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||||
isVararg = true,
|
isVararg = true
|
||||||
origin = context.standardLlvmSymbolsOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val cxaBeginCatchFunction = externalFunction(LlvmFunctionProto(
|
val cxaBeginCatchFunction = externalNativeRuntimeFunction(
|
||||||
"__cxa_begin_catch",
|
"__cxa_begin_catch",
|
||||||
returnType = LlvmRetType(int8PtrType),
|
returnType = LlvmRetType(int8PtrType),
|
||||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
||||||
parameterTypes = listOf(LlvmParamType(int8PtrType)),
|
parameterTypes = listOf(LlvmParamType(int8PtrType))
|
||||||
origin = context.standardLlvmSymbolsOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val cxaEndCatchFunction = externalFunction(LlvmFunctionProto(
|
val cxaEndCatchFunction = externalNativeRuntimeFunction(
|
||||||
"__cxa_end_catch",
|
"__cxa_end_catch",
|
||||||
returnType = LlvmRetType(voidType),
|
returnType = LlvmRetType(voidType),
|
||||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind)
|
||||||
origin = context.standardLlvmSymbolsOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
private fun getSizeOfReturnTypeInBits(functionPointer: LLVMValueRef): Long {
|
private fun getSizeOfReturnTypeInBits(functionPointer: LLVMValueRef): Long {
|
||||||
// LLVMGetElementType is called because we need to dereference a pointer to function.
|
// LLVMGetElementType is called because we need to dereference a pointer to function.
|
||||||
|
|||||||
+6
-1
@@ -12,12 +12,17 @@ import org.jetbrains.kotlin.konan.library.KonanLibrary
|
|||||||
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.library.metadata.SyntheticModulesOrigin
|
import org.jetbrains.kotlin.library.metadata.SyntheticModulesOrigin
|
||||||
import org.jetbrains.kotlin.library.metadata.klibModuleOrigin
|
import org.jetbrains.kotlin.library.metadata.klibModuleOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
internal interface LlvmImports {
|
internal interface LlvmImports {
|
||||||
fun add(origin: CompiledKlibModuleOrigin, onlyBitcode: Boolean = false)
|
data class LibraryFile(val library: KotlinLibrary, val fqName: String, val filePath: String)
|
||||||
|
|
||||||
|
fun add(origin: CompiledKlibFileOrigin, onlyBitcode: Boolean = false)
|
||||||
fun bitcodeIsUsed(library: KonanLibrary): Boolean
|
fun bitcodeIsUsed(library: KonanLibrary): Boolean
|
||||||
fun nativeDependenciesAreUsed(library: KonanLibrary): Boolean
|
fun nativeDependenciesAreUsed(library: KonanLibrary): Boolean
|
||||||
|
fun usedBitcode(): List<LibraryFile>
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKlibModuleOrigin
|
internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKlibModuleOrigin
|
||||||
|
|||||||
+6
-10
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.getClass
|
import org.jetbrains.kotlin.ir.types.getClass
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
|
||||||
import org.jetbrains.kotlin.ir.util.findAnnotation
|
import org.jetbrains.kotlin.ir.util.findAnnotation
|
||||||
|
|
||||||
internal enum class IntrinsicType {
|
internal enum class IntrinsicType {
|
||||||
@@ -440,21 +439,18 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
|
|||||||
val functionReturnType = LlvmRetType(llvm.int8PtrType)
|
val functionReturnType = LlvmRetType(llvm.int8PtrType)
|
||||||
val functionParameterTypes = listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType))
|
val functionParameterTypes = listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType))
|
||||||
|
|
||||||
val libobjc = context.standardLlvmSymbolsOrigin
|
val normalMessenger = codegen.llvm.externalNativeRuntimeFunction(
|
||||||
val normalMessenger = codegen.llvm.externalFunction(LlvmFunctionProto(
|
|
||||||
"objc_msgSend$messengerNameSuffix",
|
"objc_msgSend$messengerNameSuffix",
|
||||||
functionReturnType,
|
functionReturnType,
|
||||||
functionParameterTypes,
|
functionParameterTypes,
|
||||||
isVararg = true,
|
isVararg = true
|
||||||
origin = libobjc
|
)
|
||||||
))
|
val superMessenger = codegen.llvm.externalNativeRuntimeFunction(
|
||||||
val superMessenger = codegen.llvm.externalFunction(LlvmFunctionProto(
|
|
||||||
"objc_msgSendSuper$messengerNameSuffix",
|
"objc_msgSendSuper$messengerNameSuffix",
|
||||||
functionReturnType,
|
functionReturnType,
|
||||||
functionParameterTypes,
|
functionParameterTypes,
|
||||||
isVararg = true,
|
isVararg = true
|
||||||
origin = libobjc
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val superClass = args.single()
|
val superClass = args.single()
|
||||||
val messenger = LLVMBuildSelect(builder,
|
val messenger = LLVMBuildSelect(builder,
|
||||||
|
|||||||
+20
-19
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_STANDA
|
|||||||
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_STATIC_THREAD_LOCAL_INITIALIZER
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
@@ -1627,21 +1628,18 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
} else {
|
} else {
|
||||||
// e.g. ObjCObject, ObjCObjectBase etc.
|
// e.g. ObjCObject, ObjCObjectBase etc.
|
||||||
if (dstClass.isObjCMetaClass()) {
|
if (dstClass.isObjCMetaClass()) {
|
||||||
val isClassProto = LlvmFunctionProto(
|
val isClass = llvm.externalNativeRuntimeFunction(
|
||||||
"object_isClass",
|
"object_isClass",
|
||||||
LlvmRetType(llvm.int8Type),
|
LlvmRetType(llvm.int8Type),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType))
|
||||||
origin = context.standardLlvmSymbolsOrigin
|
|
||||||
)
|
)
|
||||||
val isClass = llvm.externalFunction(isClassProto)
|
|
||||||
call(isClass, listOf(objCObject)).let {
|
call(isClass, listOf(objCObject)).let {
|
||||||
functionGenerationContext.icmpNe(it, llvm.int8(0))
|
functionGenerationContext.icmpNe(it, llvm.int8(0))
|
||||||
}
|
}
|
||||||
} else if (dstClass.isObjCProtocolClass()) {
|
} else if (dstClass.isObjCProtocolClass()) {
|
||||||
// Note: it is not clear whether this class should be looked up this way.
|
// Note: it is not clear whether this class should be looked up this way.
|
||||||
// clang does the same, however swiftc uses dynamic lookup.
|
// clang does the same, however swiftc uses dynamic lookup.
|
||||||
val protocolClass =
|
val protocolClass = functionGenerationContext.getObjCClass("Protocol", CompiledKlibFileOrigin.StdlibRuntime)
|
||||||
functionGenerationContext.getObjCClass("Protocol", context.standardLlvmSymbolsOrigin)
|
|
||||||
call(
|
call(
|
||||||
llvm.Kotlin_Interop_IsObjectKindOfClass,
|
llvm.Kotlin_Interop_IsObjectKindOfClass,
|
||||||
listOf(objCObject, protocolClass)
|
listOf(objCObject, protocolClass)
|
||||||
@@ -2496,7 +2494,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
val protocolGetterProto = LlvmFunctionProto(
|
val protocolGetterProto = LlvmFunctionProto(
|
||||||
protocolGetterName,
|
protocolGetterName,
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
origin = irClass.llvmSymbolOrigin,
|
origin = generationState.computeOrigin(irClass),
|
||||||
independent = true // Protocol is header-only declaration.
|
independent = true // Protocol is header-only declaration.
|
||||||
)
|
)
|
||||||
val protocolGetter = llvm.externalFunction(protocolGetterProto)
|
val protocolGetter = llvm.externalFunction(protocolGetterProto)
|
||||||
@@ -2679,7 +2677,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||||
// When some dynamic caches are used, we consider that stdlib is in the dynamic cache as well.
|
// When some dynamic caches are used, we consider that stdlib is in the dynamic cache as well.
|
||||||
// Runtime is linked into stdlib module only, so import runtime global from it.
|
// Runtime is linked into stdlib module only, so import runtime global from it.
|
||||||
val global = codegen.importGlobal(name, value.llvmType, context.standardLlvmSymbolsOrigin)
|
val global = codegen.importNativeRuntimeGlobal(name, value.llvmType)
|
||||||
val initializer = generateFunctionNoRuntime(codegen, functionType(llvm.voidType, false), "") {
|
val initializer = generateFunctionNoRuntime(codegen, functionType(llvm.voidType, false), "") {
|
||||||
store(value.llvm, global)
|
store(value.llvm, global)
|
||||||
ret(null)
|
ret(null)
|
||||||
@@ -2689,7 +2687,7 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
|
|
||||||
llvm.otherStaticInitializers += initializer
|
llvm.otherStaticInitializers += initializer
|
||||||
} else {
|
} else {
|
||||||
generationState.llvmImports.add(context.standardLlvmSymbolsOrigin)
|
generationState.llvmImports.add(CompiledKlibFileOrigin.StdlibRuntime)
|
||||||
// Define a strong runtime global. It'll overrule a weak global defined in a statically linked runtime.
|
// Define a strong runtime global. It'll overrule a weak global defined in a statically linked runtime.
|
||||||
val global = llvm.staticData.placeGlobal(name, value, true)
|
val global = llvm.staticData.placeGlobal(name, value, true)
|
||||||
|
|
||||||
@@ -2759,11 +2757,9 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
//-------------------------------------------------------------------------//
|
//-------------------------------------------------------------------------//
|
||||||
fun appendStaticInitializers() {
|
fun appendStaticInitializers() {
|
||||||
// Note: the list of libraries is topologically sorted (in order for initializers to be called correctly).
|
// Note: the list of libraries is topologically sorted (in order for initializers to be called correctly).
|
||||||
val libraries = (llvm.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */)
|
val dependencies = (llvm.allBitcodeDependencies + listOf(null)/* Null for "current" non-library module */)
|
||||||
|
|
||||||
val libraryToInitializers = libraries.associateWith {
|
val libraryToInitializers = dependencies.associate { it?.library to mutableListOf<LLVMValueRef>() }
|
||||||
mutableListOf<LLVMValueRef>()
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm.irStaticInitializers.forEach {
|
llvm.irStaticInitializers.forEach {
|
||||||
val library = it.konanLibrary
|
val library = it.konanLibrary
|
||||||
@@ -2783,7 +2779,8 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
kVoidFuncType
|
kVoidFuncType
|
||||||
).also { LLVMSetLinkage(it, LLVMLinkage.LLVMExternalLinkage) }
|
).also { LLVMSetLinkage(it, LLVMLinkage.LLVMExternalLinkage) }
|
||||||
|
|
||||||
val ctorFunctions = libraries.flatMap { library ->
|
val ctorFunctions = dependencies.flatMap { dependency ->
|
||||||
|
val library = dependency?.library
|
||||||
val initializers = libraryToInitializers.getValue(library)
|
val initializers = libraryToInitializers.getValue(library)
|
||||||
|
|
||||||
val ctorName = when {
|
val ctorName = when {
|
||||||
@@ -2811,12 +2808,16 @@ internal class CodeGeneratorVisitor(val generationState: NativeGenerationState,
|
|||||||
val cache = context.config.cachedLibraries.getLibraryCache(library)
|
val cache = context.config.cachedLibraries.getLibraryCache(library)
|
||||||
?: error("Library $library is expected to be cached")
|
?: error("Library $library is expected to be cached")
|
||||||
|
|
||||||
when (cache.granularity) {
|
when (cache) {
|
||||||
CachedLibraries.Granularity.MODULE -> listOf(addCtorFunction(ctorName))
|
is CachedLibraries.Cache.Monolithic -> listOf(addCtorFunction(ctorName))
|
||||||
CachedLibraries.Granularity.FILE -> {
|
is CachedLibraries.Cache.PerFile -> {
|
||||||
context.irLinker.klibToModuleDeserializerMap[library]!!.sortedFileIds.map {
|
val files = when (dependency) {
|
||||||
addCtorFunction(fileCtorName(library.uniqueName, it))
|
is Llvm.CachedBitcodeDependency.WholeModule ->
|
||||||
|
context.irLinker.klibToModuleDeserializerMap[library]!!.sortedFileIds
|
||||||
|
is Llvm.CachedBitcodeDependency.CertainFiles ->
|
||||||
|
dependency.files
|
||||||
}
|
}
|
||||||
|
files.map { addCtorFunction(fileCtorName(library.uniqueName, it)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -28,11 +28,11 @@ internal class KotlinObjCClassInfoGenerator(override val generationState: Native
|
|||||||
val classMethods = companionObject?.generateMethodDescs().orEmpty()
|
val classMethods = companionObject?.generateMethodDescs().orEmpty()
|
||||||
|
|
||||||
val superclassName = irClass.getSuperClassNotAny()!!.let {
|
val superclassName = irClass.getSuperClassNotAny()!!.let {
|
||||||
llvm.imports.add(it.llvmSymbolOrigin)
|
llvm.imports.add(generationState.computeOrigin(it))
|
||||||
it.descriptor.getExternalObjCClassBinaryName()
|
it.descriptor.getExternalObjCClassBinaryName()
|
||||||
}
|
}
|
||||||
val protocolNames = irClass.getSuperInterfaces().map {
|
val protocolNames = irClass.getSuperInterfaces().map {
|
||||||
llvm.imports.add(it.llvmSymbolOrigin)
|
llvm.imports.add(generationState.computeOrigin(it))
|
||||||
it.name.asString().removeSuffix("Protocol")
|
it.name.asString().removeSuffix("Protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ internal fun CodeGenerator.kotlinObjCClassInfo(irClass: IrClass): LLVMValueRef {
|
|||||||
importGlobal(
|
importGlobal(
|
||||||
irClass.kotlinObjCClassInfoSymbolName,
|
irClass.kotlinObjCClassInfoSymbolName,
|
||||||
runtime.kotlinObjCClassInfo,
|
runtime.kotlinObjCClassInfo,
|
||||||
origin = irClass.llvmSymbolOrigin
|
generationState.computeOrigin(irClass)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal
|
llvmDeclarations.forClass(irClass).objCDeclarations!!.classInfoGlobal.llvmGlobal
|
||||||
|
|||||||
+2
-3
@@ -104,9 +104,8 @@ internal class KotlinStaticData(override val generationState: NativeGenerationSt
|
|||||||
UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner
|
UniqueKind.EMPTY_ARRAY -> context.ir.symbols.array.owner
|
||||||
}
|
}
|
||||||
return if (isExternal(descriptor)) {
|
return if (isExternal(descriptor)) {
|
||||||
constPointer(importGlobal(
|
constPointer(
|
||||||
kind.llvmName, runtime.objHeaderType, origin = descriptor.llvmSymbolOrigin
|
importGlobal(kind.llvmName, runtime.objHeaderType, generationState.computeOrigin(descriptor)))
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
generationState.llvmDeclarations.forUnique(kind).pointer
|
generationState.llvmDeclarations.forUnique(kind).pointer
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -12,13 +12,14 @@ import llvm.*
|
|||||||
import org.jetbrains.kotlin.backend.konan.Context
|
import org.jetbrains.kotlin.backend.konan.Context
|
||||||
import org.jetbrains.kotlin.backend.konan.RuntimeNames
|
import org.jetbrains.kotlin.backend.konan.RuntimeNames
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
import org.jetbrains.kotlin.ir.types.isNothing
|
import org.jetbrains.kotlin.ir.types.isNothing
|
||||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||||
import org.jetbrains.kotlin.ir.util.isThrowable
|
import org.jetbrains.kotlin.ir.util.isThrowable
|
||||||
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add attributes to LLVM function declaration and its invocation.
|
* Add attributes to LLVM function declaration and its invocation.
|
||||||
@@ -156,14 +157,14 @@ internal class LlvmFunctionProto(
|
|||||||
returnType: LlvmRetType,
|
returnType: LlvmRetType,
|
||||||
parameterTypes: List<LlvmParamType> = emptyList(),
|
parameterTypes: List<LlvmParamType> = emptyList(),
|
||||||
functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
|
functionAttributes: List<LlvmFunctionAttribute> = emptyList(),
|
||||||
val origin: CompiledKlibModuleOrigin,
|
val origin: CompiledKlibFileOrigin,
|
||||||
isVararg: Boolean = false,
|
isVararg: Boolean = false,
|
||||||
val independent: Boolean = false,
|
val independent: Boolean = false,
|
||||||
) : LlvmFunctionSignature(returnType, parameterTypes, isVararg, functionAttributes) {
|
) : LlvmFunctionSignature(returnType, parameterTypes, isVararg, functionAttributes) {
|
||||||
constructor(
|
constructor(
|
||||||
name: String,
|
name: String,
|
||||||
signature: LlvmFunctionSignature,
|
signature: LlvmFunctionSignature,
|
||||||
origin: CompiledKlibModuleOrigin,
|
origin: CompiledKlibFileOrigin,
|
||||||
independent: Boolean = false,
|
independent: Boolean = false,
|
||||||
) : this(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, origin, signature.isVararg, independent)
|
) : this(name, signature.returnType, signature.parameterTypes, signature.functionAttributes, origin, signature.isVararg, independent)
|
||||||
|
|
||||||
@@ -172,7 +173,7 @@ internal class LlvmFunctionProto(
|
|||||||
returnType = contextUtils.getLlvmFunctionReturnType(irFunction),
|
returnType = contextUtils.getLlvmFunctionReturnType(irFunction),
|
||||||
parameterTypes = contextUtils.getLlvmFunctionParameterTypes(irFunction),
|
parameterTypes = contextUtils.getLlvmFunctionParameterTypes(irFunction),
|
||||||
functionAttributes = inferFunctionAttributes(contextUtils, irFunction),
|
functionAttributes = inferFunctionAttributes(contextUtils, irFunction),
|
||||||
origin = irFunction.llvmSymbolOrigin,
|
origin = contextUtils.generationState.computeOrigin(irFunction),
|
||||||
independent = irFunction.hasAnnotation(RuntimeNames.independent)
|
independent = irFunction.hasAnnotation(RuntimeNames.independent)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-9
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
|
|||||||
|
|
||||||
import kotlinx.cinterop.*
|
import kotlinx.cinterop.*
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
|
|
||||||
internal val LLVMValueRef.type: LLVMTypeRef
|
internal val LLVMValueRef.type: LLVMTypeRef
|
||||||
get() = LLVMTypeOf(this)!!
|
get() = LLVMTypeOf(this)!!
|
||||||
@@ -170,19 +170,25 @@ internal fun ContextUtils.addGlobal(name: String, type: LLVMTypeRef, isExported:
|
|||||||
return LLVMAddGlobal(llvm.module, type, name)!!
|
return LLVMAddGlobal(llvm.module, type, name)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibModuleOrigin): LLVMValueRef {
|
private fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef): LLVMValueRef {
|
||||||
llvm.imports.add(origin)
|
|
||||||
|
|
||||||
val found = LLVMGetNamedGlobal(llvm.module, name)
|
val found = LLVMGetNamedGlobal(llvm.module, name)
|
||||||
return if (found != null) {
|
return if (found == null)
|
||||||
assert (getGlobalType(found) == type)
|
|
||||||
assert (LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
|
|
||||||
found
|
|
||||||
} else {
|
|
||||||
addGlobal(name, type, isExported = false)
|
addGlobal(name, type, isExported = false)
|
||||||
|
else {
|
||||||
|
require(getGlobalType(found) == type)
|
||||||
|
require(LLVMGetInitializer(found) == null) { "$name is already declared in the current module" }
|
||||||
|
found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun ContextUtils.importGlobal(name: String, type: LLVMTypeRef, origin: CompiledKlibFileOrigin) =
|
||||||
|
importGlobal(name, type).also { llvm.imports.add(origin) }
|
||||||
|
|
||||||
|
internal fun ContextUtils.importObjCGlobal(name: String, type: LLVMTypeRef) = importGlobal(name, type)
|
||||||
|
|
||||||
|
internal fun ContextUtils.importNativeRuntimeGlobal(name: String, type: LLVMTypeRef) =
|
||||||
|
importGlobal(name, type, CompiledKlibFileOrigin.StdlibRuntime)
|
||||||
|
|
||||||
internal abstract class AddressAccess {
|
internal abstract class AddressAccess {
|
||||||
abstract fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef
|
abstract fun getAddress(generationContext: FunctionGenerationContext?): LLVMValueRef
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.builtins.PrimitiveType
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
|
|
||||||
internal class RTTIGenerator(override val generationState: NativeGenerationState) : ContextUtils {
|
internal class RTTIGenerator(override val generationState: NativeGenerationState) : ContextUtils {
|
||||||
|
|
||||||
@@ -147,10 +146,8 @@ internal class RTTIGenerator(override val generationState: NativeGenerationState
|
|||||||
staticData.kotlinStringLiteral(string)
|
staticData.kotlinStringLiteral(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val EXPORT_TYPE_INFO_FQ_NAME = FqName.fromSegments(listOf("kotlin", "native", "internal", "ExportTypeInfo"))
|
|
||||||
|
|
||||||
private fun exportTypeInfoIfRequired(irClass: IrClass, typeInfoGlobal: LLVMValueRef?) {
|
private fun exportTypeInfoIfRequired(irClass: IrClass, typeInfoGlobal: LLVMValueRef?) {
|
||||||
val annotation = irClass.annotations.findAnnotation(EXPORT_TYPE_INFO_FQ_NAME)
|
val annotation = irClass.annotations.findAnnotation(RuntimeNames.exportTypeInfoAnnotation)
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
val name = annotation.getAnnotationStringValue()!!
|
val name = annotation.getAnnotationStringValue()!!
|
||||||
// TODO: use LLVMAddAlias.
|
// TODO: use LLVMAddAlias.
|
||||||
|
|||||||
+18
-26
@@ -28,48 +28,40 @@ internal open class ObjCCodeGenerator(val codegen: CodeGenerator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val objcMsgSend = constPointer(
|
private val objcMsgSend = constPointer(
|
||||||
llvm.externalFunction(LlvmFunctionProto(
|
llvm.externalNativeRuntimeFunction(
|
||||||
"objc_msgSend",
|
"objc_msgSend",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType), LlvmParamType(llvm.int8PtrType)),
|
||||||
isVararg = true,
|
isVararg = true
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
).llvmValue
|
||||||
)).llvmValue
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val objcRelease = run {
|
val objcRelease = llvm.externalNativeRuntimeFunction(
|
||||||
val proto = LlvmFunctionProto(
|
"llvm.objc.release",
|
||||||
"llvm.objc.release",
|
LlvmRetType(llvm.voidType),
|
||||||
LlvmRetType(llvm.voidType),
|
listOf(LlvmParamType(llvm.int8PtrType)),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmFunctionAttribute.NoUnwind)
|
||||||
listOf(LlvmFunctionAttribute.NoUnwind),
|
)
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
|
||||||
)
|
|
||||||
llvm.externalFunction(proto)
|
|
||||||
}
|
|
||||||
|
|
||||||
val objcAlloc = llvm.externalFunction(LlvmFunctionProto(
|
val objcAlloc = llvm.externalNativeRuntimeFunction(
|
||||||
"objc_alloc",
|
"objc_alloc",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType))
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val objcAutoreleaseReturnValue = llvm.externalFunction(LlvmFunctionProto(
|
val objcAutoreleaseReturnValue = llvm.externalNativeRuntimeFunction(
|
||||||
"llvm.objc.autoreleaseReturnValue",
|
"llvm.objc.autoreleaseReturnValue",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType)),
|
||||||
listOf(LlvmFunctionAttribute.NoUnwind),
|
listOf(LlvmFunctionAttribute.NoUnwind)
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val objcRetainAutoreleasedReturnValue = llvm.externalFunction(LlvmFunctionProto(
|
val objcRetainAutoreleasedReturnValue = llvm.externalNativeRuntimeFunction(
|
||||||
"llvm.objc.retainAutoreleasedReturnValue",
|
"llvm.objc.retainAutoreleasedReturnValue",
|
||||||
LlvmRetType(llvm.int8PtrType),
|
LlvmRetType(llvm.int8PtrType),
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
listOf(LlvmParamType(llvm.int8PtrType)),
|
||||||
listOf(LlvmFunctionAttribute.NoUnwind),
|
listOf(LlvmFunctionAttribute.NoUnwind)
|
||||||
origin = context.stdlibModule.llvmSymbolOrigin
|
)
|
||||||
))
|
|
||||||
|
|
||||||
val objcRetainAutoreleasedReturnValueMarker: LLVMValueRef? by lazy {
|
val objcRetainAutoreleasedReturnValueMarker: LLVMValueRef? by lazy {
|
||||||
// See emitAutoreleasedReturnValueMarker in Clang.
|
// See emitAutoreleasedReturnValueMarker in Clang.
|
||||||
|
|||||||
+3
-8
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.konan.llvm.objc
|
|||||||
|
|
||||||
import llvm.*
|
import llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides methods to generate Objective-C RTTI and other data.
|
* This class provides methods to generate Objective-C RTTI and other data.
|
||||||
@@ -75,18 +74,14 @@ internal class ObjCDataGenerator(val codegen: CodeGenerator) {
|
|||||||
val globalName = prefix + name
|
val globalName = prefix + name
|
||||||
|
|
||||||
// TODO: refactor usages and use [Global] class.
|
// TODO: refactor usages and use [Global] class.
|
||||||
val llvmGlobal = LLVMGetNamedGlobal(llvm.module, globalName) ?:
|
val llvmGlobal = LLVMGetNamedGlobal(llvm.module, globalName)
|
||||||
codegen.importGlobal(globalName, classObjectType, CurrentKlibModuleOrigin)
|
?: codegen.importObjCGlobal(globalName, classObjectType)
|
||||||
|
|
||||||
return constPointer(llvmGlobal)
|
return constPointer(llvmGlobal)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val emptyCache = constPointer(
|
private val emptyCache = constPointer(
|
||||||
codegen.importGlobal(
|
codegen.importObjCGlobal("_objc_empty_cache", codegen.runtime.objCCache)
|
||||||
"_objc_empty_cache",
|
|
||||||
codegen.runtime.objCCache,
|
|
||||||
CurrentKlibModuleOrigin
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun emitEmptyClass(name: String, superName: String) {
|
fun emitEmptyClass(name: String, superName: String) {
|
||||||
|
|||||||
+6
-15
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
|
|||||||
import org.jetbrains.kotlin.backend.konan.objcexport.BlockPointerBridge
|
import org.jetbrains.kotlin.backend.konan.objcexport.BlockPointerBridge
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.util.simpleFunctions
|
import org.jetbrains.kotlin.ir.util.simpleFunctions
|
||||||
import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin
|
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
internal fun ObjCExportCodeGeneratorBase.generateBlockToKotlinFunctionConverter(
|
||||||
@@ -315,11 +314,7 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
|||||||
ret(llvm.kNullInt8Ptr)
|
ret(llvm.kNullInt8Ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isa = codegen.importGlobal(
|
val isa = codegen.importObjCGlobal("_NSConcreteStackBlock", llvm.int8PtrType)
|
||||||
"_NSConcreteStackBlock",
|
|
||||||
llvm.int8PtrType,
|
|
||||||
CurrentKlibModuleOrigin
|
|
||||||
)
|
|
||||||
|
|
||||||
val flags = llvm.int32((1 shl 25) or (1 shl 30) or (1 shl 31))
|
val flags = llvm.int32((1 shl 25) or (1 shl 30) or (1 shl 31))
|
||||||
val reserved = llvm.int32(0)
|
val reserved = llvm.int32(0)
|
||||||
@@ -350,12 +345,8 @@ internal class BlockGenerator(private val codegen: CodeGenerator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val ObjCExportCodeGeneratorBase.retainBlock: LlvmCallable
|
private val ObjCExportCodeGeneratorBase.retainBlock: LlvmCallable
|
||||||
get() {
|
get() = llvm.externalNativeRuntimeFunction(
|
||||||
val functionProto = LlvmFunctionProto(
|
"objc_retainBlock",
|
||||||
"objc_retainBlock",
|
LlvmRetType(llvm.int8PtrType),
|
||||||
LlvmRetType(llvm.int8PtrType),
|
listOf(LlvmParamType(llvm.int8PtrType))
|
||||||
listOf(LlvmParamType(llvm.int8PtrType)),
|
)
|
||||||
origin = CurrentKlibModuleOrigin
|
|
||||||
)
|
|
||||||
return llvm.externalFunction(functionProto)
|
|
||||||
}
|
|
||||||
+10
-24
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenFunctions
|
|||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
|
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.isUnit
|
import org.jetbrains.kotlin.backend.konan.ir.isUnit
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.llvmSymbolOrigin
|
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.superClasses
|
import org.jetbrains.kotlin.backend.konan.ir.superClasses
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.*
|
import org.jetbrains.kotlin.backend.konan.llvm.*
|
||||||
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
|
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCCodeGenerator
|
||||||
@@ -26,6 +25,7 @@ import org.jetbrains.kotlin.backend.konan.objcexport.*
|
|||||||
import org.jetbrains.kotlin.backend.konan.serialization.resolveFakeOverrideMaybeAbstract
|
import org.jetbrains.kotlin.backend.konan.serialization.resolveFakeOverrideMaybeAbstract
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.library.metadata.CompiledKlibFileOrigin
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||||
@@ -40,8 +40,6 @@ import org.jetbrains.kotlin.ir.types.isUnit
|
|||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.konan.target.AppleConfigurables
|
import org.jetbrains.kotlin.konan.target.AppleConfigurables
|
||||||
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
|
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
|
||||||
import org.jetbrains.kotlin.library.metadata.CompiledKlibModuleOrigin
|
|
||||||
import org.jetbrains.kotlin.library.metadata.CurrentKlibModuleOrigin
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors
|
import org.jetbrains.kotlin.psi2ir.descriptors.IrBuiltInsOverDescriptors
|
||||||
import org.jetbrains.kotlin.utils.DFS
|
import org.jetbrains.kotlin.utils.DFS
|
||||||
@@ -223,15 +221,6 @@ internal open class ObjCExportCodeGeneratorBase(codegen: CodeGenerator) : ObjCCo
|
|||||||
|
|
||||||
val rttiGenerator = RTTIGenerator(generationState)
|
val rttiGenerator = RTTIGenerator(generationState)
|
||||||
|
|
||||||
private val objcTerminate: LlvmCallable by lazy {
|
|
||||||
llvm.externalFunction(LlvmFunctionProto(
|
|
||||||
"objc_terminate",
|
|
||||||
LlvmRetType(llvm.voidType),
|
|
||||||
functionAttributes = listOf(LlvmFunctionAttribute.NoUnwind),
|
|
||||||
origin = CurrentKlibModuleOrigin
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dispose() {
|
fun dispose() {
|
||||||
rttiGenerator.dispose()
|
rttiGenerator.dispose()
|
||||||
}
|
}
|
||||||
@@ -478,7 +467,7 @@ internal class ObjCExportCodeGenerator(
|
|||||||
replaceExternalWeakOrCommonGlobal(
|
replaceExternalWeakOrCommonGlobal(
|
||||||
"Kotlin_ObjCInterop_uniquePrefix",
|
"Kotlin_ObjCInterop_uniquePrefix",
|
||||||
codegen.staticData.cStringLiteral(namer.topLevelNamePrefix),
|
codegen.staticData.cStringLiteral(namer.topLevelNamePrefix),
|
||||||
context.standardLlvmSymbolsOrigin
|
CompiledKlibFileOrigin.StdlibRuntime
|
||||||
)
|
)
|
||||||
|
|
||||||
emitSelectorsHolder()
|
emitSelectorsHolder()
|
||||||
@@ -524,7 +513,7 @@ internal class ObjCExportCodeGenerator(
|
|||||||
val sortedAdaptersPointer = staticData.placeGlobalConstArray("", type, sortedAdapters)
|
val sortedAdaptersPointer = staticData.placeGlobalConstArray("", type, sortedAdapters)
|
||||||
|
|
||||||
// Note: this globals replace runtime globals with weak linkage:
|
// Note: this globals replace runtime globals with weak linkage:
|
||||||
val origin = context.standardLlvmSymbolsOrigin
|
val origin = CompiledKlibFileOrigin.StdlibRuntime
|
||||||
replaceExternalWeakOrCommonGlobal(prefix, sortedAdaptersPointer, origin)
|
replaceExternalWeakOrCommonGlobal(prefix, sortedAdaptersPointer, origin)
|
||||||
replaceExternalWeakOrCommonGlobal("${prefix}Num", llvm.constInt32(sortedAdapters.size), origin)
|
replaceExternalWeakOrCommonGlobal("${prefix}Num", llvm.constInt32(sortedAdapters.size), origin)
|
||||||
}
|
}
|
||||||
@@ -535,9 +524,9 @@ internal class ObjCExportCodeGenerator(
|
|||||||
|
|
||||||
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||||
replaceExternalWeakOrCommonGlobal(
|
replaceExternalWeakOrCommonGlobal(
|
||||||
"Kotlin_ObjCExport_initTypeAdapters",
|
"Kotlin_ObjCExport_initTypeAdapters",
|
||||||
llvm.constInt1(true),
|
llvm.constInt1(true),
|
||||||
context.standardLlvmSymbolsOrigin
|
CompiledKlibFileOrigin.StdlibRuntime
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -704,7 +693,7 @@ internal class ObjCExportCodeGenerator(
|
|||||||
private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(
|
private fun ObjCExportCodeGenerator.replaceExternalWeakOrCommonGlobal(
|
||||||
name: String,
|
name: String,
|
||||||
value: ConstValue,
|
value: ConstValue,
|
||||||
origin: CompiledKlibModuleOrigin
|
origin: CompiledKlibFileOrigin
|
||||||
) {
|
) {
|
||||||
// TODO: A similar mechanism is used in `IrToBitcode.overrideRuntimeGlobal`. Consider merging them.
|
// TODO: A similar mechanism is used in `IrToBitcode.overrideRuntimeGlobal`. Consider merging them.
|
||||||
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
if (generationState.llvmModuleSpecification.importsKotlinDeclarationsFromOtherSharedLibraries()) {
|
||||||
@@ -742,7 +731,7 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo(
|
|||||||
replaceExternalWeakOrCommonGlobal(
|
replaceExternalWeakOrCommonGlobal(
|
||||||
irClass.writableTypeInfoSymbolName,
|
irClass.writableTypeInfoSymbolName,
|
||||||
writableTypeInfoValue,
|
writableTypeInfoValue,
|
||||||
irClass.llvmSymbolOrigin
|
generationState.computeOrigin(irClass)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
setOwnWritableTypeInfo(irClass, writableTypeInfoValue)
|
setOwnWritableTypeInfo(irClass, writableTypeInfoValue)
|
||||||
@@ -924,11 +913,8 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
|
|||||||
|
|
||||||
private fun ObjCExportCodeGenerator.emitCollectionConverters() {
|
private fun ObjCExportCodeGenerator.emitCollectionConverters() {
|
||||||
|
|
||||||
fun importConverter(name: String): ConstPointer = constPointer(llvm.externalFunction(LlvmFunctionProto(
|
fun importConverter(name: String): ConstPointer =
|
||||||
name,
|
constPointer(llvm.externalNativeRuntimeFunction(name, kotlinToObjCFunctionType).llvmValue)
|
||||||
kotlinToObjCFunctionType,
|
|
||||||
origin = CurrentKlibModuleOrigin
|
|
||||||
)).llvmValue)
|
|
||||||
|
|
||||||
setObjCExportTypeInfo(
|
setObjCExportTypeInfo(
|
||||||
symbols.list.owner,
|
symbols.list.owner,
|
||||||
|
|||||||
+39
-21
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.konan.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_FUNCTION_CLASS
|
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_FUNCTION_CLASS
|
||||||
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
import org.jetbrains.kotlin.backend.konan.NativeGenerationState
|
||||||
|
import org.jetbrains.kotlin.backend.konan.KonanFqNames
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
|
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
|
||||||
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr
|
import org.jetbrains.kotlin.backend.konan.serialization.KonanManglerIr
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
@@ -21,32 +22,49 @@ internal class CacheInfoBuilder(
|
|||||||
private val moduleDeserializer: KonanIrLinker.KonanPartialModuleDeserializer,
|
private val moduleDeserializer: KonanIrLinker.KonanPartialModuleDeserializer,
|
||||||
private val irModule: IrModuleFragment
|
private val irModule: IrModuleFragment
|
||||||
) {
|
) {
|
||||||
fun build() = irModule.acceptChildrenVoid(object : IrElementVisitorVoid {
|
fun build() = irModule.files.forEach { irFile ->
|
||||||
override fun visitElement(element: IrElement) {
|
var hasEagerlyInitializedProperties = false
|
||||||
element.acceptChildrenVoid(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
declaration.acceptChildrenVoid(this)
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
if (!declaration.isInterface && !declaration.isLocal
|
|
||||||
&& declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS
|
|
||||||
) {
|
|
||||||
val declaredFields = generationState.context.getLayoutBuilder(declaration).getDeclaredFields()
|
|
||||||
generationState.classFields.add(moduleDeserializer.buildClassFields(declaration, declaredFields))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction) {
|
override fun visitClass(declaration: IrClass) {
|
||||||
// Don't need to visit the children here: classes would be all local and wouldn't be handled anyway,
|
declaration.acceptChildrenVoid(this)
|
||||||
// as for functions - both their callees will be handled and inline bodies will be built for the top function.
|
|
||||||
|
|
||||||
if (!declaration.isFakeOverride && declaration.isInline && declaration.isExported) {
|
if (!declaration.isInterface && !declaration.isLocal
|
||||||
generationState.inlineFunctionBodies.add(moduleDeserializer.buildInlineFunctionReference(declaration))
|
&& declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS
|
||||||
trackCallees(declaration)
|
) {
|
||||||
|
val declaredFields = generationState.context.getLayoutBuilder(declaration).getDeclaredFields()
|
||||||
|
generationState.classFields.add(moduleDeserializer.buildClassFields(declaration, declaredFields))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
// Don't need to visit the children here: classes would be all local and wouldn't be handled anyway,
|
||||||
|
// as for functions - both their callees will be handled and inline bodies will be built for the top function.
|
||||||
|
|
||||||
|
if (!declaration.isFakeOverride && declaration.isInline && declaration.isExported) {
|
||||||
|
generationState.inlineFunctionBodies.add(moduleDeserializer.buildInlineFunctionReference(declaration))
|
||||||
|
trackCallees(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitProperty(declaration: IrProperty) {
|
||||||
|
declaration.acceptChildrenVoid(this)
|
||||||
|
|
||||||
|
if (declaration.parent == irFile
|
||||||
|
&& declaration.hasAnnotation(KonanFqNames.eagerInitialization)
|
||||||
|
) {
|
||||||
|
hasEagerlyInitializedProperties = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (hasEagerlyInitializedProperties)
|
||||||
|
generationState.eagerInitializedFiles.add(moduleDeserializer.buildEagerInitializedFile(irFile))
|
||||||
|
}
|
||||||
|
|
||||||
private val IrDeclaration.isExported
|
private val IrDeclaration.isExported
|
||||||
get() = with(KonanManglerIr) { isExported(compatibleMode = moduleDeserializer.compatibilityMode.oldSignatures) }
|
get() = with(KonanManglerIr) { isExported(compatibleMode = moduleDeserializer.compatibilityMode.oldSignatures) }
|
||||||
|
|||||||
+5
-2
@@ -51,6 +51,7 @@ internal class CachesAbiSupport(mapping: NativeMapping, private val irFactory: I
|
|||||||
returnType = irClass.parentAsClass.defaultType
|
returnType = irClass.parentAsClass.defaultType
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = irClass.getPackageFragment()
|
parent = irClass.getPackageFragment()
|
||||||
|
attributeOwnerId = irClass // To be able to get the file.
|
||||||
|
|
||||||
addValueParameter {
|
addValueParameter {
|
||||||
name = Name.identifier("innerClass")
|
name = Name.identifier("innerClass")
|
||||||
@@ -73,6 +74,7 @@ internal class CachesAbiSupport(mapping: NativeMapping, private val irFactory: I
|
|||||||
returnType = actualField.type
|
returnType = actualField.type
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = irProperty.getPackageFragment()
|
parent = irProperty.getPackageFragment()
|
||||||
|
attributeOwnerId = irProperty // To be able to get the file.
|
||||||
|
|
||||||
(owner as? IrClass)?.let {
|
(owner as? IrClass)?.let {
|
||||||
addValueParameter {
|
addValueParameter {
|
||||||
@@ -150,6 +152,7 @@ internal class ImportCachesAbiTransformer(val generationState: NativeGenerationS
|
|||||||
private val cachesAbiSupport = generationState.context.cachesAbiSupport
|
private val cachesAbiSupport = generationState.context.cachesAbiSupport
|
||||||
private val innerClassesSupport = generationState.context.innerClassesSupport
|
private val innerClassesSupport = generationState.context.innerClassesSupport
|
||||||
private val llvmImports = generationState.llvmImports
|
private val llvmImports = generationState.llvmImports
|
||||||
|
private val irLinker = generationState.context.irLinker
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
irFile.transformChildrenVoid(this)
|
irFile.transformChildrenVoid(this)
|
||||||
@@ -168,7 +171,7 @@ internal class ImportCachesAbiTransformer(val generationState: NativeGenerationS
|
|||||||
|
|
||||||
irClass?.isInner == true && innerClassesSupport.getOuterThisField(irClass) == field -> {
|
irClass?.isInner == true && innerClassesSupport.getOuterThisField(irClass) == field -> {
|
||||||
val accessor = cachesAbiSupport.getOuterThisAccessor(irClass)
|
val accessor = cachesAbiSupport.getOuterThisAccessor(irClass)
|
||||||
llvmImports.add(irClass.llvmSymbolOrigin)
|
llvmImports.add(generationState.computeOrigin(irClass))
|
||||||
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
|
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
|
||||||
putValueArgument(0, expression.receiver)
|
putValueArgument(0, expression.receiver)
|
||||||
}
|
}
|
||||||
@@ -176,7 +179,7 @@ internal class ImportCachesAbiTransformer(val generationState: NativeGenerationS
|
|||||||
|
|
||||||
property?.isLateinit == true -> {
|
property?.isLateinit == true -> {
|
||||||
val accessor = cachesAbiSupport.getLateinitPropertyAccessor(property)
|
val accessor = cachesAbiSupport.getLateinitPropertyAccessor(property)
|
||||||
llvmImports.add(property.llvmSymbolOrigin)
|
llvmImports.add(generationState.computeOrigin(property))
|
||||||
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
|
return irCall(expression.startOffset, expression.endOffset, accessor, emptyList()).apply {
|
||||||
if (irClass != null)
|
if (irClass != null)
|
||||||
putValueArgument(0, expression.receiver)
|
putValueArgument(0, expression.receiver)
|
||||||
|
|||||||
+3
-3
@@ -543,7 +543,7 @@ private class InteropLoweringPart1(val generationState: NativeGenerationState) :
|
|||||||
): IrExpression = generateWithStubs(call) {
|
): IrExpression = generateWithStubs(call) {
|
||||||
if (method.parent !is IrClass) {
|
if (method.parent !is IrClass) {
|
||||||
// Category-provided.
|
// Category-provided.
|
||||||
generationState.llvmImports.add(method.llvmSymbolOrigin)
|
generationState.llvmImports.add(generationState.computeOrigin(method))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.generateObjCCall(
|
this.generateObjCCall(
|
||||||
@@ -617,7 +617,7 @@ private class InteropLoweringPart1(val generationState: NativeGenerationState) :
|
|||||||
// handled in CodeGeneratorVisitor.callVirtual.
|
// handled in CodeGeneratorVisitor.callVirtual.
|
||||||
val useKotlinDispatch = isInteropStubsFile &&
|
val useKotlinDispatch = isInteropStubsFile &&
|
||||||
(builder.scope.scopeOwnerSymbol.owner as? IrAnnotationContainer)
|
(builder.scope.scopeOwnerSymbol.owner as? IrAnnotationContainer)
|
||||||
?.hasAnnotation(FqName("kotlin.native.internal.ExportForCppRuntime")) == true
|
?.hasAnnotation(RuntimeNames.exportForCppRuntime) == true
|
||||||
|
|
||||||
if (!useKotlinDispatch) {
|
if (!useKotlinDispatch) {
|
||||||
val arguments = callee.valueParameters.map { expression.getValueArgument(it.index) }
|
val arguments = callee.valueParameters.map { expression.getValueArgument(it.index) }
|
||||||
@@ -1011,7 +1011,7 @@ private class InteropTransformer(
|
|||||||
private fun generateCCall(expression: IrCall): IrExpression {
|
private fun generateCCall(expression: IrCall): IrExpression {
|
||||||
val function = expression.symbol.owner
|
val function = expression.symbol.owner
|
||||||
|
|
||||||
generationState.llvmImports.add(function.llvmSymbolOrigin)
|
generationState.llvmImports.add(generationState.computeOrigin(function))
|
||||||
val exceptionMode = ForeignExceptionMode.byValue(
|
val exceptionMode = ForeignExceptionMode.byValue(
|
||||||
function.konanLibrary?.manifestProperties?.getProperty(ForeignExceptionMode.manifestKey)
|
function.konanLibrary?.manifestProperties?.getProperty(ForeignExceptionMode.manifestKey)
|
||||||
)
|
)
|
||||||
|
|||||||
+66
-6
@@ -23,14 +23,17 @@ import org.jetbrains.kotlin.backend.common.serialization.*
|
|||||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAndType
|
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinaryNameAndType
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.encodings.FunctionFlags
|
import org.jetbrains.kotlin.backend.common.serialization.encodings.FunctionFlags
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.isForwardDeclarationModule
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.linkerissues.UserVisibleIrModulesSupport
|
import org.jetbrains.kotlin.backend.common.serialization.linkerissues.UserVisibleIrModulesSupport
|
||||||
import org.jetbrains.kotlin.backend.konan.*
|
import org.jetbrains.kotlin.backend.konan.*
|
||||||
|
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
|
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
|
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
|
|
||||||
import org.jetbrains.kotlin.backend.konan.descriptors.toFieldInfo
|
import org.jetbrains.kotlin.backend.konan.descriptors.toFieldInfo
|
||||||
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs
|
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
||||||
|
import org.jetbrains.kotlin.library.metadata.klibModuleOrigin
|
||||||
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
|
import org.jetbrains.kotlin.descriptors.konan.isNativeStdlib
|
||||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
import org.jetbrains.kotlin.ir.builders.TranslationPluginContext
|
||||||
@@ -47,8 +50,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
||||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
import org.jetbrains.kotlin.library.metadata.DeserializedKlibModuleOrigin
|
|
||||||
import org.jetbrains.kotlin.library.metadata.klibModuleOrigin
|
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -196,6 +197,27 @@ internal object ClassFieldsSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SerializedEagerInitializedFile(val file: Int)
|
||||||
|
|
||||||
|
internal object EagerInitializedPropertySerializer {
|
||||||
|
fun serialize(properties: List<SerializedEagerInitializedFile>): ByteArray {
|
||||||
|
val size = properties.sumOf { Int.SIZE_BYTES }
|
||||||
|
val stream = ByteArrayStream(ByteArray(size))
|
||||||
|
properties.forEach {
|
||||||
|
stream.writeInt(it.file)
|
||||||
|
}
|
||||||
|
return stream.buf
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserializeTo(data: ByteArray, result: MutableList<SerializedEagerInitializedFile>) {
|
||||||
|
val stream = ByteArrayStream(data)
|
||||||
|
while (stream.hasData()) {
|
||||||
|
val file = stream.readInt()
|
||||||
|
result.add(SerializedEagerInitializedFile(file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun ProtoClass.findClass(irClass: IrClass, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoClass {
|
internal fun ProtoClass.findClass(irClass: IrClass, fileReader: IrLibraryFile, symbolDeserializer: IrSymbolDeserializer): ProtoClass {
|
||||||
val signature = irClass.symbol.signature ?: error("No signature for ${irClass.render()}")
|
val signature = irClass.symbol.signature ?: error("No signature for ${irClass.render()}")
|
||||||
var result: ProtoClass? = null
|
var result: ProtoClass? = null
|
||||||
@@ -400,9 +422,7 @@ internal class KonanIrLinker(
|
|||||||
is IrExternalPackageFragment -> {
|
is IrExternalPackageFragment -> {
|
||||||
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
|
||||||
val moduleDeserializer = moduleDeserializers[moduleDescriptor] ?: error("No module deserializer for $moduleDescriptor")
|
val moduleDeserializer = moduleDeserializers[moduleDescriptor] ?: error("No module deserializer for $moduleDescriptor")
|
||||||
val descriptor = declaration.descriptor
|
moduleDeserializer.getFileNameOf(declaration)
|
||||||
val idSig = moduleDeserializer.descriptorSignatures[descriptor] ?: error("No signature for $descriptor")
|
|
||||||
idSig.topLevelSignature().fileSignature()?.fileName ?: error("No file for $idSig")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> error("Unknown package fragment kind ${packageFragment::class.java}")
|
else -> error("Unknown package fragment kind ${packageFragment::class.java}")
|
||||||
@@ -443,6 +463,33 @@ internal class KonanIrLinker(
|
|||||||
) {
|
) {
|
||||||
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
|
override val moduleFragment: IrModuleFragment = KonanIrModuleFragmentImpl(moduleDescriptor, builtIns)
|
||||||
|
|
||||||
|
val files by lazy { fileDeserializationStates.map { it.file } }
|
||||||
|
|
||||||
|
private val fileToFileDeserializationState by lazy { fileDeserializationStates.associateBy { it.file } }
|
||||||
|
|
||||||
|
private val idSignatureToFile by lazy {
|
||||||
|
buildMap {
|
||||||
|
fileDeserializationStates.forEach { fileDeserializationState ->
|
||||||
|
fileDeserializationState.fileDeserializer.reversedSignatureIndex.keys.forEach { idSig ->
|
||||||
|
put(idSig, fileDeserializationState.file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFileNameOf(declaration: IrDeclaration): String {
|
||||||
|
fun IrDeclaration.getSignature() = symbol.signature ?: descriptorSignatures[descriptor]
|
||||||
|
|
||||||
|
val idSig = declaration.getSignature()
|
||||||
|
?: (declaration.parent as? IrDeclaration)?.getSignature()
|
||||||
|
?: ((declaration as? IrAttributeContainer)?.attributeOwnerId as? IrDeclaration)?.getSignature()
|
||||||
|
?: error("Can't find signature of ${declaration.render()}")
|
||||||
|
val topLevelIdSig = idSig.topLevelSignature()
|
||||||
|
return topLevelIdSig.fileSignature()?.fileName
|
||||||
|
?: idSignatureToFile[topLevelIdSig]?.path
|
||||||
|
?: error("No file for $idSig")
|
||||||
|
}
|
||||||
|
|
||||||
fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference {
|
fun buildInlineFunctionReference(irFunction: IrFunction): SerializedInlineFunctionReference {
|
||||||
val signature = irFunction.symbol.signature
|
val signature = irFunction.symbol.signature
|
||||||
?: error("No signature for ${irFunction.render()}")
|
?: error("No signature for ${irFunction.render()}")
|
||||||
@@ -598,6 +645,12 @@ internal class KonanIrLinker(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildEagerInitializedFile(irFile: IrFile): SerializedEagerInitializedFile {
|
||||||
|
val fileDeserializationState = fileToFileDeserializationState[irFile]
|
||||||
|
?: error("No file deserializer for ${irFile.render()}")
|
||||||
|
return SerializedEagerInitializedFile(fileDeserializationState.fileIndex)
|
||||||
|
}
|
||||||
|
|
||||||
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl(
|
private val descriptorByIdSignatureFinder = DescriptorByIdSignatureFinderImpl(
|
||||||
moduleDescriptor, KonanManglerDesc,
|
moduleDescriptor, KonanManglerDesc,
|
||||||
DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY
|
DescriptorByIdSignatureFinderImpl.LookupMode.MODULE_ONLY
|
||||||
@@ -807,6 +860,13 @@ internal class KonanIrLinker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val eagerInitializedFiles by lazy {
|
||||||
|
val cache = cachedLibraries.getLibraryCache(klib)!! // ?: error("No cache for ${klib.libraryName}") // KT-54668
|
||||||
|
cache.serializedEagerInitializedFiles
|
||||||
|
.map { fileDeserializationStates[it.file].file }
|
||||||
|
.distinct()
|
||||||
|
}
|
||||||
|
|
||||||
val sortedFileIds by lazy {
|
val sortedFileIds by lazy {
|
||||||
fileDeserializationStates
|
fileDeserializationStates
|
||||||
.sortedBy { it.file.fileEntry.name }
|
.sortedBy { it.file.fileEntry.name }
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
package kotlin.native.internal
|
||||||
|
|
||||||
|
//
|
||||||
|
// NOTE: THIS FILE IS AUTO-GENERATED, DO NOT EDIT
|
||||||
|
//
|
||||||
|
// This is a special fictitious file, mirroring native runtime.
|
||||||
|
// During cache building for stdlib, the compiler will link native runtime to the bitcode this file
|
||||||
|
// will be compiled to. The bitcode dependencies of this file will be generated by the compiler,
|
||||||
|
// containing all the files with either ExportTypeInfo or ExportForCppRuntime annotations.
|
||||||
|
//
|
||||||
Reference in New Issue
Block a user