diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt index dc210707e7f..82adab1a7c8 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Boxing.kt @@ -259,6 +259,7 @@ internal fun IrBuiltIns.getKotlinClass(cache: BoxCache): IrClass = when (cache) BoxCache.LONG -> longClass }.owner +// TODO: consider adding box caches for unsigned types. enum class BoxCache { BOOLEAN, BYTE, SHORT, CHAR, INT, LONG } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt index 54e625430f8..448ac8f9a99 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt @@ -25,18 +25,16 @@ import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.konan.descriptors.isUnit import org.jetbrains.kotlin.backend.konan.llvm.* +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.annotations.* -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.name.isChildOf import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension -import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isUnit @@ -760,14 +758,18 @@ internal class CAdapterGenerator( typedef _Bool ${prefix}_KBoolean; #endif """.trimIndent()) - output("typedef char ${prefix}_KByte;") - output("typedef unsigned short ${prefix}_KChar;") - output("typedef short ${prefix}_KShort;") - output("typedef int ${prefix}_KInt;") - output("typedef long long ${prefix}_KLong;") - output("typedef float ${prefix}_KFloat;") - output("typedef double ${prefix}_KDouble;") - output("typedef void* ${prefix}_KNativePtr;") + output("typedef unsigned short ${prefix}_KChar;") + output("typedef signed char ${prefix}_KByte;") + output("typedef short ${prefix}_KShort;") + output("typedef int ${prefix}_KInt;") + output("typedef long long ${prefix}_KLong;") + output("typedef unsigned char ${prefix}_KUByte;") + output("typedef unsigned short ${prefix}_KUShort;") + output("typedef unsigned int ${prefix}_KUInt;") + output("typedef unsigned long long ${prefix}_KULong;") + output("typedef float ${prefix}_KFloat;") + output("typedef double ${prefix}_KDouble;") + output("typedef void* ${prefix}_KNativePtr;") output("struct ${prefix}_KType;") output("typedef struct ${prefix}_KType ${prefix}_KType;") @@ -894,6 +896,15 @@ internal class CAdapterGenerator( } } + private val unsignedTypeMapping = UnsignedType.values().associate { + it.classId to when (it) { + UnsignedType.UBYTE -> "${prefix}_KUByte" + UnsignedType.USHORT -> "${prefix}_KUShort" + UnsignedType.UINT -> "${prefix}_KUInt" + UnsignedType.ULONG -> "${prefix}_KULong" + } + } + internal fun isMappedToString(descriptor: ClassDescriptor): Boolean = isMappedToString(descriptor.defaultType.computeBinaryType()) @@ -926,8 +937,10 @@ internal class CAdapterGenerator( } private fun translateNonVoidTypeFull(type: KotlinType): Pair = type.unwrapToPrimitiveOrReference( - eachInlinedClass = { _, _ -> - // unsigned types to be handled. + eachInlinedClass = { inlinedClass, _ -> + unsignedTypeMapping[inlinedClass.classId]?.let { + return it to it + } }, ifPrimitive = { primitiveType, _ -> primitiveTypeMapping[primitiveType]!!.let { it to it } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 15b669b506b..c03bf930539 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.kotlinNativeInternal import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint import org.jetbrains.kotlin.backend.konan.lower.TestProcessor import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName import org.jetbrains.kotlin.config.coroutinesPackageFqName @@ -134,6 +135,14 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val val nativePtr = symbolTable.referenceClass(context.nativePtr) val nativePtrType = nativePtr.typeWith(arguments = emptyList()) + private fun unsignedClass(unsignedType: UnsignedType): IrClassSymbol = + symbolTable.referenceClass(builtIns.builtInsModule.findClassAcrossModuleDependencies(unsignedType.classId)!!) + + val uByte = unsignedClass(UnsignedType.UBYTE) + val uShort = unsignedClass(UnsignedType.USHORT) + val uInt = unsignedClass(UnsignedType.UINT) + val uLong = unsignedClass(UnsignedType.ULONG) + val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context)) val interopNativePointedGetRawPointer = diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt index 86c3a6a912a..8a619042fb8 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/objcexport/ObjCExportCodeGenerator.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.types.KotlinType @@ -95,8 +96,11 @@ internal class ObjCExportCodeGenerator( ): LLVMValueRef = when (valueType) { ObjCValueType.BOOL -> zext(value, int8Type) // TODO: zext behaviour may be strange on bit types. - ObjCValueType.CHAR, ObjCValueType.UNSIGNED_SHORT, ObjCValueType.SHORT, - ObjCValueType.INT, ObjCValueType.LONG_LONG, ObjCValueType.FLOAT, ObjCValueType.DOUBLE -> value + ObjCValueType.UNICHAR, + ObjCValueType.CHAR, ObjCValueType.SHORT, ObjCValueType.INT, ObjCValueType.LONG_LONG, + ObjCValueType.UNSIGNED_CHAR, ObjCValueType.UNSIGNED_SHORT, ObjCValueType.UNSIGNED_INT, + ObjCValueType.UNSIGNED_LONG_LONG, + ObjCValueType.FLOAT, ObjCValueType.DOUBLE -> value } private fun FunctionGenerationContext.objCToKotlin( @@ -105,8 +109,11 @@ internal class ObjCExportCodeGenerator( ): LLVMValueRef = when (valueType) { ObjCValueType.BOOL -> icmpNe(value, Int8(0).llvm) - ObjCValueType.CHAR, ObjCValueType.UNSIGNED_SHORT, ObjCValueType.SHORT, - ObjCValueType.INT, ObjCValueType.LONG_LONG, ObjCValueType.FLOAT, ObjCValueType.DOUBLE -> value + ObjCValueType.UNICHAR, + ObjCValueType.CHAR, ObjCValueType.SHORT, ObjCValueType.INT, ObjCValueType.LONG_LONG, + ObjCValueType.UNSIGNED_CHAR, ObjCValueType.UNSIGNED_SHORT, ObjCValueType.UNSIGNED_INT, + ObjCValueType.UNSIGNED_LONG_LONG, + ObjCValueType.FLOAT, ObjCValueType.DOUBLE -> value } fun FunctionGenerationContext.kotlinReferenceToObjC(value: LLVMValueRef) = @@ -340,22 +347,30 @@ private fun ObjCExportCodeGenerator.setObjCExportTypeInfo( private val ObjCExportCodeGenerator.kotlinToObjCFunctionType: LLVMTypeRef get() = functionType(int8TypePtr, false, codegen.kObjHeaderPtr) -private fun ObjCExportCodeGenerator.emitBoxConverter(objCValueType: ObjCValueType) { - val symbols = context.ir.symbols +private fun ObjCExportCodeGenerator.emitBoxConverters() { val irBuiltIns = context.irBuiltIns + val symbols = context.ir.symbols - val boxClass = when (objCValueType) { - ObjCValueType.BOOL -> irBuiltIns.booleanClass - ObjCValueType.UNSIGNED_SHORT -> irBuiltIns.charClass - ObjCValueType.CHAR -> irBuiltIns.byteClass - ObjCValueType.SHORT -> irBuiltIns.shortClass - ObjCValueType.INT -> irBuiltIns.intClass - ObjCValueType.LONG_LONG -> irBuiltIns.longClass - ObjCValueType.FLOAT -> irBuiltIns.floatClass - ObjCValueType.DOUBLE -> irBuiltIns.doubleClass - }.owner + emitBoxConverter(irBuiltIns.booleanClass, ObjCValueType.BOOL, "numberWithBool:") + emitBoxConverter(irBuiltIns.byteClass, ObjCValueType.CHAR, "numberWithChar:") + emitBoxConverter(irBuiltIns.shortClass, ObjCValueType.SHORT, "numberWithShort:") + emitBoxConverter(irBuiltIns.intClass, ObjCValueType.INT, "numberWithInt:") + emitBoxConverter(irBuiltIns.longClass, ObjCValueType.LONG_LONG, "numberWithLongLong:") + emitBoxConverter(symbols.uByte, ObjCValueType.UNSIGNED_CHAR, "numberWithUnsignedChar") + emitBoxConverter(symbols.uShort, ObjCValueType.UNSIGNED_SHORT, "numberWithUnsignedShort:") + emitBoxConverter(symbols.uInt, ObjCValueType.UNSIGNED_INT, "numberWithUnsignedInt:") + emitBoxConverter(symbols.uLong, ObjCValueType.UNSIGNED_LONG_LONG, "numberWithUnsignedLongLong:") + emitBoxConverter(irBuiltIns.floatClass, ObjCValueType.FLOAT, "numberWithFloat:") + emitBoxConverter(irBuiltIns.doubleClass, ObjCValueType.DOUBLE, "numberWithDouble:") +} - val name = "${boxClass.name}To${objCValueType.nsNumberName}" +private fun ObjCExportCodeGenerator.emitBoxConverter( + boxClassSymbol: IrClassSymbol, + objCValueType: ObjCValueType, + nsNumberFactorySelector: String +) { + val boxClass = boxClassSymbol.owner + val name = "${boxClass.name}ToNSNumber" val converter = generateFunction(codegen, kotlinToObjCFunctionType, name) { val unboxFunction = context.getUnboxFunction(boxClass).llvmFunction @@ -368,7 +383,7 @@ private fun ObjCExportCodeGenerator.emitBoxConverter(objCValueType: ObjCValueTyp val value = kotlinToObjC(kotlinValue, objCValueType) val nsNumber = genGetSystemClass("NSNumber") - ret(genSendMessage(int8TypePtr, nsNumber, objCValueType.nsNumberFactorySelector, value)) + ret(genSendMessage(int8TypePtr, nsNumber, nsNumberFactorySelector, value)) } LLVMSetLinkage(converter, LLVMLinkage.LLVMPrivateLinkage) @@ -446,9 +461,7 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() { constPointer(context.llvm.Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap) ) - ObjCValueType.values().forEach { - emitBoxConverter(it) - } + emitBoxConverters() emitFunctionConverters() @@ -1091,11 +1104,15 @@ private fun objCFunctionType(context: Context, methodBridge: MethodBridge): LLVM private val ObjCValueType.llvmType: LLVMTypeRef get() = when (this) { ObjCValueType.BOOL -> int8Type + ObjCValueType.UNICHAR -> int16Type ObjCValueType.CHAR -> int8Type - ObjCValueType.UNSIGNED_SHORT -> int16Type ObjCValueType.SHORT -> int16Type ObjCValueType.INT -> int32Type ObjCValueType.LONG_LONG -> int64Type + ObjCValueType.UNSIGNED_CHAR -> int8Type + ObjCValueType.UNSIGNED_SHORT -> int16Type + ObjCValueType.UNSIGNED_INT -> int32Type + ObjCValueType.UNSIGNED_LONG_LONG -> int64Type ObjCValueType.FLOAT -> LLVMFloatType()!! ObjCValueType.DOUBLE -> LLVMDoubleType()!! } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt index 5891ee7761c..c7bf8360001 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportHeaderGenerator.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.konan.objcexport import org.jetbrains.kotlin.backend.konan.* import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName @@ -66,13 +67,18 @@ abstract class ObjCExportHeaderGenerator( result += CustomTypeMapper.Collection(generator, map, "NSDictionary") result += CustomTypeMapper.Collection(generator, mutableMap, namer.mutableMapName) - for (descriptor in listOf(boolean, char, byte, short, int, long, float, double)) { + for (descriptor in listOf(boolean, byte, short, int, long, float, double)) { // TODO: Kotlin code doesn't have any checkcasts on unboxing, // so it is possible that it expects boxed number of other type and unboxes it incorrectly. // TODO: NSNumber seem to have different equality semantics. result += CustomTypeMapper.Simple(descriptor, "NSNumber") } + for (unsignedType in UnsignedType.values()) { + val descriptor = moduleDescriptor.findClassAcrossModuleDependencies(unsignedType.classId)!! + result += CustomTypeMapper.Simple(descriptor, "NSNumber") + } + result += CustomTypeMapper.Simple(string, "NSString") (0..mapper.maxFunctionTypeParameterCount).forEach { @@ -737,11 +743,15 @@ abstract class ObjCExportHeaderGenerator( is ValueTypeBridge -> { val cName = when (typeBridge.objCValueType) { ObjCValueType.BOOL -> "BOOL" + ObjCValueType.UNICHAR -> "unichar" ObjCValueType.CHAR -> "int8_t" - ObjCValueType.UNSIGNED_SHORT -> "unichar" ObjCValueType.SHORT -> "int16_t" ObjCValueType.INT -> "int32_t" ObjCValueType.LONG_LONG -> "int64_t" + ObjCValueType.UNSIGNED_CHAR -> "uint8_t" + ObjCValueType.UNSIGNED_SHORT -> "uint16_t" + ObjCValueType.UNSIGNED_INT -> "uint32_t" + ObjCValueType.UNSIGNED_LONG_LONG -> "uint64_t" ObjCValueType.FLOAT -> "float" ObjCValueType.DOUBLE -> "double" } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt index 452599a548b..b2c142623e0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/ObjCExportMapper.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors import org.jetbrains.kotlin.backend.konan.descriptors.isArray import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.types.KotlinType @@ -111,13 +112,18 @@ internal fun ObjCExportMapper.doesThrow(method: FunctionDescriptor): Boolean = m } private fun ObjCExportMapper.bridgeType(kotlinType: KotlinType): TypeBridge = kotlinType.unwrapToPrimitiveOrReference( - eachInlinedClass = { _, _ -> - // unsigned types to be handled. + eachInlinedClass = { inlinedClass, _ -> + when (inlinedClass.classId) { + UnsignedType.UBYTE.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_CHAR) + UnsignedType.USHORT.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_SHORT) + UnsignedType.UINT.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_INT) + UnsignedType.ULONG.classId -> return ValueTypeBridge(ObjCValueType.UNSIGNED_LONG_LONG) + } }, ifPrimitive = { primitiveType, _ -> val objCValueType = when (primitiveType) { KonanPrimitiveType.BOOLEAN -> ObjCValueType.BOOL - KonanPrimitiveType.CHAR -> ObjCValueType.UNSIGNED_SHORT + KonanPrimitiveType.CHAR -> ObjCValueType.UNICHAR KonanPrimitiveType.BYTE -> ObjCValueType.CHAR KonanPrimitiveType.SHORT -> ObjCValueType.SHORT KonanPrimitiveType.INT -> ObjCValueType.INT @@ -219,4 +225,4 @@ internal fun ObjCExportMapper.bridgePropertyType(descriptor: PropertyDescriptor) assert(isBaseProperty(descriptor)) return bridgeType(descriptor.type) -} \ No newline at end of file +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt index e0dc309ba82..b495f803703 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/objcexport/objcTypes.kt @@ -111,27 +111,17 @@ object ObjCVoidType : ObjCType() { override fun render(attrsAndName: String) = "void".withAttrsAndName(attrsAndName) } -internal enum class ObjCValueType( - val encoding: String -) { - +internal enum class ObjCValueType(val encoding: String) { BOOL("c"), + UNICHAR("S"), CHAR("c"), SHORT("s"), - UNSIGNED_SHORT("S"), INT("i"), LONG_LONG("q"), + UNSIGNED_CHAR("C"), + UNSIGNED_SHORT("S"), + UNSIGNED_INT("I"), + UNSIGNED_LONG_LONG("Q"), FLOAT("f"), DOUBLE("d") - - ; - - // UNSIGNED_SHORT -> unsignedShort - val nsNumberName = this.name.split('_').mapIndexed { index, s -> - val lower = s.toLowerCase() - if (index > 0) lower.capitalize() else lower - }.joinToString("") - - val nsNumberValueSelector get() = "${nsNumberName}Value" - val nsNumberFactorySelector get() = "numberWith${nsNumberName.capitalize()}:" } diff --git a/runtime/src/main/cpp/ObjCExport.mm b/runtime/src/main/cpp/ObjCExport.mm index 859669e5064..7da7ae468cb 100644 --- a/runtime/src/main/cpp/ObjCExport.mm +++ b/runtime/src/main/cpp/ObjCExport.mm @@ -433,11 +433,14 @@ static void initializeObjCExport() { extern "C" { OBJ_GETTER(Kotlin_boxBoolean, KBoolean value); -OBJ_GETTER(Kotlin_boxChar, KChar value); OBJ_GETTER(Kotlin_boxByte, KByte value); OBJ_GETTER(Kotlin_boxShort, KShort value); OBJ_GETTER(Kotlin_boxInt, KInt value); OBJ_GETTER(Kotlin_boxLong, KLong value); +OBJ_GETTER(Kotlin_boxUByte, KUByte value); +OBJ_GETTER(Kotlin_boxUShort, KUShort value); +OBJ_GETTER(Kotlin_boxUInt, KUInt value); +OBJ_GETTER(Kotlin_boxULong, KULong value); OBJ_GETTER(Kotlin_boxFloat, KFloat value); OBJ_GETTER(Kotlin_boxDouble, KDouble value); @@ -457,11 +460,14 @@ static OBJ_GETTER(boxedBooleanToKotlinImp, NSNumber* self, SEL cmd) { // TODO: the code below makes some assumption on char, short, int and long sizes. switch (type[0]) { - case 'S': RETURN_RESULT_OF(Kotlin_boxChar, self.unsignedShortValue); case 'c': RETURN_RESULT_OF(Kotlin_boxByte, self.charValue); case 's': RETURN_RESULT_OF(Kotlin_boxShort, self.shortValue); case 'i': RETURN_RESULT_OF(Kotlin_boxInt, self.intValue); case 'q': RETURN_RESULT_OF(Kotlin_boxLong, self.longLongValue); + case 'C': RETURN_RESULT_OF(Kotlin_boxUByte, self.unsignedCharValue); + case 'S': RETURN_RESULT_OF(Kotlin_boxUShort, self.unsignedShortValue); + case 'I': RETURN_RESULT_OF(Kotlin_boxUInt, self.unsignedIntValue); + case 'Q': RETURN_RESULT_OF(Kotlin_boxULong, self.unsignedLongLongValue); case 'f': RETURN_RESULT_OF(Kotlin_boxFloat, self.floatValue); case 'd': RETURN_RESULT_OF(Kotlin_boxDouble, self.doubleValue); diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index db2522a5bb0..f26dddf13f5 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -42,6 +42,10 @@ typedef uint16_t KChar; typedef int16_t KShort; typedef int32_t KInt; typedef int64_t KLong; +typedef uint8_t KUByte; +typedef uint16_t KUShort; +typedef uint32_t KUInt; +typedef uint64_t KULong; typedef float KFloat; typedef double KDouble; typedef void* KNativePtr; diff --git a/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt b/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt index 98ee13b0662..706f63d3739 100644 --- a/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt +++ b/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt @@ -237,6 +237,29 @@ external private fun copyImpl(array: IntArray, fromIndex: Int, external private fun copyImpl(array: LongArray, fromIndex: Int, destination: LongArray, toIndex: Int, count: Int) +// Note: [copyImpl] for an unsigned array is bitwise identical to signed type, so +// signed array implementations from runtime are directly reused for unsigned ones. + +@ExperimentalUnsignedTypes +@SymbolName("Kotlin_ByteArray_copyImpl") +external private fun copyImpl(array: UByteArray, fromIndex: Int, + destination: UByteArray, toIndex: Int, count: Int) + +@ExperimentalUnsignedTypes +@SymbolName("Kotlin_ShortArray_copyImpl") +external private fun copyImpl(array: UShortArray, fromIndex: Int, + destination: UShortArray, toIndex: Int, count: Int) + +@ExperimentalUnsignedTypes +@SymbolName("Kotlin_IntArray_copyImpl") +external private fun copyImpl(array: UIntArray, fromIndex: Int, + destination: UIntArray, toIndex: Int, count: Int) + +@ExperimentalUnsignedTypes +@SymbolName("Kotlin_LongArray_copyImpl") +external private fun copyImpl(array: ULongArray, fromIndex: Int, + destination: ULongArray, toIndex: Int, count: Int) + @SymbolName("Kotlin_FloatArray_copyImpl") external private fun copyImpl(array: FloatArray, fromIndex: Int, destination: FloatArray, toIndex: Int, count: Int) @@ -279,6 +302,30 @@ fun LongArray.copyRangeTo(destination: LongArray, fromIndex: Int, toIndex: Int, copyImpl(this, fromIndex, destination, destinationIndex, toIndex - fromIndex) } +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +fun UByteArray.copyRangeTo(destination: UByteArray, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) { + copyImpl(this, fromIndex, destination, destinationIndex, toIndex - fromIndex) +} + +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +fun UShortArray.copyRangeTo(destination: UShortArray, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) { + copyImpl(this, fromIndex, destination, destinationIndex, toIndex - fromIndex) +} + +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +fun UIntArray.copyRangeTo(destination: UIntArray, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) { + copyImpl(this, fromIndex, destination, destinationIndex, toIndex - fromIndex) +} + +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +fun ULongArray.copyRangeTo(destination: ULongArray, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) { + copyImpl(this, fromIndex, destination, destinationIndex, toIndex - fromIndex) +} + fun FloatArray.copyRangeTo(destination: FloatArray, fromIndex: Int, toIndex: Int, destinationIndex: Int = 0) { copyImpl(this, fromIndex, destination, destinationIndex, toIndex - fromIndex) } diff --git a/runtime/src/main/kotlin/kotlin/collections/Arrays.kt b/runtime/src/main/kotlin/kotlin/collections/Arrays.kt index 884b9d6e113..08ad6811edf 100644 --- a/runtime/src/main/kotlin/kotlin/collections/Arrays.kt +++ b/runtime/src/main/kotlin/kotlin/collections/Arrays.kt @@ -514,6 +514,94 @@ public actual fun LongArray.contentToString(): String { } } +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun UByteArray.contentToString(): String { + if (size == 0) + return "[]" + val iMax = size - 1 + + val b = StringBuilder() + b.append('[') + var i = 0 + while (true) { + b.append(this[i]) + if (i == iMax) + return b.append(']').toString() + b.append(", ") + i++ + } +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun UShortArray.contentToString(): String { + if (size == 0) + return "[]" + val iMax = size - 1 + + val b = StringBuilder() + b.append('[') + var i = 0 + while (true) { + b.append(this[i]) + if (i == iMax) + return b.append(']').toString() + b.append(", ") + i++ + } +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun UIntArray.contentToString(): String { + if (size == 0) + return "[]" + val iMax = size - 1 + + val b = StringBuilder() + b.append('[') + var i = 0 + while (true) { + b.append(this[i]) + if (i == iMax) + return b.append(']').toString() + b.append(", ") + i++ + } +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun ULongArray.contentToString(): String { + if (size == 0) + return "[]" + val iMax = size - 1 + + val b = StringBuilder() + b.append('[') + var i = 0 + while (true) { + b.append(this[i]) + if (i == iMax) + return b.append(']').toString() + b.append(", ") + i++ + } +} + /** * Returns a string representation of the contents of the specified array as if it is [List]. */ @@ -972,6 +1060,54 @@ public actual fun LongArray.contentHashCode(): Int { return result } +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun UByteArray.contentHashCode(): Int { + var result = 1 + for (element in this) + result = 31 * result + element.hashCode() + return result +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun UShortArray.contentHashCode(): Int { + var result = 1 + for (element in this) + result = 31 * result + element.hashCode() + return result +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun UIntArray.contentHashCode(): Int { + var result = 1 + for (element in this) + result = 31 * result + element.hashCode() + return result +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public fun ULongArray.contentHashCode(): Int { + var result = 1 + for (element in this) + result = 31 * result + element.hashCode() + return result +} + /** * Returns a hash code based on the contents of this array as if it is [List]. */ diff --git a/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt b/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt index e04e2fbe618..2747f105832 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt @@ -61,6 +61,22 @@ fun boxInt(value: Int): Int? = value @ExportForCppRuntime("Kotlin_boxLong") fun boxLong(value: Long): Long? = value +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_boxUByte") +fun boxUByte(value: UByte): UByte? = value + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_boxUShort") +fun boxUShort(value: UShort): UShort? = value + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_boxUInt") +fun boxUInt(value: UInt): UInt? = value + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_boxULong") +fun boxULong(value: ULong): ULong? = value + @ExportForCppRuntime("Kotlin_boxFloat") fun boxFloat(value: Float): Float? = value