Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Support unsigned types #1854

Merged
merged 2 commits into from
Aug 17, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;")

Expand Down Expand Up @@ -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())

Expand Down Expand Up @@ -926,8 +937,10 @@ internal class CAdapterGenerator(
}

private fun translateNonVoidTypeFull(type: KotlinType): Pair<String, String> = 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 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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) =
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -446,9 +461,7 @@ private fun ObjCExportCodeGenerator.emitSpecialClassesConvertions() {
constPointer(context.llvm.Kotlin_Interop_CreateKotlinMutableDictonaryFromKMap)
)

ObjCValueType.values().forEach {
emitBoxConverter(it)
}
emitBoxConverters()

emitFunctionConverters()

Expand Down Expand Up @@ -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
Copy link
Contributor

@olonho olonho Aug 9, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make it map/array indexed by ObjCValueType ordinal?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kotlin compiler appears to optimize when over enum entries.

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()!!
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -219,4 +225,4 @@ internal fun ObjCExportMapper.bridgePropertyType(descriptor: PropertyDescriptor)
assert(isBaseProperty(descriptor))

return bridgeType(descriptor.type)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()}:"
}
10 changes: 8 additions & 2 deletions runtime/src/main/cpp/ObjCExport.mm
Original file line number Diff line number Diff line change
Expand Up @@ -433,11 +433,14 @@ -(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
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);

Expand All @@ -457,11 +460,14 @@ -(ObjHeader*)toKotlin:(ObjHeader**)OBJ_RESULT {
// 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);

Expand Down
4 changes: 4 additions & 0 deletions runtime/src/main/cpp/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading