From 9b1498abad5dfa38260eaf3a7ff2380250a32a85 Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov Date: Wed, 7 Apr 2021 15:40:32 +0700 Subject: [PATCH] Use runtime bitcode to get size of primitive types As an alternative to explicitly setting type size in konan.properties or backend code we can "ask" LLVM about it. Unfortunately, there is no Clang/LLVM API for it, so we use a trivial workaround: Create dumb function in runtime code, and then extract info about return type size using LLVM. --- .../kotlin/backend/konan/llvm/ContextUtils.kt | 23 +++++++ .../llvm/objcexport/BlockPointerSupport.kt | 6 +- .../objcexport/ObjCExportCodeGenerator.kt | 60 +++---------------- .../runtime/src/main/cpp/ObjCExport.h | 3 + .../runtime/src/main/cpp/ObjCExport.mm | 4 ++ kotlin-native/runtime/src/main/cpp/Types.cpp | 4 ++ kotlin-native/runtime/src/main/cpp/Types.h | 3 + 7 files changed, 49 insertions(+), 54 deletions(-) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 5acba6c28e6..80e54052050 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -502,6 +502,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val Kotlin_ObjCExport_createContinuationArgument by lazyRtFunction val Kotlin_ObjCExport_resumeContinuation by lazyRtFunction + private val Kotlin_ObjCExport_NSIntegerTypeProvider by lazyRtFunction + private val Kotlin_longTypeProvider by lazyRtFunction + val Kotlin_mm_safePointFunctionEpilogue by lazyRtFunction val Kotlin_mm_safePointWhileLoopBody by lazyRtFunction val Kotlin_mm_safePointExceptionUnwind by lazyRtFunction @@ -593,6 +596,26 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { val llvmFloat = floatType val llvmDouble = doubleType val llvmVector128 = vector128Type + + private fun getSizeOfReturnTypeInBits(functionPointer: LLVMValueRef): Long { + // LLVMGetElementType is called because we need to dereference a pointer to function. + val nsIntegerType = LLVMGetReturnType(LLVMGetElementType(functionPointer.type)) + return LLVMSizeOfTypeInBits(runtime.targetData, nsIntegerType) + } + + /** + * Width of NSInteger in bits. + */ + val nsIntegerTypeWidth: Long by lazy { + getSizeOfReturnTypeInBits(Kotlin_ObjCExport_NSIntegerTypeProvider) + } + + /** + * Width of C long type in bits. + */ + val longTypeWidth: Long by lazy { + getSizeOfReturnTypeInBits(Kotlin_longTypeProvider) + } } class IrStaticInitializer(val konanLibrary: KotlinLibrary?, val initializer: LLVMValueRef) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt index 0ca13e435dc..96064e047ca 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/BlockPointerSupport.kt @@ -194,7 +194,11 @@ internal class BlockGenerator(private val codegen: CodeGenerator) { } fun org.jetbrains.kotlin.backend.konan.Context.LongInt(value: Long) = - if (is64BitLong()) Int64(value) else Int32(value.toInt()) + when (val longWidth = llvm.longTypeWidth) { + 32L -> Int32(value.toInt()) + 64L -> Int64(value) + else -> error("Unexpected width of long type: $longWidth") + } private fun generateDescriptorForBlock(blockType: BlockType): ConstValue { val numberOfParameters = blockType.numberOfParameters diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 2d8a8caba37..55a808b2074 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.konan.target.KonanTarget +import org.jetbrains.kotlin.konan.target.AppleConfigurables import org.jetbrains.kotlin.konan.target.LinkerOutputKind import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.utils.DFS @@ -1669,56 +1669,10 @@ private val TypeBridge.objCEncoding: String get() = when (this) { is ValueTypeBridge -> this.objCValueType.encoding } -private fun Context.is64BitNSInteger(): Boolean = when (val target = this.config.target) { - KonanTarget.IOS_X64, - KonanTarget.IOS_ARM64, - KonanTarget.TVOS_ARM64, - KonanTarget.TVOS_X64, - KonanTarget.MACOS_X64, - KonanTarget.MACOS_ARM64, - KonanTarget.WATCHOS_X64 -> true - KonanTarget.WATCHOS_ARM64, - KonanTarget.WATCHOS_ARM32, - KonanTarget.WATCHOS_X86, - KonanTarget.IOS_ARM32 -> false - KonanTarget.ANDROID_X64, - KonanTarget.ANDROID_X86, - KonanTarget.ANDROID_ARM32, - KonanTarget.ANDROID_ARM64, - KonanTarget.LINUX_X64, - KonanTarget.MINGW_X86, - KonanTarget.MINGW_X64, - KonanTarget.LINUX_ARM64, - KonanTarget.LINUX_ARM32_HFP, - KonanTarget.LINUX_MIPS32, - KonanTarget.LINUX_MIPSEL32, - KonanTarget.WASM32, - is KonanTarget.ZEPHYR -> error("Target $target has no support for NSInteger type.") -} - -internal fun Context.is64BitLong(): Boolean = when (this.config.target) { - KonanTarget.IOS_X64, - KonanTarget.IOS_ARM64, - KonanTarget.TVOS_ARM64, - KonanTarget.TVOS_X64, - KonanTarget.ANDROID_X64, - KonanTarget.ANDROID_ARM64, - KonanTarget.LINUX_ARM64, - KonanTarget.MINGW_X64, - KonanTarget.LINUX_X64, - KonanTarget.MACOS_X64, - KonanTarget.MACOS_ARM64, - KonanTarget.WATCHOS_X64 -> true - KonanTarget.WATCHOS_ARM64, - KonanTarget.WATCHOS_ARM32, - KonanTarget.ANDROID_X86, - KonanTarget.ANDROID_ARM32, - KonanTarget.WATCHOS_X86, - KonanTarget.MINGW_X86, - KonanTarget.LINUX_ARM32_HFP, - KonanTarget.LINUX_MIPS32, - KonanTarget.LINUX_MIPSEL32, - KonanTarget.WASM32, - is KonanTarget.ZEPHYR, - KonanTarget.IOS_ARM32 -> false +private fun Context.is64BitNSInteger(): Boolean { + val configurables = this.config.platform.configurables + require(configurables is AppleConfigurables) { + "Target ${configurables.target} has no support for NSInteger type." + } + return llvm.nsIntegerTypeWidth == 64L } diff --git a/kotlin-native/runtime/src/main/cpp/ObjCExport.h b/kotlin-native/runtime/src/main/cpp/ObjCExport.h index 3ede22a3035..e2b637ba48e 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCExport.h +++ b/kotlin-native/runtime/src/main/cpp/ObjCExport.h @@ -39,6 +39,9 @@ extern "C" OBJ_GETTER(Kotlin_ObjCExport_refFromObjC, id obj); extern "C" id Kotlin_Interop_CreateNSStringFromKString(KRef str); extern "C" OBJ_GETTER(Kotlin_Interop_CreateKStringFromNSString, NSString* str); +/// Utility function that is used to determine NSInteger size in compile time. +extern "C" NSInteger Kotlin_ObjCExport_NSIntegerTypeProvider(); + #endif // KONAN_OBJC_INTEROP #endif // RUNTIME_OBJCEXPORT_H diff --git a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm index 795d1a91b94..aca91e2a5ac 100644 --- a/kotlin-native/runtime/src/main/cpp/ObjCExport.mm +++ b/kotlin-native/runtime/src/main/cpp/ObjCExport.mm @@ -1090,6 +1090,10 @@ extern "C" void Kotlin_ObjCExport_AbstractMethodCalled(id self, SEL selector) { class_getName(object_getClass(self)), sel_getName(selector)]; } +extern "C" NSInteger Kotlin_ObjCExport_NSIntegerTypeProvider() { + return 0; +} + #else extern "C" ALWAYS_INLINE void* Kotlin_Interop_refToObjC(ObjHeader* obj) { diff --git a/kotlin-native/runtime/src/main/cpp/Types.cpp b/kotlin-native/runtime/src/main/cpp/Types.cpp index b7defd21d51..57a6762caef 100644 --- a/kotlin-native/runtime/src/main/cpp/Types.cpp +++ b/kotlin-native/runtime/src/main/cpp/Types.cpp @@ -108,4 +108,8 @@ KVector4f Kotlin_Vector4i32_of(KInt f0, KInt f1, KInt f2, KInt f3) { return (KVector4f)v4i; } +long Kotlin_longTypeProvider() { + return 0; +} + } // extern "C" diff --git a/kotlin-native/runtime/src/main/cpp/Types.h b/kotlin-native/runtime/src/main/cpp/Types.h index 64300cc0af1..bcdcdde20c4 100644 --- a/kotlin-native/runtime/src/main/cpp/Types.h +++ b/kotlin-native/runtime/src/main/cpp/Types.h @@ -124,6 +124,9 @@ void CheckCast(const ObjHeader* obj, const TypeInfo* type_info); KBoolean IsArray(KConstRef obj) RUNTIME_PURE; bool IsSubInterface(const TypeInfo* thiz, const TypeInfo* other) RUNTIME_PURE; +/// Utility function that is used to determine long type size in compile time. +long Kotlin_longTypeProvider(); + #ifdef __cplusplus } #endif