diff --git a/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp b/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp index f02eba73067cbb552e21d263926367319453cada..68cd4938463112cc1a22c48db69cd3bdd6acb7f9 100644 --- a/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp +++ b/static_core/plugins/ets/runtime/intrinsics/escompat_Array.cpp @@ -537,10 +537,11 @@ static auto GetSwap([[maybe_unused]] void *arrAddr, [[maybe_unused]] mem::GCBarr static constexpr size_t SWAPPED_BETWEEN_SAFEPOINT_THRESHOLD = 50000UL; template -static void RefReverse(void *arrAddr, int32_t length, mem::GCBarrierSet *barrierSet) +static void RefReverse(ManagedThread *thread, EtsHandle &arrayHandle, int32_t length) { - auto *arr = static_cast(arrAddr); - auto swap = GetSwap(arrAddr, barrierSet); + auto *arr = arrayHandle->GetData()->GetData(); + auto *barrierSet = thread->GetBarrierSet(); + auto swap = GetSwap(arr, barrierSet); bool usePreBarrier = barrierSet->IsPreBarrierEnabled(); auto swapWithBarriers = [&swap, &usePreBarrier, barrierSet](T *aPtr, T *bPtr) { @@ -550,14 +551,14 @@ static void RefReverse(void *arrAddr, int32_t length, mem::GCBarrierSet *barrier } swap(aPtr, bPtr); }; - auto putSafepoint = [&usePreBarrier, barrierSet, arr](size_t dstStart, size_t dstEndMirror, size_t bLength) { + auto putSafepoint = [&usePreBarrier, barrierSet, &arr, thread](size_t dstStart, size_t dstEndMirror, size_t count) { if (barrierSet->GetPostType() != ark::mem::BarrierType::POST_WRB_NONE) { constexpr uint32_t OFFSET = ark::coretypes::Array::GetDataOffset(); - const uint32_t size = bLength * sizeof(ObjectPointerType); - barrierSet->PostBarrier(arr, OFFSET + dstStart * sizeof(ObjectPointerType), size); - barrierSet->PostBarrier(arr, OFFSET + dstEndMirror * sizeof(ObjectPointerType) - size, size); + const uint32_t size = count * sizeof(T); + barrierSet->PostBarrier(arr, OFFSET + dstStart * sizeof(T), size); + barrierSet->PostBarrier(arr, OFFSET + dstEndMirror * sizeof(T) - size, size); } - ark::interpreter::RuntimeInterface::Safepoint(); + ark::interpreter::RuntimeInterface::Safepoint(thread); usePreBarrier = barrierSet->IsPreBarrierEnabled(); }; auto halfLength = static_cast(length) / 2; @@ -568,6 +569,9 @@ static void RefReverse(void *arrAddr, int32_t length, mem::GCBarrierSet *barrier swapWithBarriers(&arr[j], &arr[length - 1 - j]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } putSafepoint(groupIdx, length - 1 - groupIdx, SWAPPED_BETWEEN_SAFEPOINT_THRESHOLD); + // If GC suspend worker during RefReverse execution then it may move array pointed by arr to a different memory + // location - should re-read a new array address + arr = arrayHandle->GetData()->GetData(); } // Reverse possible remaining part with length less than SWAPPED_BETWEEN_SAFEPOINT_THRESHOLD size_t finalIdx = (halfLength / SWAPPED_BETWEEN_SAFEPOINT_THRESHOLD) * SWAPPED_BETWEEN_SAFEPOINT_THRESHOLD; @@ -590,10 +594,7 @@ extern "C" EtsEscompatArray *EtsEscompatArrayReverse(EtsEscompatArray *array) [[maybe_unused]] EtsHandleScope scope(coro); EtsHandle arrayHandle(coro, array); - auto arrAddr = ToVoidPtr(ToUintPtr(arrayHandle->GetData()->GetData())); - auto *barrierSet = Thread::GetCurrent()->GetBarrierSet(); - - RefReverse(arrAddr, actualLength, barrierSet); + RefReverse(coro, arrayHandle, actualLength); return arrayHandle.GetPtr(); } diff --git a/static_core/plugins/ets/tests/ets-common-tests/intrinsics/array_reverse.ets b/static_core/plugins/ets/tests/ets-common-tests/intrinsics/array_reverse.ets index e9440348c6c3cd79a0664fc10841e04b0c3fd1c5..d29471b0d9ef5a97370d714567c7a365f6588a4b 100644 --- a/static_core/plugins/ets/tests/ets-common-tests/intrinsics/array_reverse.ets +++ b/static_core/plugins/ets/tests/ets-common-tests/intrinsics/array_reverse.ets @@ -59,6 +59,21 @@ function test_union_array(): void { check_array_reverse(data) } +function test_long_len_array_reverse() { + let inp = new Array(); + let orig_exp = new Array(); + let rev_exp = new Array(); + // SWAPPED_BETWEEN_SAFEPOINT_THRESHOLD = 50000UL; + let len = 100001; + for (let i: number = 0; i < len; i++) { + inp.push(i); + orig_exp.push(i); + rev_exp.push(len - 1 - i); + } + check_array(inp.reverse(), orig_exp); + check_array(inp.reverse(), rev_exp); +} + function check_array_reverse(data: Array): void { let data_rev = Array.from(data).reverse() check_array(data, data_rev) @@ -84,5 +99,6 @@ function main(): int { testSuite.addTest("Arrays of char: reverse test", test_char_array); testSuite.addTest("Arrays of string: reverse test", test_string_array); testSuite.addTest("Arrays of union: reverse test", test_union_array); + testSuite.addTest("Long len arrays: reverse test with safepoints", test_long_len_array_reverse); return testSuite.run() }