diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt index caeb51c79fe..d246c3d2344 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CAdapterGenerator.kt @@ -33,7 +33,6 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.makeNullable -import org.jetbrains.kotlin.utils.addIfNotNull private enum class ScopeKind { TOP, @@ -72,6 +71,9 @@ private val KotlinType.shortNameForPredefinedType private val KotlinType.createNullableNameForPredefinedType get() = "createNullable${this.shortNameForPredefinedType}" +private val KotlinType.createGetNonNullValueOfPredefinedType + get() = "getNonNullValueOf${this.shortNameForPredefinedType}" + internal val cKeywords = setOf( // Actual C keywords. "auto", "break", "case", @@ -532,12 +534,17 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi private var symbolTableOrNull: SymbolTable? = null internal val symbolTable get() = symbolTableOrNull!! + // Primitive built-ins and unsigned types private val predefinedTypes = listOf( context.builtIns.byteType, context.builtIns.shortType, context.builtIns.intType, context.builtIns.longType, context.builtIns.floatType, context.builtIns.doubleType, context.builtIns.charType, context.builtIns.booleanType, - context.builtIns.unitType) + context.builtIns.unitType + ) + UnsignedType.values().map { + // Unfortunately, `context.ir` and `context.irBuiltins` are not initialized, so `context.ir.symbols.ubyte`, etc, are unreachable. + context.builtIns.builtInsModule.findClassAcrossModuleDependencies(it.classId)!!.defaultType + } internal fun paramsToUniqueNames(params: List): Map { paramNamesRecorded.clear() @@ -800,7 +807,7 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi defineUsedTypesImpl(scope, usedTypes) val usedReferenceTypes = usedTypes.filter { isMappedToReference(it) } // Add nullable primitives, which are used in prototypes of "(*createNullable)" - val predefinedNullableTypes = predefinedTypes.map { it.makeNullable() } + val predefinedNullableTypes: List = predefinedTypes.map { it.makeNullable() } (predefinedNullableTypes + usedReferenceTypes) .map { translateType(it) } @@ -880,6 +887,8 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi val nullableIt = it.makeNullable() val argument = if (!it.isUnit()) translateType(it) else "void" output("${translateType(nullableIt)} (*${it.createNullableNameForPredefinedType})($argument);", 1) + if(!it.isUnit()) + output("$argument (*${it.createGetNonNullValueOfPredefinedType})(${translateType(nullableIt)});", 1) } output("") @@ -1009,6 +1018,16 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi output("KObjHeader* result = Kotlin_box${it.shortNameForPredefinedType}($argument result_holder.slot());", 1) output("return ${translateType(nullableIt)} { .pinned = CreateStablePointer(result) };", 1) output("}") + + if (!it.isUnit()) { + output("extern \"C\" ${translateType(it)} Kotlin_unbox${it.shortNameForPredefinedType}(KObjHeader*);") + output("static ${translateType(it)} ${it.createGetNonNullValueOfPredefinedType}Impl(${translateType(nullableIt)} value) {") + output("Kotlin_initRuntimeIfNeeded();", 1) + output("ScopedRunnableState stateGuard;", 1) + output("KObjHolder value_holder;", 1) + output("return Kotlin_unbox${it.shortNameForPredefinedType}(DerefStablePointer(value.pinned, value_holder.slot()));", 1) + output("}") + } } makeScopeDefinitions(top, DefinitionKind.C_SOURCE_DECLARATION, 0) output("static ${prefix}_ExportedSymbols __konan_symbols = {") @@ -1017,6 +1036,9 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi output(".IsInstance = IsInstanceImpl,", 1) predefinedTypes.forEach { output(".${it.createNullableNameForPredefinedType} = ${it.createNullableNameForPredefinedType}Impl,", 1) + if (!it.isUnit()) { + output(".${it.createGetNonNullValueOfPredefinedType} = ${it.createGetNonNullValueOfPredefinedType}Impl,", 1) + } } makeScopeDefinitions(top, DefinitionKind.C_SOURCE_STRUCT, 1) diff --git a/kotlin-native/backend.native/tests/build.gradle b/kotlin-native/backend.native/tests/build.gradle index 78c44c5164c..f18e6020102 100644 --- a/kotlin-native/backend.native/tests/build.gradle +++ b/kotlin-native/backend.native/tests/build.gradle @@ -5236,6 +5236,13 @@ for (i in 0..2) { } } +dynamicTest("kt42830") { + disabled = (project.testTarget == 'wasm32') // wasm doesn't support -produce dynamic + source = "produce_dynamic/kt-42830/box_unbox.kt" + cSource = "$projectDir/produce_dynamic/kt-42830/main.c" + useGoldenData = true +} + dynamicTest("produce_dynamic_unhandledException") { disabled = (project.testTarget == 'wasm32') || // Uses exceptions + dynamic is unsupported for wasm. (cacheTesting != null) // Disabled due to KT-47828. diff --git a/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/box_unbox-main.out b/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/box_unbox-main.out new file mode 100644 index 00000000000..3a1398d6ab9 --- /dev/null +++ b/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/box_unbox-main.out @@ -0,0 +1,36 @@ +true +true +true +￿ +￿ +￿ +-128 +-128 +-128 +-32768 +-32768 +-32768 +-2147483648 +-2147483648 +-2147483648 +-9223372036854775808 +-9223372036854775808 +-9223372036854775808 +3.4028235E38 +3.4028235E38 +3.4028235E38 +1.7976931348623157E308 +1.7976931348623157E308 +1.7976931348623157E308 +255 +255 +255 +65535 +65535 +65535 +4294967295 +4294967295 +4294967295 +18446744073709551615 +18446744073709551615 +18446744073709551615 diff --git a/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/box_unbox.kt b/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/box_unbox.kt new file mode 100644 index 00000000000..9812eb6c695 --- /dev/null +++ b/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/box_unbox.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +fun printAny(v: Any?) { + println(v) +} + +fun printBoolean(v: Boolean) { + println(v) +} +fun printChar(v: Char) { + println(v) +} +fun printByte(v: Byte) { + println(v) +} +fun printShort(v: Short) { + println(v) +} +fun printInt(v: Int) { + println(v) +} +fun printLong(v: Long) { + println(v) +} +fun printFloat(v: Float) { + println(v) +} +fun printDouble(v: Double) { + println(v) +} +fun printUByte(v: UByte) { + println(v) +} +fun printUShort(v: UShort) { + println(v) +} +fun printUInt(v: UInt) { + println(v) +} +fun printULong(v: ULong) { + println(v) +} diff --git a/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/main.c b/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/main.c new file mode 100644 index 00000000000..f72e5c77ef1 --- /dev/null +++ b/kotlin-native/backend.native/tests/produce_dynamic/kt-42830/main.c @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ +#include "testlib_api.h" +#define __ testlib_symbols()-> +#define T_(x) testlib_kref_ ## x + +#include +#include +#include +#include + +#define TEST_TYPE_VAL(TYPE_C, TYPE, VAL) \ + TYPE_C primitive##TYPE = VAL; \ + __ kotlin.root.print##TYPE (primitive##TYPE); \ + T_(kotlin_##TYPE) nullable##TYPE = __ createNullable##TYPE (primitive##TYPE); \ + T_(kotlin_Any) any##TYPE = { .pinned = nullable##TYPE.pinned }; \ + __ kotlin.root.printAny (any##TYPE); \ + TYPE_C unboxed##TYPE = __ getNonNullValueOf##TYPE (nullable##TYPE); \ + __ kotlin.root.print##TYPE (unboxed##TYPE); + + +int main(int argc, char** argv) { + TEST_TYPE_VAL(bool, Boolean, true); + TEST_TYPE_VAL(uint16_t, Char, UINT16_MAX); + TEST_TYPE_VAL(int8_t, Byte, INT8_MIN); + TEST_TYPE_VAL(int16_t, Short, INT16_MIN); + TEST_TYPE_VAL(int32_t, Int, INT32_MIN); + TEST_TYPE_VAL(int64_t, Long, INT64_MIN); + TEST_TYPE_VAL(float, Float, FLT_MAX); + TEST_TYPE_VAL(double, Double, DBL_MAX); + TEST_TYPE_VAL(uint8_t, UByte, UINT8_MAX); + TEST_TYPE_VAL(uint16_t, UShort, UINT16_MAX); + TEST_TYPE_VAL(uint32_t, UInt, UINT32_MAX); + TEST_TYPE_VAL(uint64_t, ULong, UINT64_MAX); +} diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt index 3887f35a7e5..78fcdbd2f8b 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/Boxing.kt @@ -41,7 +41,7 @@ external fun getCachedLongBox(value: Long): Long? @GCUnsafeCall("inLongBoxCache") external fun inLongBoxCache(value: Long): Boolean -// TODO: functions below are used for ObjCExport, move and rename them correspondigly. +// TODO: functions below are used for ObjCExport and CAdapterGenerator, move and rename them correspondigly. @ExportForCppRuntime("Kotlin_boxBoolean") fun boxBoolean(value: Boolean): Boolean? = value @@ -84,4 +84,46 @@ fun boxFloat(value: Float): Float? = value fun boxDouble(value: Double): Double? = value @ExportForCppRuntime("Kotlin_boxUnit") -internal fun Kotlin_boxUnit(): Unit? = Unit \ No newline at end of file +internal fun Kotlin_boxUnit(): Unit? = Unit + +// Unbox fuctions + +@ExportForCppRuntime("Kotlin_unboxBoolean") +fun unboxBoolean(value: Boolean?): Boolean = value!! + +@ExportForCppRuntime("Kotlin_unboxChar") +fun unboxChar(value: Char?): Char = value!! + +@ExportForCppRuntime("Kotlin_unboxByte") +fun unboxByte(value: Byte?): Byte = value!! + +@ExportForCppRuntime("Kotlin_unboxShort") +fun unboxShort(value: Short?): Short = value!! + +@ExportForCppRuntime("Kotlin_unboxInt") +fun unboxInt(value: Int?): Int = value!! + +@ExportForCppRuntime("Kotlin_unboxLong") +fun unboxLong(value: Long?): Long = value!! + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_unboxUByte") +fun unboxUByte(value: UByte?): UByte = value!! + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_unboxUShort") +fun unboxUShort(value: UShort?): UShort = value!! + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_unboxUInt") +fun unboxUInt(value: UInt?): UInt = value!! + +@ExperimentalUnsignedTypes +@ExportForCppRuntime("Kotlin_unboxULong") +fun unboxULong(value: ULong?): ULong = value!! + +@ExportForCppRuntime("Kotlin_unboxFloat") +fun unboxFloat(value: Float?): Float = value!! + +@ExportForCppRuntime("Kotlin_unboxDouble") +fun unboxDouble(value: Double?): Double = value!!