[K/N] Introduce intrinsics that atomically update array elements

Supported atomic update of elements for IntArray, LongArray and Array<T>
See KT-58360

Merge-request: KT-MR-11020
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
mvicsokolova
2023-07-12 14:32:36 +00:00
committed by Space Team
parent 20c53fc15d
commit d9fa9c1b3b
13 changed files with 598 additions and 54 deletions
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <cinttypes>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
@@ -114,4 +115,22 @@ void Kotlin_CPointer_CopyMemory(KNativePtr to, KNativePtr from, KInt count) {
memcpy(to, from, count);
}
RUNTIME_NOTHROW RUNTIME_PURE KRef* Kotlin_arrayGetElementAddress(KRef array, KInt index) {
ArrayHeader* arr = array->array();
RuntimeAssert(index >= 0 && static_cast<uint32_t>(index) < arr->count_, "Index %" PRId32 " must be in [0, %" PRIu32 ")", index, arr->count_);
return ArrayAddressOfElementAt(arr, index);
}
RUNTIME_NOTHROW RUNTIME_PURE KInt* Kotlin_intArrayGetElementAddress(KRef array, KInt index) {
ArrayHeader* arr = array->array();
RuntimeAssert(index >= 0 && static_cast<uint32_t>(index) < arr->count_, "Index %" PRId32 " must be in [0, %" PRIu32 ")", index, arr->count_);
return IntArrayAddressOfElementAt(arr, index);
}
RUNTIME_NOTHROW RUNTIME_PURE KLong* Kotlin_longArrayGetElementAddress(KRef array, KInt index) {
ArrayHeader* arr = array->array();
RuntimeAssert(index >= 0 && static_cast<uint32_t>(index) < arr->count_, "Index %" PRId32 " must be in [0, %" PRIu32 ")", index, arr->count_);
return LongArrayAddressOfElementAt(arr, index);
}
} // extern "C"
@@ -62,6 +62,14 @@ inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index
return AddressOfElementAt<KInt>(obj, index);
}
inline KLong* LongArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KLong>(obj, index);
}
inline const KLong* LongArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return AddressOfElementAt<KLong>(obj, index);
}
// Consider aligning of base to sizeof(T).
template <typename T>
inline T* PrimitiveArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
@@ -90,6 +98,9 @@ void Kotlin_io_Console_println0();
void Kotlin_io_Console_println0ToStdErr();
void Kotlin_NativePtrArray_set(KRef thiz, KInt index, KNativePtr value);
KNativePtr Kotlin_NativePtrArray_get(KConstRef thiz, KInt index);
RUNTIME_NOTHROW RUNTIME_PURE KRef* Kotlin_arrayGetElementAddress(KRef array, KInt index);
RUNTIME_NOTHROW RUNTIME_PURE KInt* Kotlin_intArrayGetElementAddress(KRef array, KInt index);
RUNTIME_NOTHROW RUNTIME_PURE KLong* Kotlin_longArrayGetElementAddress(KRef array, KInt index);
#ifdef __cplusplus
}
@@ -0,0 +1,199 @@
/*
* Copyright 2010-2023 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.
*/
package kotlin.concurrent
import kotlin.native.internal.*
import kotlin.reflect.*
import kotlin.concurrent.*
import kotlin.native.concurrent.*
/**
* Atomically gets the value of the [IntArray][this] element at the given [index].
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.ATOMIC_GET_ARRAY_ELEMENT)
internal external fun IntArray.atomicGet(index: Int): Int
/**
* Atomically sets the value of the [IntArray][this] element at the given [index] to the [new value][newValue].
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.ATOMIC_SET_ARRAY_ELEMENT)
internal external fun IntArray.atomicSet(index: Int, newValue: Int)
/**
* Atomically sets the value of the [IntArray][this] element at the given [index] to the [new value][newValue]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.GET_AND_SET_ARRAY_ELEMENT)
internal external fun IntArray.getAndSet(index: Int, newValue: Int): Int
/**
* Atomically adds the [given value][delta] to the [IntArray][this] element at the given [index]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.GET_AND_ADD_ARRAY_ELEMENT)
internal external fun IntArray.getAndAdd(index: Int, delta: Int): Int
/**
* Atomically sets the value of the [IntArray][this] element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue] and returns the old value of the element in any case.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.COMPARE_AND_EXCHANGE_ARRAY_ELEMENT)
internal external fun IntArray.compareAndExchange(index: Int, expectedValue: Int, newValue: Int): Int
/**
* Atomically sets the value of the [IntArray][this] element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue].
* Returns true if the operation was successful and false only if the current value of the element was not equal to the expected value.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.COMPARE_AND_SET_ARRAY_ELEMENT)
internal external fun IntArray.compareAndSet(index: Int, expectedValue: Int, newValue: Int): Boolean
/**
* Atomically gets the value of the [LongArray][this] element at the given [index].
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.ATOMIC_GET_ARRAY_ELEMENT)
internal external fun LongArray.atomicGet(index: Int): Long
/**
* Atomically sets the value of the [LongArray][this] element at the given [index] to the [new value][newValue].
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.ATOMIC_SET_ARRAY_ELEMENT)
internal external fun LongArray.atomicSet(index: Int, newValue: Long)
/**
* Atomically sets the value of the [LongArray][this] element at the given [index] to the [new value][newValue]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.GET_AND_SET_ARRAY_ELEMENT)
internal external fun LongArray.getAndSet(index: Int, newValue: Long): Long
/**
* Atomically adds the [given value][delta] to the [LongArray][this] element at the given [index]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.GET_AND_ADD_ARRAY_ELEMENT)
internal external fun LongArray.getAndAdd(index: Int, delta: Long): Long
/**
* Atomically sets the value of the [LongArray][this] element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue] and returns the old value of the element in any case.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.COMPARE_AND_EXCHANGE_ARRAY_ELEMENT)
internal external fun LongArray.compareAndExchange(index: Int, expectedValue: Long, newValue: Long): Long
/**
* Atomically sets the value of the [LongArray][this] element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue].
* Returns true if the operation was successful and false only if the current value of the element was not equal to the expected value.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.COMPARE_AND_SET_ARRAY_ELEMENT)
internal external fun LongArray.compareAndSet(index: Int, expectedValue: Long, newValue: Long): Boolean
/**
* Atomically gets the value of the [Array<T>][this] element at the given [index].
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.ATOMIC_GET_ARRAY_ELEMENT)
internal external fun <T> Array<T>.atomicGet(index: Int): T
/**
* Atomically sets the value of the [Array<T>][this] element at the given [index] to the [new value][newValue].
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.ATOMIC_SET_ARRAY_ELEMENT)
internal external fun <T> Array<T>.atomicSet(index: Int, newValue: T)
/**
* Atomically sets the value of the [Array<T>][this] element at the given [index] to the [new value][newValue]
* and returns the old value of the element.
*
* Provides sequential consistent ordering guarantees.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.GET_AND_SET_ARRAY_ELEMENT)
internal external fun <T> Array<T>.getAndSet(index: Int, value: T): T
/**
* Atomically sets the value of the [Array<T>][this] element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue] and returns the old value of the element in any case.
*
* Comparison of values is done by reference.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.COMPARE_AND_EXCHANGE_ARRAY_ELEMENT)
internal external fun <T> Array<T>.compareAndExchange(index: Int, expectedValue: T, newValue: T): T
/**
* Atomically sets the value of the [Array<T>][this] element at the given [index] to the [new value][newValue]
* if the current value equals the [expected value][expectedValue].
* Returns true if the operation was successful and false only if the current value of the element was not equal to the expected value.
*
* Comparison of values is done by reference.
*
* Provides sequential consistent ordering guarantees and never fails spuriously.
*
* NOTE: Ensure that the provided [index] does not exceed the size of the [array][this]. Exceeding the array size may result in undefined behavior.
*/
@TypedIntrinsic(IntrinsicType.COMPARE_AND_SET_ARRAY_ELEMENT)
internal external fun <T> Array<T>.compareAndSet(index: Int, expectedValue: T, newValue: T): Boolean
@@ -91,5 +91,12 @@ internal class IntrinsicType {
const val COMPARE_AND_EXCHANGE = "COMPARE_AND_EXCHANGE"
const val GET_AND_SET = "GET_AND_SET"
const val GET_AND_ADD = "GET_AND_ADD"
const val ATOMIC_GET_ARRAY_ELEMENT = "ATOMIC_GET_ARRAY_ELEMENT"
const val ATOMIC_SET_ARRAY_ELEMENT = "ATOMIC_SET_ARRAY_ELEMENT"
const val COMPARE_AND_EXCHANGE_ARRAY_ELEMENT = "COMPARE_AND_EXCHANGE_ARRAY_ELEMENT"
const val GET_AND_SET_ARRAY_ELEMENT = "GET_AND_SET_ARRAY_ELEMENT"
const val GET_AND_ADD_ARRAY_ELEMENT = "GET_AND_ADD_ARRAY_ELEMENT"
const val COMPARE_AND_SET_ARRAY_ELEMENT = "COMPARE_AND_SET_ARRAY_ELEMENT"
}
}
}