diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 2cdb823b354..c1490f044a5 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -1257,6 +1257,20 @@ task array3(type: RunKonanTest) { source = "runtime/collections/array3.kt" } +task typed_array0(type: RunKonanTest) { + // MIPS target is big-endian. + disabled = (project.testTarget == 'linux_mips32') + goldValue = "OK\n" + source = "runtime/collections/typed_array0.kt" +} + +task typed_array1(type: RunKonanTest) { + disabled = (project.testTarget == 'wasm32') // No exceptions on WASM. + goldValue = "OK\n" + source = "runtime/collections/typed_array1.kt" +} + + task sort0(type: RunKonanTest) { goldValue = "[a, b, x]\n[-1, 0, 42, 239, 100500]\n" source = "runtime/collections/sort0.kt" diff --git a/backend.native/tests/runtime/collections/typed_array0.kt b/backend.native/tests/runtime/collections/typed_array0.kt new file mode 100644 index 00000000000..761392c2270 --- /dev/null +++ b/backend.native/tests/runtime/collections/typed_array0.kt @@ -0,0 +1,14 @@ +package runtime.collections.typed_array0 + +import kotlin.test.* + +@Test fun runTest() { + // Those tests assume little endian bit ordering. + val array = ByteArray(42) + array.setLongAt(5, 0x1234_5678_9abc_def0) + + expect(0xdef0.toInt()) { array.charAt(5).toInt() } + expect(0x9abc.toShort()) { array.shortAt(7) } + expect(0x1234_5678) { array.intAt(9) } + 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 new file mode 100644 index 00000000000..10279caec0f --- /dev/null +++ b/backend.native/tests/runtime/collections/typed_array1.kt @@ -0,0 +1,74 @@ +package runtime.collections.typed_array1 + +import kotlin.test.* + +@Test fun runTest() { + val array = ByteArray(17) + val results = mutableSetOf() + var counter = 0 + try { + results += array.shortAt(16) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + results += array.charAt(22) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + results += array.intAt(15) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + results += array.longAt(14) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + results += array.floatAt(14) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + results += array.doubleAt(13) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + + try { + array.setShortAt(16, 2.toShort()) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + array.setCharAt(22, 'a') + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + array.setIntAt(15, 1234) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + array.setLongAt(14, 1.toLong()) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + array.setFloatAt(14, 1.0f) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + try { + array.setDoubleAt(13, 3.0) + } catch (e: ArrayIndexOutOfBoundsException) { + counter++ + } + + expect(12) { counter } + expect(0) { results.size } + 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 f344e9b7cfd..d9923a9ccb6 100644 --- a/runtime/src/main/cpp/Arrays.cpp +++ b/runtime/src/main/cpp/Arrays.cpp @@ -131,6 +131,102 @@ KInt Kotlin_ByteArray_getArrayLength(KConstRef thiz) { return array->count_; } +KChar Kotlin_ByteArray_getCharAt(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index + 1) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +} + +KShort Kotlin_ByteArray_getShortAt(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index + 1) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +} + +KInt Kotlin_ByteArray_getIntAt(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index + 3) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +} + +KLong Kotlin_ByteArray_getLongAt(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index + 7) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +} + +KFloat Kotlin_ByteArray_getFloatAt(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index + 3) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +} + +KDouble Kotlin_ByteArray_getDoubleAt(KConstRef thiz, KInt index) { + const ArrayHeader* array = thiz->array(); + if (static_cast(index + 7) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)); +} + +void Kotlin_ByteArray_setCharAt(KRef thiz, KInt index, KChar value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index + 1) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +} + +void Kotlin_ByteArray_setShortAt(KRef thiz, KInt index, KShort value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index + 1) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +} + +void Kotlin_ByteArray_setIntAt(KRef thiz, KInt index, KInt value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index + 3) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +} + +void Kotlin_ByteArray_setLongAt(KRef thiz, KInt index, KLong value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index + 7) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +} + +void Kotlin_ByteArray_setFloatAt(KRef thiz, KInt index, KFloat value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index + 3) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +} + +void Kotlin_ByteArray_setDoubleAt(KRef thiz, KInt index, KDouble value) { + ArrayHeader* array = thiz->array(); + if (static_cast(index + 7) >= array->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *reinterpret_cast(ByteArrayAddressOfElementAt(array, index)) = value; +} + KChar Kotlin_CharArray_get(KConstRef thiz, KInt index) { const ArrayHeader* array = thiz->array(); if (static_cast(index) >= array->count_) { diff --git a/runtime/src/main/kotlin/konan/TypedArrays.kt b/runtime/src/main/kotlin/konan/TypedArrays.kt new file mode 100644 index 00000000000..5b3f1bc51f4 --- /dev/null +++ b/runtime/src/main/kotlin/konan/TypedArrays.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package konan + +import konan.SymbolName + +@SymbolName("Kotlin_ByteArray_getCharAt") +external fun ByteArray.charAt(index: Int): Char + +@SymbolName("Kotlin_ByteArray_getShortAt") +external fun ByteArray.shortAt(index: Int): Short + +@SymbolName("Kotlin_ByteArray_getIntAt") +external fun ByteArray.intAt(index: Int): Int + +@SymbolName("Kotlin_ByteArray_getLongAt") +external fun ByteArray.longAt(index: Int): Long + +@SymbolName("Kotlin_ByteArray_getFloatAt") +external fun ByteArray.floatAt(index: Int): Float + +@SymbolName("Kotlin_ByteArray_getDoubleAt") +external fun ByteArray.doubleAt(index: Int): Double + +@SymbolName("Kotlin_ByteArray_setCharAt") +external fun ByteArray.setCharAt(index: Int, value: Char) + +@SymbolName("Kotlin_ByteArray_setShortAt") +external fun ByteArray.setShortAt(index: Int, value: Short) + +@SymbolName("Kotlin_ByteArray_setIntAt") +external fun ByteArray.setIntAt(index: Int, value: Int) + +@SymbolName("Kotlin_ByteArray_setLongAt") +external fun ByteArray.setLongAt(index: Int, value: Long) + +@SymbolName("Kotlin_ByteArray_setFloatAt") +external fun ByteArray.setFloatAt(index: Int, value: Float) + +@SymbolName("Kotlin_ByteArray_setDoubleAt") +external fun ByteArray.setDoubleAt(index: Int, value: Double)