Refine LLVM bitcode imports detection
Don't link native libraries if external function requires only library-stored bitcode
This commit is contained in:
committed by
SvyatoslavScherbina
parent
f8393819fc
commit
06f8864b69
+6
-3
@@ -27,7 +27,8 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot
|
|||||||
stubGenerator.simpleBridgeGenerator.kotlinToNative(
|
stubGenerator.simpleBridgeGenerator.kotlinToNative(
|
||||||
nativeBacked = this,
|
nativeBacked = this,
|
||||||
returnType = BridgedType.NATIVE_PTR,
|
returnType = BridgedType.NATIVE_PTR,
|
||||||
kotlinValues = emptyList()
|
kotlinValues = emptyList(),
|
||||||
|
independent = false
|
||||||
) {
|
) {
|
||||||
"&${global.name}"
|
"&${global.name}"
|
||||||
}
|
}
|
||||||
@@ -58,7 +59,8 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot
|
|||||||
getter = mirror.info.argFromBridged(stubGenerator.simpleBridgeGenerator.kotlinToNative(
|
getter = mirror.info.argFromBridged(stubGenerator.simpleBridgeGenerator.kotlinToNative(
|
||||||
nativeBacked = this,
|
nativeBacked = this,
|
||||||
returnType = mirror.info.bridgedType,
|
returnType = mirror.info.bridgedType,
|
||||||
kotlinValues = emptyList()
|
kotlinValues = emptyList(),
|
||||||
|
independent = false
|
||||||
) {
|
) {
|
||||||
mirror.info.cToBridged(expr = global.name)
|
mirror.info.cToBridged(expr = global.name)
|
||||||
}, kotlinScope, nativeBacked = this)
|
}, kotlinScope, nativeBacked = this)
|
||||||
@@ -71,7 +73,8 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot
|
|||||||
stubGenerator.simpleBridgeGenerator.kotlinToNative(
|
stubGenerator.simpleBridgeGenerator.kotlinToNative(
|
||||||
nativeBacked = setterStub,
|
nativeBacked = setterStub,
|
||||||
returnType = BridgedType.VOID,
|
returnType = BridgedType.VOID,
|
||||||
kotlinValues = listOf(bridgedValue)
|
kotlinValues = listOf(bridgedValue),
|
||||||
|
independent = false
|
||||||
) { nativeValues ->
|
) { nativeValues ->
|
||||||
out("${global.name} = ${mirror.info.cFromBridged(
|
out("${global.name} = ${mirror.info.cFromBridged(
|
||||||
nativeValues.single(),
|
nativeValues.single(),
|
||||||
|
|||||||
+2
@@ -157,6 +157,8 @@ data class KotlinFunctionType(
|
|||||||
internal val cnamesStructsPackageName = "cnames.structs"
|
internal val cnamesStructsPackageName = "cnames.structs"
|
||||||
|
|
||||||
object KotlinTypes {
|
object KotlinTypes {
|
||||||
|
val independent = Classifier.topLevel("kotlin.native.internal", "Independent")
|
||||||
|
|
||||||
val boolean by BuiltInType
|
val boolean by BuiltInType
|
||||||
val byte by BuiltInType
|
val byte by BuiltInType
|
||||||
val short by BuiltInType
|
val short by BuiltInType
|
||||||
|
|||||||
+1
@@ -32,6 +32,7 @@ interface MappingBridgeGenerator {
|
|||||||
nativeBacked: NativeBacked,
|
nativeBacked: NativeBacked,
|
||||||
returnType: Type,
|
returnType: Type,
|
||||||
kotlinValues: List<TypedKotlinValue>,
|
kotlinValues: List<TypedKotlinValue>,
|
||||||
|
independent: Boolean,
|
||||||
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
||||||
): KotlinExpression
|
): KotlinExpression
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -35,6 +35,7 @@ class MappingBridgeGeneratorImpl(
|
|||||||
nativeBacked: NativeBacked,
|
nativeBacked: NativeBacked,
|
||||||
returnType: Type,
|
returnType: Type,
|
||||||
kotlinValues: List<TypedKotlinValue>,
|
kotlinValues: List<TypedKotlinValue>,
|
||||||
|
independent: Boolean,
|
||||||
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
||||||
): KotlinExpression {
|
): KotlinExpression {
|
||||||
val bridgeArguments = mutableListOf<BridgeTypedKotlinValue>()
|
val bridgeArguments = mutableListOf<BridgeTypedKotlinValue>()
|
||||||
@@ -70,7 +71,7 @@ class MappingBridgeGeneratorImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val callExpr = simpleBridgeGenerator.kotlinToNative(
|
val callExpr = simpleBridgeGenerator.kotlinToNative(
|
||||||
nativeBacked, bridgeReturnType, bridgeArguments
|
nativeBacked, bridgeReturnType, bridgeArguments, independent
|
||||||
) { bridgeNativeValues ->
|
) { bridgeNativeValues ->
|
||||||
|
|
||||||
val nativeValues = mutableListOf<String>()
|
val nativeValues = mutableListOf<String>()
|
||||||
|
|||||||
+2
-1
@@ -307,7 +307,8 @@ sealed class TypeInfo {
|
|||||||
type.returnType,
|
type.returnType,
|
||||||
type.parameterTypes.mapIndexed { index, it ->
|
type.parameterTypes.mapIndexed { index, it ->
|
||||||
TypedKotlinValue(it, "p$index")
|
TypedKotlinValue(it, "p$index")
|
||||||
} + TypedKotlinValue(PointerType(VoidType), "interpretCPointer<COpaque>($kniBlockPtr)")
|
} + TypedKotlinValue(PointerType(VoidType), "interpretCPointer<COpaque>($kniBlockPtr)"),
|
||||||
|
independent = true
|
||||||
|
|
||||||
) { nativeValues ->
|
) { nativeValues ->
|
||||||
val type = type
|
val type = type
|
||||||
|
|||||||
+5
-1
@@ -226,7 +226,11 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator,
|
|||||||
bodyGenerator,
|
bodyGenerator,
|
||||||
this@ObjCMethodStub,
|
this@ObjCMethodStub,
|
||||||
returnType,
|
returnType,
|
||||||
nativeBridgeArguments
|
nativeBridgeArguments,
|
||||||
|
independent = when (container) {
|
||||||
|
is ObjCClassOrProtocol -> true // Every proper instance has this method in its method table.
|
||||||
|
is ObjCCategory -> false // Method is contributed by native dependency.
|
||||||
|
}
|
||||||
) { nativeValues ->
|
) { nativeValues ->
|
||||||
val messengerParameterTypes = mutableListOf<String>()
|
val messengerParameterTypes = mutableListOf<String>()
|
||||||
messengerParameterTypes.add("void*")
|
messengerParameterTypes.add("void*")
|
||||||
|
|||||||
+1
@@ -60,6 +60,7 @@ interface SimpleBridgeGenerator {
|
|||||||
nativeBacked: NativeBacked,
|
nativeBacked: NativeBacked,
|
||||||
returnType: BridgedType,
|
returnType: BridgedType,
|
||||||
kotlinValues: List<BridgeTypedKotlinValue>,
|
kotlinValues: List<BridgeTypedKotlinValue>,
|
||||||
|
independent: Boolean,
|
||||||
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
||||||
): KotlinExpression
|
): KotlinExpression
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -71,7 +71,8 @@ class SimpleBridgeGeneratorImpl(
|
|||||||
nativeBacked: NativeBacked,
|
nativeBacked: NativeBacked,
|
||||||
returnType: BridgedType,
|
returnType: BridgedType,
|
||||||
kotlinValues: List<BridgeTypedKotlinValue>,
|
kotlinValues: List<BridgeTypedKotlinValue>,
|
||||||
block: NativeCodeBuilder.(arguments: List<NativeExpression>) -> NativeExpression
|
independent: Boolean,
|
||||||
|
block: NativeCodeBuilder.(nativeValues: List<NativeExpression>) -> NativeExpression
|
||||||
): KotlinExpression {
|
): KotlinExpression {
|
||||||
|
|
||||||
val kotlinLines = mutableListOf<String>()
|
val kotlinLines = mutableListOf<String>()
|
||||||
@@ -116,6 +117,7 @@ class SimpleBridgeGeneratorImpl(
|
|||||||
}
|
}
|
||||||
KotlinPlatform.NATIVE -> {
|
KotlinPlatform.NATIVE -> {
|
||||||
val functionName = pkgName.replace(INVALID_CLANG_IDENTIFIER_REGEX, "_") + "_$kotlinFunctionName"
|
val functionName = pkgName.replace(INVALID_CLANG_IDENTIFIER_REGEX, "_") + "_$kotlinFunctionName"
|
||||||
|
if (independent) kotlinLines.add("@" + topLevelKotlinScope.reference(KotlinTypes.independent))
|
||||||
kotlinLines.add("@SymbolName(${functionName.quoteAsKotlinLiteral()})")
|
kotlinLines.add("@SymbolName(${functionName.quoteAsKotlinLiteral()})")
|
||||||
"$cReturnType $functionName ($joinedCParameters)"
|
"$cReturnType $functionName ($joinedCParameters)"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -660,7 +660,8 @@ class StubGenerator(
|
|||||||
bodyGenerator,
|
bodyGenerator,
|
||||||
this,
|
this,
|
||||||
func.returnType,
|
func.returnType,
|
||||||
bridgeArguments
|
bridgeArguments,
|
||||||
|
independent = false
|
||||||
) { nativeValues ->
|
) { nativeValues ->
|
||||||
"${func.name}(${nativeValues.joinToString()})"
|
"${func.name}(${nativeValues.joinToString()})"
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-4
@@ -40,7 +40,10 @@ internal class LinkStage(val context: Context) {
|
|||||||
|
|
||||||
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
|
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
|
||||||
private val emitted = context.bitcodeFileName
|
private val emitted = context.bitcodeFileName
|
||||||
private val libraries = context.llvm.librariesToLink
|
|
||||||
|
private val bitcodeLibraries = context.llvm.bitcodeToLink
|
||||||
|
private val nativeDependencies = context.llvm.nativeDependenciesToLink
|
||||||
|
|
||||||
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
|
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
|
||||||
addAll(elements.filter { !it.isEmpty() })
|
addAll(elements.filter { !it.isEmpty() })
|
||||||
}
|
}
|
||||||
@@ -221,7 +224,7 @@ internal class LinkStage(val context: Context) {
|
|||||||
fun makeObjectFiles() {
|
fun makeObjectFiles() {
|
||||||
|
|
||||||
val bitcodeFiles = listOf(emitted) +
|
val bitcodeFiles = listOf(emitted) +
|
||||||
libraries.map { it.bitcodePaths }.flatten().filter { it.isBitcode }
|
bitcodeLibraries.map { it.bitcodePaths }.flatten().filter { it.isBitcode }
|
||||||
|
|
||||||
objectFiles.add(when (platform.configurables) {
|
objectFiles.add(when (platform.configurables) {
|
||||||
is WasmConfigurables
|
is WasmConfigurables
|
||||||
@@ -235,10 +238,10 @@ internal class LinkStage(val context: Context) {
|
|||||||
|
|
||||||
fun linkStage() {
|
fun linkStage() {
|
||||||
val includedBinaries =
|
val includedBinaries =
|
||||||
libraries.map { it.includedPaths }.flatten()
|
nativeDependencies.map { it.includedPaths }.flatten()
|
||||||
|
|
||||||
val libraryProvidedLinkerFlags =
|
val libraryProvidedLinkerFlags =
|
||||||
libraries.map { it.linkerOpts }.flatten()
|
nativeDependencies.map { it.linkerOpts }.flatten()
|
||||||
|
|
||||||
link(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
|
link(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -8,4 +8,5 @@ object RuntimeNames {
|
|||||||
val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler")
|
val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler")
|
||||||
val exportTypeInfoAnnotation = FqName("kotlin.native.internal.ExportTypeInfo")
|
val exportTypeInfoAnnotation = FqName("kotlin.native.internal.ExportTypeInfo")
|
||||||
val cCall = FqName("kotlinx.cinterop.internal.CCall")
|
val cCall = FqName("kotlinx.cinterop.internal.CCall")
|
||||||
|
val independent = FqName("kotlin.native.internal.Independent")
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-8
@@ -296,8 +296,13 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
return LLVMAddFunction(llvmModule, "llvm.memcpy.p0i8.p0i8.i32", functionType)!!
|
return LLVMAddFunction(llvmModule, "llvm.memcpy.p0i8.p0i8.i32", functionType)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun externalFunction(name: String, type: LLVMTypeRef, origin: CompiledKonanModuleOrigin): LLVMValueRef {
|
internal fun externalFunction(
|
||||||
this.imports.add(origin)
|
name: String,
|
||||||
|
type: LLVMTypeRef,
|
||||||
|
origin: CompiledKonanModuleOrigin,
|
||||||
|
independent: Boolean = false
|
||||||
|
): LLVMValueRef {
|
||||||
|
this.imports.add(origin, onlyBitcode = independent)
|
||||||
|
|
||||||
val found = LLVMGetNamedFunction(llvmModule, name)
|
val found = LLVMGetNamedFunction(llvmModule, name)
|
||||||
if (found != null) {
|
if (found != null) {
|
||||||
@@ -336,11 +341,12 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
|
|
||||||
class ImportsImpl(private val context: Context) : LlvmImports {
|
class ImportsImpl(private val context: Context) : LlvmImports {
|
||||||
|
|
||||||
private val usedLibraries = mutableSetOf<KonanLibrary>()
|
private val usedBitcode = mutableSetOf<KonanLibrary>()
|
||||||
|
private val usedNativeDependencies = mutableSetOf<KonanLibrary>()
|
||||||
|
|
||||||
private val allLibraries by lazy { context.librariesWithDependencies.toSet() }
|
private val allLibraries by lazy { context.librariesWithDependencies.toSet() }
|
||||||
|
|
||||||
override fun add(origin: CompiledKonanModuleOrigin) {
|
override fun add(origin: CompiledKonanModuleOrigin, onlyBitcode: Boolean) {
|
||||||
val library = when (origin) {
|
val library = when (origin) {
|
||||||
CurrentKonanModuleOrigin -> return
|
CurrentKonanModuleOrigin -> return
|
||||||
is DeserializedKonanModuleOrigin -> origin.library
|
is DeserializedKonanModuleOrigin -> origin.library
|
||||||
@@ -350,16 +356,28 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
error("Library (${library.libraryName}) is used but not requested.\nRequested libraries: ${allLibraries.joinToString { it.libraryName }}")
|
error("Library (${library.libraryName}) is used but not requested.\nRequested libraries: ${allLibraries.joinToString { it.libraryName }}")
|
||||||
}
|
}
|
||||||
|
|
||||||
usedLibraries.add(library)
|
usedBitcode.add(library)
|
||||||
|
if (!onlyBitcode) {
|
||||||
|
usedNativeDependencies.add(library)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isImported(library: KonanLibrary): Boolean = library in usedLibraries
|
override fun bitcodeIsUsed(library: KonanLibrary) = library in usedBitcode
|
||||||
|
|
||||||
|
override fun nativeDependenciesAreUsed(library: KonanLibrary) = library in usedNativeDependencies
|
||||||
}
|
}
|
||||||
|
|
||||||
val librariesToLink: List<KonanLibrary> by lazy {
|
val nativeDependenciesToLink: List<KonanLibrary> by lazy {
|
||||||
context.config.resolvedLibraries
|
context.config.resolvedLibraries
|
||||||
.filterRoots { (!it.isDefault && !context.config.purgeUserLibs) || imports.isImported(it.library) }
|
|
||||||
.getFullList(TopologicalLibraryOrder)
|
.getFullList(TopologicalLibraryOrder)
|
||||||
|
.filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.nativeDependenciesAreUsed(it) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
val bitcodeToLink: List<KonanLibrary> by lazy {
|
||||||
|
context.config.resolvedLibraries
|
||||||
|
.getFullList(TopologicalLibraryOrder)
|
||||||
|
.filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.bitcodeIsUsed(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val staticData = StaticData(context)
|
val staticData = StaticData(context)
|
||||||
|
|||||||
+3
-2
@@ -15,8 +15,9 @@ import org.jetbrains.kotlin.konan.library.KonanLibrary
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
internal interface LlvmImports {
|
internal interface LlvmImports {
|
||||||
fun add(origin: CompiledKonanModuleOrigin)
|
fun add(origin: CompiledKonanModuleOrigin, onlyBitcode: Boolean = false)
|
||||||
fun isImported(library: KonanLibrary): Boolean
|
fun bitcodeIsUsed(library: KonanLibrary): Boolean
|
||||||
|
fun nativeDependenciesAreUsed(library: KonanLibrary): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKonanModuleOrigin
|
internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKonanModuleOrigin
|
||||||
|
|||||||
+2
-1
@@ -2123,7 +2123,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
val protocolGetter = context.llvm.externalFunction(
|
val protocolGetter = context.llvm.externalFunction(
|
||||||
protocolGetterName,
|
protocolGetterName,
|
||||||
functionType(int8TypePtr, false),
|
functionType(int8TypePtr, false),
|
||||||
irClass.llvmSymbolOrigin
|
irClass.llvmSymbolOrigin,
|
||||||
|
independent = true // Protocol is header-only declaration.
|
||||||
)
|
)
|
||||||
|
|
||||||
return call(protocolGetter, emptyList())
|
return call(protocolGetter, emptyList())
|
||||||
|
|||||||
+2
-1
@@ -120,7 +120,8 @@ internal class KotlinObjCClassInfoGenerator(override val context: Context) : Con
|
|||||||
context.llvm.externalFunction(
|
context.llvm.externalFunction(
|
||||||
imp,
|
imp,
|
||||||
functionType(voidType),
|
functionType(voidType),
|
||||||
origin = info.bridge.llvmSymbolOrigin
|
origin = info.bridge.llvmSymbolOrigin,
|
||||||
|
independent = true
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -397,7 +397,8 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
|||||||
|
|
||||||
context.llvm.externalFunction(declaration.symbolName, llvmFunctionType,
|
context.llvm.externalFunction(declaration.symbolName, llvmFunctionType,
|
||||||
// Assume that `external fun` is defined in native libs attached to this module:
|
// Assume that `external fun` is defined in native libs attached to this module:
|
||||||
origin = declaration.llvmSymbolOrigin
|
origin = declaration.llvmSymbolOrigin,
|
||||||
|
independent = declaration.hasAnnotation(RuntimeNames.independent)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val symbolName = if (declaration.isExported()) {
|
val symbolName = if (declaration.isExported()) {
|
||||||
|
|||||||
@@ -105,3 +105,11 @@ internal annotation class PointsTo(vararg val onWhom: Int)
|
|||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
internal annotation class TypedIntrinsic(val kind: String)
|
internal annotation class TypedIntrinsic(val kind: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that `@SymbolName external` function is implemented in library-stored bitcode
|
||||||
|
* and doesn't have native dependencies.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
annotation class Independent
|
||||||
Reference in New Issue
Block a user