From 06f8864b69a4075af7d768da78f4bddcaaac6cfc Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Thu, 14 Mar 2019 17:35:27 +0300 Subject: [PATCH] Refine LLVM bitcode imports detection Don't link native libraries if external function requires only library-stored bitcode --- .../native/interop/gen/GlobalVariableStub.kt | 9 +++-- .../native/interop/gen/KotlinCodeModel.kt | 2 ++ .../interop/gen/MappingBridgeGenerator.kt | 1 + .../interop/gen/MappingBridgeGeneratorImpl.kt | 3 +- .../kotlin/native/interop/gen/Mappings.kt | 3 +- .../kotlin/native/interop/gen/ObjCStubs.kt | 6 +++- .../interop/gen/SimpleBridgeGenerator.kt | 1 + .../interop/gen/SimpleBridgeGeneratorImpl.kt | 4 ++- .../native/interop/gen/jvm/StubGenerator.kt | 3 +- .../kotlin/backend/konan/LinkStage.kt | 11 +++--- .../kotlin/backend/konan/RuntimeNames.kt | 1 + .../kotlin/backend/konan/llvm/ContextUtils.kt | 34 ++++++++++++++----- .../kotlin/backend/konan/llvm/Imports.kt | 5 +-- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 3 +- .../llvm/KotlinObjCClassInfoGenerator.kt | 3 +- .../backend/konan/llvm/LlvmDeclarations.kt | 3 +- .../kotlin/native/internal/Annotations.kt | 10 +++++- 17 files changed, 76 insertions(+), 26 deletions(-) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt index d99226c810b..841feabae10 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/GlobalVariableStub.kt @@ -27,7 +27,8 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot stubGenerator.simpleBridgeGenerator.kotlinToNative( nativeBacked = this, returnType = BridgedType.NATIVE_PTR, - kotlinValues = emptyList() + kotlinValues = emptyList(), + independent = false ) { "&${global.name}" } @@ -58,7 +59,8 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot getter = mirror.info.argFromBridged(stubGenerator.simpleBridgeGenerator.kotlinToNative( nativeBacked = this, returnType = mirror.info.bridgedType, - kotlinValues = emptyList() + kotlinValues = emptyList(), + independent = false ) { mirror.info.cToBridged(expr = global.name) }, kotlinScope, nativeBacked = this) @@ -71,7 +73,8 @@ class GlobalVariableStub(global: GlobalDecl, stubGenerator: StubGenerator) : Kot stubGenerator.simpleBridgeGenerator.kotlinToNative( nativeBacked = setterStub, returnType = BridgedType.VOID, - kotlinValues = listOf(bridgedValue) + kotlinValues = listOf(bridgedValue), + independent = false ) { nativeValues -> out("${global.name} = ${mirror.info.cFromBridged( nativeValues.single(), diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt index c8f80bad246..f6574704878 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/KotlinCodeModel.kt @@ -157,6 +157,8 @@ data class KotlinFunctionType( internal val cnamesStructsPackageName = "cnames.structs" object KotlinTypes { + val independent = Classifier.topLevel("kotlin.native.internal", "Independent") + val boolean by BuiltInType val byte by BuiltInType val short by BuiltInType diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGenerator.kt index aeb786557d2..68068bba5a4 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGenerator.kt @@ -32,6 +32,7 @@ interface MappingBridgeGenerator { nativeBacked: NativeBacked, returnType: Type, kotlinValues: List, + independent: Boolean, block: NativeCodeBuilder.(nativeValues: List) -> NativeExpression ): KotlinExpression diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt index 07c8273840c..cfda59df17d 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt @@ -35,6 +35,7 @@ class MappingBridgeGeneratorImpl( nativeBacked: NativeBacked, returnType: Type, kotlinValues: List, + independent: Boolean, block: NativeCodeBuilder.(nativeValues: List) -> NativeExpression ): KotlinExpression { val bridgeArguments = mutableListOf() @@ -70,7 +71,7 @@ class MappingBridgeGeneratorImpl( } val callExpr = simpleBridgeGenerator.kotlinToNative( - nativeBacked, bridgeReturnType, bridgeArguments + nativeBacked, bridgeReturnType, bridgeArguments, independent ) { bridgeNativeValues -> val nativeValues = mutableListOf() diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt index bf57670d9f5..1e0ba7853e1 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt @@ -307,7 +307,8 @@ sealed class TypeInfo { type.returnType, type.parameterTypes.mapIndexed { index, it -> TypedKotlinValue(it, "p$index") - } + TypedKotlinValue(PointerType(VoidType), "interpretCPointer($kniBlockPtr)") + } + TypedKotlinValue(PointerType(VoidType), "interpretCPointer($kniBlockPtr)"), + independent = true ) { nativeValues -> val type = type diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt index a3abca03ed5..b3b2a6e0118 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt @@ -226,7 +226,11 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator, bodyGenerator, this@ObjCMethodStub, 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 -> val messengerParameterTypes = mutableListOf() messengerParameterTypes.add("void*") diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGenerator.kt index 9c2eaf4cb91..2f7f880dde4 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGenerator.kt @@ -60,6 +60,7 @@ interface SimpleBridgeGenerator { nativeBacked: NativeBacked, returnType: BridgedType, kotlinValues: List, + independent: Boolean, block: NativeCodeBuilder.(nativeValues: List) -> NativeExpression ): KotlinExpression diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt index 916534b9441..589ed5769b2 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt @@ -71,7 +71,8 @@ class SimpleBridgeGeneratorImpl( nativeBacked: NativeBacked, returnType: BridgedType, kotlinValues: List, - block: NativeCodeBuilder.(arguments: List) -> NativeExpression + independent: Boolean, + block: NativeCodeBuilder.(nativeValues: List) -> NativeExpression ): KotlinExpression { val kotlinLines = mutableListOf() @@ -116,6 +117,7 @@ class SimpleBridgeGeneratorImpl( } KotlinPlatform.NATIVE -> { val functionName = pkgName.replace(INVALID_CLANG_IDENTIFIER_REGEX, "_") + "_$kotlinFunctionName" + if (independent) kotlinLines.add("@" + topLevelKotlinScope.reference(KotlinTypes.independent)) kotlinLines.add("@SymbolName(${functionName.quoteAsKotlinLiteral()})") "$cReturnType $functionName ($joinedCParameters)" } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt index cbc40fc6d92..1641eacc0b2 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt @@ -660,7 +660,8 @@ class StubGenerator( bodyGenerator, this, func.returnType, - bridgeArguments + bridgeArguments, + independent = false ) { nativeValues -> "${func.name}(${nativeValues.joinToString()})" } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt index fa8f74bdc46..ca15cedd475 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt @@ -40,7 +40,10 @@ internal class LinkStage(val context: Context) { private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false 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.addNonEmpty(elements: List) { addAll(elements.filter { !it.isEmpty() }) } @@ -221,7 +224,7 @@ internal class LinkStage(val context: Context) { fun makeObjectFiles() { 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) { is WasmConfigurables @@ -235,10 +238,10 @@ internal class LinkStage(val context: Context) { fun linkStage() { val includedBinaries = - libraries.map { it.includedPaths }.flatten() + nativeDependencies.map { it.includedPaths }.flatten() val libraryProvidedLinkerFlags = - libraries.map { it.linkerOpts }.flatten() + nativeDependencies.map { it.linkerOpts }.flatten() link(objectFiles, includedBinaries, libraryProvidedLinkerFlags) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt index 8c7de54b14c..0c357eb95f9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/RuntimeNames.kt @@ -8,4 +8,5 @@ object RuntimeNames { val exportForCompilerAnnotation = FqName("kotlin.native.internal.ExportForCompiler") val exportTypeInfoAnnotation = FqName("kotlin.native.internal.ExportTypeInfo") val cCall = FqName("kotlinx.cinterop.internal.CCall") + val independent = FqName("kotlin.native.internal.Independent") } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index cba89c5f870..619c03f03ff 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -296,8 +296,13 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { return LLVMAddFunction(llvmModule, "llvm.memcpy.p0i8.p0i8.i32", functionType)!! } - internal fun externalFunction(name: String, type: LLVMTypeRef, origin: CompiledKonanModuleOrigin): LLVMValueRef { - this.imports.add(origin) + internal fun externalFunction( + name: String, + type: LLVMTypeRef, + origin: CompiledKonanModuleOrigin, + independent: Boolean = false + ): LLVMValueRef { + this.imports.add(origin, onlyBitcode = independent) val found = LLVMGetNamedFunction(llvmModule, name) if (found != null) { @@ -336,11 +341,12 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { class ImportsImpl(private val context: Context) : LlvmImports { - private val usedLibraries = mutableSetOf() + private val usedBitcode = mutableSetOf() + private val usedNativeDependencies = mutableSetOf() private val allLibraries by lazy { context.librariesWithDependencies.toSet() } - override fun add(origin: CompiledKonanModuleOrigin) { + override fun add(origin: CompiledKonanModuleOrigin, onlyBitcode: Boolean) { val library = when (origin) { CurrentKonanModuleOrigin -> return 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 }}") } - 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 by lazy { + val nativeDependenciesToLink: List by lazy { context.config.resolvedLibraries - .filterRoots { (!it.isDefault && !context.config.purgeUserLibs) || imports.isImported(it.library) } .getFullList(TopologicalLibraryOrder) + .filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.nativeDependenciesAreUsed(it) } + + } + + val bitcodeToLink: List by lazy { + context.config.resolvedLibraries + .getFullList(TopologicalLibraryOrder) + .filter { (!it.isDefault && !context.config.purgeUserLibs) || imports.bitcodeIsUsed(it) } } val staticData = StaticData(context) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt index 2bc2ff9d339..9955b8265f0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Imports.kt @@ -15,8 +15,9 @@ import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.resolve.descriptorUtil.module internal interface LlvmImports { - fun add(origin: CompiledKonanModuleOrigin) - fun isImported(library: KonanLibrary): Boolean + fun add(origin: CompiledKonanModuleOrigin, onlyBitcode: Boolean = false) + fun bitcodeIsUsed(library: KonanLibrary): Boolean + fun nativeDependenciesAreUsed(library: KonanLibrary): Boolean } internal val DeclarationDescriptor.llvmSymbolOrigin: CompiledKonanModuleOrigin diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 733ebb0e101..0a190346bb0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2123,7 +2123,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map