Fix typed array access for platforms not allowing unaligned access.
This commit is contained in:
committed by
Nikolay Igotti
parent
a7723ee0bc
commit
5c994265cd
@@ -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")
|
||||
}
|
||||
@@ -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<Any>()
|
||||
var counter = 0
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
results += array.getShortAt(16)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
results += array.getCharAt(22)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
results += array.getIntAt(15)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
results += array.getLongAt(14)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
results += array.getFloatAt(14)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
results += array.getDoubleAt(13)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
array.setShortAt(16, 2.toShort())
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
array.setCharAt(22, 'a')
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
array.setIntAt(15, 1234)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
array.setLongAt(14, 1.toLong())
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
array.setFloatAt(14, 1.0f)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
try {
|
||||
assertFailsWith<ArrayIndexOutOfBoundsException> {
|
||||
array.setDoubleAt(13, 3.0)
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
counter++
|
||||
}
|
||||
|
||||
expect(12) { counter }
|
||||
expect(0) { results.size }
|
||||
|
||||
array.freeze()
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
array.setShortAt(0, 2.toShort())
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
array.setCharAt(0, 'a')
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
array.setIntAt(0, 2)
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
array.setLongAt(0, 2)
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
array.setFloatAt(0, 1.0f)
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
array.setDoubleAt(0, 1.0)
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
@@ -166,12 +166,17 @@ KChar Kotlin_ByteArray_getCharAt(KConstRef thiz, KInt index) {
|
||||
if (static_cast<uint32_t>(index + 1) >= array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
#if KONAN_NO_UNALIGNED_ACCESS
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
|
||||
return (static_cast<KChar>(address[0]) << 0) | (static_cast<KChar>(address[1]) << 8);
|
||||
#else
|
||||
auto result = *reinterpret_cast<const KChar*>(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<uint32_t>(index + 1) >= array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
#if KONAN_NO_UNALIGNED_ACCESS
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
|
||||
return (static_cast<KShort>(address[0]) << 0) | (static_cast<KShort>(address[1]) << 8);
|
||||
#else
|
||||
auto result = *reinterpret_cast<const KShort*>(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<uint32_t>(index + 3) >= array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
#if KONAN_NO_UNALIGNED_ACCESS
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
|
||||
return (static_cast<KInt>(address[0]) << 0) | (static_cast<KInt>(address[1]) << 8) |
|
||||
(static_cast<KInt>(address[2]) << 16) | (static_cast<KInt>(address[3]) << 24);
|
||||
#else
|
||||
auto result = *reinterpret_cast<const KInt*>(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<uint32_t>(index + 7) >= array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
#if KONAN_NO_UNALIGNED_ACCESS
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(ByteArrayAddressOfElementAt(array, index));
|
||||
return (static_cast<KLong>(address[0]) << 0) | (static_cast<KLong>(address[1]) << 8) |
|
||||
(static_cast<KLong>(address[2]) << 16) | (static_cast<KLong>(address[3]) << 24) |
|
||||
(static_cast<KLong>(address[4]) << 32) | (static_cast<KLong>(address[5]) << 40) |
|
||||
(static_cast<KLong>(address[6]) << 48) | (static_cast<KLong>(address[7]) << 56);
|
||||
#else
|
||||
auto result = *reinterpret_cast<const KLong*>(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<uint32_t>(index + 3) >= array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
#if KONAN_NO_UNALIGNED_ACCESS
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(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<const KFloat*>(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<uint32_t>(index + 7) >= array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
#if KONAN_NO_UNALIGNED_ACCESS
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(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<const KDouble*>(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<uint8_t*>(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<KChar*>(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<uint8_t*>(ByteArrayAddressOfElementAt(array, index));
|
||||
address[0] = (value >> 0) & 0xff;
|
||||
address[1] = (value >> 8) & 0xff;
|
||||
#else
|
||||
#if __BIG_ENDIAN__
|
||||
value = __builtin_bswap16(value);
|
||||
#endif
|
||||
*reinterpret_cast<KShort*>(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<uint8_t*>(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<KInt*>(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<uint8_t*>(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<KLong*>(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<uint8_t*>(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<KFloat*>(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<uint8_t*>(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<KDouble*>(ByteArrayAddressOfElementAt(array, index)) = value;
|
||||
#endif // KONAN_NO_UNALIGNED_ACCESS
|
||||
}
|
||||
|
||||
KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user