diff --git a/backend.native/tests/runtime/collections/typed_array0.kt b/backend.native/tests/runtime/collections/typed_array0.kt index f99a6b1a251..e2baf4f40d9 100644 --- a/backend.native/tests/runtime/collections/typed_array0.kt +++ b/backend.native/tests/runtime/collections/typed_array0.kt @@ -12,6 +12,7 @@ import kotlin.test.* val array = ByteArray(42) array.setLongAt(5, 0x1234_5678_9abc_def0) + expect(0x1234_5678_9abc_def0) { array.getLongAt(5) } expect(0xdef0.toInt()) { array.getCharAt(5).toInt() } expect(0x9abc.toShort()) { array.getShortAt(7) } expect(0x1234_5678) { array.getIntAt(9) } @@ -20,5 +21,10 @@ import kotlin.test.* expect(0xf0u) { array.getUByteAt(5) } expect(0x1234_5678_9abcuL) { array.getULongAt(7) } + array.setIntAt(2, 0x40100000) + expect(2.25f) { array.getFloatAt(2) } + array.setLongAt(11, 0x400c_0000_0000_0000) + expect(3.5) { array.getDoubleAt(11) } + println("OK") } \ No newline at end of file diff --git a/backend.native/tests/runtime/collections/typed_array1.kt b/backend.native/tests/runtime/collections/typed_array1.kt index cd3c7b8b049..62f49a5b17d 100644 --- a/backend.native/tests/runtime/collections/typed_array1.kt +++ b/backend.native/tests/runtime/collections/typed_array1.kt @@ -6,74 +6,68 @@ package runtime.collections.typed_array1 import kotlin.test.* +import kotlin.native.concurrent.* @Test fun runTest() { val array = ByteArray(17) val results = mutableSetOf() var counter = 0 - try { + assertFailsWith { results += array.getShortAt(16) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { results += array.getCharAt(22) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { results += array.getIntAt(15) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { results += array.getLongAt(14) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { results += array.getFloatAt(14) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { results += array.getDoubleAt(13) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - - try { + assertFailsWith { array.setShortAt(16, 2.toShort()) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { array.setCharAt(22, 'a') - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { array.setIntAt(15, 1234) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { array.setLongAt(14, 1.toLong()) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { array.setFloatAt(14, 1.0f) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - try { + assertFailsWith { array.setDoubleAt(13, 3.0) - } catch (e: ArrayIndexOutOfBoundsException) { - counter++ } - - expect(12) { counter } expect(0) { results.size } + + array.freeze() + assertFailsWith { + array.setShortAt(0, 2.toShort()) + } + assertFailsWith { + array.setCharAt(0, 'a') + } + assertFailsWith { + array.setIntAt(0, 2) + } + assertFailsWith { + array.setLongAt(0, 2) + } + assertFailsWith { + array.setFloatAt(0, 1.0f) + } + assertFailsWith { + array.setDoubleAt(0, 1.0) + } println("OK") } \ No newline at end of file diff --git a/runtime/src/main/cpp/Arrays.cpp b/runtime/src/main/cpp/Arrays.cpp index 440678eaa6b..95b4598403f 100644 --- a/runtime/src/main/cpp/Arrays.cpp +++ b/runtime/src/main/cpp/Arrays.cpp @@ -166,12 +166,17 @@ KChar Kotlin_ByteArray_getCharAt(KConstRef thiz, KInt index) { if (static_cast(index + 1) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } +#if KONAN_NO_UNALIGNED_ACCESS + const uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + return (static_cast(address[0]) << 0) | (static_cast(address[1]) << 8); +#else auto result = *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); #if __BIG_ENDIAN__ return __builtin_bswap16(result); #else return result; -#endif +#endif // __BIG_ENDIAN__ +#endif // KONAN_NO_UNALIGNED_ACCESS } KShort Kotlin_ByteArray_getShortAt(KConstRef thiz, KInt index) { @@ -179,12 +184,17 @@ KShort Kotlin_ByteArray_getShortAt(KConstRef thiz, KInt index) { if (static_cast(index + 1) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } +#if KONAN_NO_UNALIGNED_ACCESS + const uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + return (static_cast(address[0]) << 0) | (static_cast(address[1]) << 8); +#else auto result = *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); #if __BIG_ENDIAN__ return __builtin_bswap16(result); #else return result; -#endif +#endif // __BIG_ENDIAN__ +#endif // KONAN_NO_UNALIGNED_ACCESS } KInt Kotlin_ByteArray_getIntAt(KConstRef thiz, KInt index) { @@ -192,12 +202,18 @@ KInt Kotlin_ByteArray_getIntAt(KConstRef thiz, KInt index) { if (static_cast(index + 3) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } +#if KONAN_NO_UNALIGNED_ACCESS + const uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + return (static_cast(address[0]) << 0) | (static_cast(address[1]) << 8) | + (static_cast(address[2]) << 16) | (static_cast(address[3]) << 24); +#else auto result = *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); #if __BIG_ENDIAN__ return __builtin_bswap32(result); #else return result; -#endif +#endif // __BIG_ENDIAN__ +#endif // KONAN_NO_UNALIGNED_ACCESS } KLong Kotlin_ByteArray_getLongAt(KConstRef thiz, KInt index) { @@ -205,13 +221,20 @@ KLong Kotlin_ByteArray_getLongAt(KConstRef thiz, KInt index) { if (static_cast(index + 7) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } - +#if KONAN_NO_UNALIGNED_ACCESS + const uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + return (static_cast(address[0]) << 0) | (static_cast(address[1]) << 8) | + (static_cast(address[2]) << 16) | (static_cast(address[3]) << 24) | + (static_cast(address[4]) << 32) | (static_cast(address[5]) << 40) | + (static_cast(address[6]) << 48) | (static_cast(address[7]) << 56); +#else auto result = *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); #if __BIG_ENDIAN__ return __builtin_bswap64(result); #else return result; -#endif +#endif // __BIG_ENDIAN__ +#endif // KONAN_NO_UNALIGNED_ACCESS } KFloat Kotlin_ByteArray_getFloatAt(KConstRef thiz, KInt index) { @@ -219,8 +242,21 @@ KFloat Kotlin_ByteArray_getFloatAt(KConstRef thiz, KInt index) { if (static_cast(index + 3) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } +#if KONAN_NO_UNALIGNED_ACCESS + const uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + union { + KFloat f; + uint8_t b[4]; + } u; + u.b[0] = address[0]; + u.b[1] = address[1]; + u.b[2] = address[2]; + u.b[3] = address[3]; + return u.f; +#else auto result = *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); return result; +#endif // KONAN_NO_UNALIGNED_ACCESS } KDouble Kotlin_ByteArray_getDoubleAt(KConstRef thiz, KInt index) { @@ -228,7 +264,24 @@ KDouble Kotlin_ByteArray_getDoubleAt(KConstRef thiz, KInt index) { if (static_cast(index + 7) >= array->count_) { ThrowArrayIndexOutOfBoundsException(); } +#if KONAN_NO_UNALIGNED_ACCESS + const uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + union { + KDouble d; + uint8_t b[8]; + } u; + u.b[0] = address[0]; + u.b[1] = address[1]; + u.b[2] = address[2]; + u.b[3] = address[3]; + u.b[4] = address[4]; + u.b[5] = address[5]; + u.b[6] = address[6]; + u.b[7] = address[7]; + return u.d; +#else return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +#endif // KONAN_NO_UNALIGNED_ACCESS } void Kotlin_ByteArray_setCharAt(KRef thiz, KInt index, KChar value) { @@ -237,10 +290,16 @@ void Kotlin_ByteArray_setCharAt(KRef thiz, KInt index, KChar value) { ThrowArrayIndexOutOfBoundsException(); } mutabilityCheck(thiz); +#if KONAN_NO_UNALIGNED_ACCESS + uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + address[0] = (value >> 0) & 0xff; + address[1] = (value >> 8) & 0xff; +#else #if __BIG_ENDIAN__ value = __builtin_bswap16(value); -#endif +#endif // __BIG_ENDIAN__ *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +#endif // KONAN_NO_UNALIGNED_ACCESS } void Kotlin_ByteArray_setShortAt(KRef thiz, KInt index, KShort value) { @@ -249,10 +308,16 @@ void Kotlin_ByteArray_setShortAt(KRef thiz, KInt index, KShort value) { ThrowArrayIndexOutOfBoundsException(); } mutabilityCheck(thiz); +#if KONAN_NO_UNALIGNED_ACCESS + uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + address[0] = (value >> 0) & 0xff; + address[1] = (value >> 8) & 0xff; +#else #if __BIG_ENDIAN__ value = __builtin_bswap16(value); #endif *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +#endif // KONAN_NO_UNALIGNED_ACCESS } void Kotlin_ByteArray_setIntAt(KRef thiz, KInt index, KInt value) { @@ -261,10 +326,18 @@ void Kotlin_ByteArray_setIntAt(KRef thiz, KInt index, KInt value) { ThrowArrayIndexOutOfBoundsException(); } mutabilityCheck(thiz); +#if KONAN_NO_UNALIGNED_ACCESS + uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + address[0] = (value >> 0) & 0xff; + address[1] = (value >> 8) & 0xff; + address[2] = (value >> 16) & 0xff; + address[3] = (value >> 24) & 0xff; +#else #if __BIG_ENDIAN__ value = __builtin_bswap32(value); -#endif +#endif // __BIG_ENDIAN__ *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +#endif // KONAN_NO_UNALIGNED_ACCESS } void Kotlin_ByteArray_setLongAt(KRef thiz, KInt index, KLong value) { @@ -273,10 +346,22 @@ void Kotlin_ByteArray_setLongAt(KRef thiz, KInt index, KLong value) { ThrowArrayIndexOutOfBoundsException(); } mutabilityCheck(thiz); +#if KONAN_NO_UNALIGNED_ACCESS + uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + address[0] = (value >> 0) & 0xff; + address[1] = (value >> 8) & 0xff; + address[2] = (value >> 16) & 0xff; + address[3] = (value >> 24) & 0xff; + address[4] = (value >> 32) & 0xff; + address[5] = (value >> 40) & 0xff; + address[6] = (value >> 48) & 0xff; + address[7] = (value >> 56) & 0xff; +#else #if __BIG_ENDIAN__ value = __builtin_bswap64(value); -#endif +#endif // __BIG_ENDIAN__ *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +#endif // KONAN_NO_UNALIGNED_ACCESS } void Kotlin_ByteArray_setFloatAt(KRef thiz, KInt index, KFloat value) { @@ -285,7 +370,20 @@ void Kotlin_ByteArray_setFloatAt(KRef thiz, KInt index, KFloat value) { ThrowArrayIndexOutOfBoundsException(); } mutabilityCheck(thiz); +#if KONAN_NO_UNALIGNED_ACCESS + uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + union { + KFloat f; + uint8_t b[4]; + } u; + u.f = value; + address[0] = u.b[0]; + address[1] = u.b[1]; + address[2] = u.b[2]; + address[3] = u.b[3]; +#else *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +#endif // KONAN_NO_UNALIGNED_ACCESS } void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) { @@ -294,7 +392,24 @@ void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) { ThrowArrayIndexOutOfBoundsException(); } mutabilityCheck(thiz); +#if KONAN_NO_UNALIGNED_ACCESS + uint8_t* address = reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); + union { + KDouble d; + uint8_t b[8]; + } u; + u.d = value; + address[0] = u.b[0]; + address[1] = u.b[1]; + address[2] = u.b[2]; + address[3] = u.b[3]; + address[4] = u.b[4]; + address[5] = u.b[5]; + address[6] = u.b[6]; + address[7] = u.b[7]; +#else *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +#endif // KONAN_NO_UNALIGNED_ACCESS } KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) { diff --git a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt index a7633c4890c..f00233f25e0 100644 --- a/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt +++ b/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/ClangArgs.kt @@ -168,7 +168,8 @@ class ClangArgs(private val configurables: Configurables) : Configurables by con // and general ABI requires 4-byte alignment on 64-bit long fields as mentioned in // https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv6FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009021-SW1 // See https://github.com/ktorio/ktor/issues/941 for the context. - "-DKONAN_NO_64BIT_ATOMIC=1") + "-DKONAN_NO_64BIT_ATOMIC=1", + "-DKONAN_NO_UNALIGNED_ACCESS=1") KonanTarget.IOS_ARM64 -> listOf("-DKONAN_OBJC_INTEROP=1",