1/*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/base/atomic_helper.h"
17#include "ecmascript/global_env.h"
18#include "ecmascript/js_typed_array.h"
19#include "ecmascript/tests/test_helper.h"
20
21using namespace panda::ecmascript;
22using namespace panda::ecmascript::base;
23
24namespace panda::test {
25class AtomicHelperTest : public BaseTestWithScope<false> {
26};
27
28HWTEST_F_L0(AtomicHelperTest, ValidateIntegerTypedArray)
29{
30    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
31    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
32
33    bool waitable = false;
34    uint32_t bufferSize = 10;
35    JSHandle<JSTaggedValue> func = env->GetInt8ArrayFunction();
36    JSHandle<JSTypedArray> array =
37        JSHandle<JSTypedArray>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(func), func));
38    JSHandle<JSArrayBuffer> buffer = factory->NewJSArrayBuffer(bufferSize);
39    JSHandle<JSTaggedValue> bufferVal = JSHandle<JSTaggedValue>::Cast(buffer);
40    array->SetViewedArrayBufferOrByteArray(thread, bufferVal);
41    JSHandle<JSTaggedValue> arrayVal = JSHandle<JSTaggedValue>::Cast(array);
42    JSHandle<JSTaggedValue> resultBuffer(thread, AtomicHelper::ValidateIntegerTypedArray(thread, arrayVal, waitable));
43    EXPECT_EQ(resultBuffer.GetTaggedValue(), buffer.GetTaggedValue());
44}
45
46HWTEST_F_L0(AtomicHelperTest, ValidateAtomicAccess)
47{
48    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
49    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
50    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
51
52    uint32_t bufferSize = 256;
53    uint32_t byteOffset = 7;
54    uint32_t arrayLength = 3;
55    JSHandle<JSTaggedValue> func = env->GetInt8ArrayFunction();
56    JSHandle<JSTypedArray> array =
57        JSHandle<JSTypedArray>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(func), func));
58    JSHandle<JSArrayBuffer> buffer = factory->NewJSArrayBuffer(bufferSize);
59    JSHandle<JSTaggedValue> bufferVal = JSHandle<JSTaggedValue>::Cast(buffer);
60    array->SetViewedArrayBufferOrByteArray(thread, bufferVal);
61    array->SetTypedArrayName(thread, globalConst->GetHandledInt8ArrayString()); // test int8 array
62    array->SetByteOffset(byteOffset);
63    array->SetArrayLength(arrayLength);
64    JSHandle<JSTaggedValue> arrayVal = JSHandle<JSTaggedValue>::Cast(array);
65    uint32_t index0 =
66        AtomicHelper::ValidateAtomicAccess(thread, arrayVal, JSHandle<JSTaggedValue>(thread, JSTaggedValue(0)));
67    uint32_t index1 =
68        AtomicHelper::ValidateAtomicAccess(thread, arrayVal, JSHandle<JSTaggedValue>(thread, JSTaggedValue(1)));
69    uint32_t index2 =
70        AtomicHelper::ValidateAtomicAccess(thread, arrayVal, JSHandle<JSTaggedValue>(thread, JSTaggedValue(2)));
71    EXPECT_EQ(index0, 0 * sizeof(int8_t) + byteOffset);
72    EXPECT_EQ(index1, 1 * sizeof(int8_t) + byteOffset);
73    EXPECT_EQ(index2, 2 * sizeof(int8_t) + byteOffset);
74}
75
76HWTEST_F_L0(AtomicHelperTest, Atomic_Store_Load)
77{
78    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
79    const GlobalEnvConstants *globalConst = thread->GlobalConstants();
80    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
81
82    uint32_t bufferSize = 256;
83    uint32_t byteOffset = 7;
84    uint32_t arrayLength = 3;
85    JSHandle<JSTaggedValue> func = env->GetUint32ArrayFunction();
86    JSHandle<JSTypedArray> array =
87        JSHandle<JSTypedArray>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(func), func));
88    JSHandle<JSArrayBuffer> buffer = factory->NewJSArrayBuffer(bufferSize);
89    JSHandle<JSTaggedValue> bufferVal = JSHandle<JSTaggedValue>::Cast(buffer);
90    array->SetViewedArrayBufferOrByteArray(thread, bufferVal);
91    array->SetTypedArrayName(thread, globalConst->GetHandledUint32ArrayString()); // test uint32_t array
92    array->SetByteOffset(byteOffset);
93    array->SetArrayLength(arrayLength);
94    JSHandle<JSTaggedValue> arrayVal = JSHandle<JSTaggedValue>::Cast(array);
95    JSHandle<JSTaggedValue> index0(thread, JSTaggedValue(0));
96    JSHandle<JSTaggedValue> index1(thread, JSTaggedValue(1));
97    JSHandle<JSTaggedValue> index2(thread, JSTaggedValue(2));
98    JSHandle<JSTaggedValue> value0(thread, JSTaggedValue(-1)); // to uint32_t : 4294967295
99    JSHandle<JSTaggedValue> value1(thread, JSTaggedValue(1));
100#ifdef PANDA_TARGET_MACOS
101    JSHandle<JSTaggedValue> value2(thread, static_cast<JSTaggedValue>(static_cast<uint32_t>(4294967295 + 1))); // to uint32_t : 0
102#else
103    JSHandle<JSTaggedValue> value2(thread, JSTaggedValue(4294967295 + 1));
104#endif
105    JSHandle<JSTaggedValue> bufferTag0(thread, AtomicHelper::AtomicStore(thread, arrayVal, index0, value0));
106    JSHandle<JSTaggedValue> bufferTag1(thread, AtomicHelper::AtomicStore(thread, arrayVal, index1, value1));
107    JSHandle<JSTaggedValue> bufferTag2(thread, AtomicHelper::AtomicStore(thread, arrayVal, index2, value2));
108    EXPECT_EQ(value0.GetTaggedValue().GetNumber(), -1);
109    EXPECT_EQ(value1.GetTaggedValue().GetNumber(), 1);
110    EXPECT_EQ(value2.GetTaggedValue().GetNumber(), 4294967296);
111
112    JSHandle<JSTaggedValue> result0(thread, AtomicHelper::AtomicLoad(thread, arrayVal, index0));
113    JSHandle<JSTaggedValue> result1(thread, AtomicHelper::AtomicLoad(thread, arrayVal, index1));
114    JSHandle<JSTaggedValue> result2(thread, AtomicHelper::AtomicLoad(thread, arrayVal, index2));
115    EXPECT_EQ(result0.GetTaggedValue().GetNumber(), 4294967295); // 4294967295 : -1 to uint32_t
116    EXPECT_EQ(result1.GetTaggedValue().GetNumber(), 1);
117    EXPECT_EQ(result2.GetTaggedValue().GetNumber(), 0); // 0 : 4294967296 to uint32_t
118}
119}  // namespace panda::test
120