1 /*
2 * Copyright (c) 2025 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 <vector>
17
18 #include "common_components/heap/barrier/barrier.h"
19 #include "common_components/heap/collector/collector.h"
20 #include "common_interfaces/objects/ref_field.h"
21 #include "common_interfaces/objects/base_object.h"
22
23 #include "common_components/tests/test_helper.h"
24
25 using namespace common;
26
27
28 class DummyObject : public BaseObject {
29 public:
GetTypeInfo() const30 const common::TypeInfo* GetTypeInfo() const
31 {
32 return nullptr;
33 }
GetSize() const34 size_t GetSize() const
35 {
36 return sizeof(DummyObject);
37 }
38 };
39
40
41 class MockCollector : public Collector {
42 public:
Init(const RuntimeParam & param)43 void Init(const RuntimeParam& param) override {}
RunGarbageCollection(uint64_t,GCReason,GCType)44 void RunGarbageCollection(uint64_t, GCReason, GCType) override {}
ForwardObject(BaseObject *)45 BaseObject* ForwardObject(BaseObject*) override
46 {
47 return nullptr;
48 }
ShouldIgnoreRequest(GCRequest &)49 bool ShouldIgnoreRequest(GCRequest&) override
50 {
51 return false;
52 }
IsFromObject(BaseObject *) const53 bool IsFromObject(BaseObject*) const override
54 {
55 return false;
56 }
IsUnmovableFromObject(BaseObject *) const57 bool IsUnmovableFromObject(BaseObject*) const override
58 {
59 return false;
60 }
FindToVersion(BaseObject *) const61 BaseObject* FindToVersion(BaseObject*) const override
62 {
63 return nullptr;
64 }
65
TryUpdateRefField(BaseObject * Obj,RefField<> & field,BaseObject * & toVersion) const66 bool TryUpdateRefField(BaseObject* Obj, RefField<>& field, BaseObject*& toVersion) const override
67 {
68 toVersion = reinterpret_cast<BaseObject*>(field.GetFieldValue());
69 return true;
70 }
71
TryForwardRefField(BaseObject *,RefField<> &,BaseObject * &) const72 bool TryForwardRefField(BaseObject*, RefField<>&, BaseObject*&) const override
73 {
74 return false;
75 }
TryUntagRefField(BaseObject *,RefField<> &,BaseObject * &) const76 bool TryUntagRefField(BaseObject*, RefField<>&, BaseObject*&) const override
77 {
78 return false;
79 }
GetAndTryTagRefField(BaseObject *) const80 RefField<> GetAndTryTagRefField(BaseObject*) const override
81 {
82 return RefField<>(nullptr);
83 }
IsOldPointer(RefField<> &) const84 bool IsOldPointer(RefField<>&) const override
85 {
86 return false;
87 }
IsCurrentPointer(RefField<> &) const88 bool IsCurrentPointer(RefField<>&) const override
89 {
90 return false;
91 }
AddRawPointerObject(BaseObject *)92 void AddRawPointerObject(BaseObject*) override {}
RemoveRawPointerObject(BaseObject *)93 void RemoveRawPointerObject(BaseObject*) override {}
94 };
95
96
97 class BarrierTest : public common::test::BaseTestWithScope {
98 protected:
99 MockCollector collector;
100 Barrier barrier{collector};
101 std::unique_ptr<DummyObject> dummyObj;
102
SetUp()103 void SetUp() override
104 {
105 dummyObj = std::make_unique<DummyObject>();
106 }
107 };
108
HWTEST_F_L0(BarrierTest,ReadRefField_ReturnsExpectedValue)109 HWTEST_F_L0(BarrierTest, ReadRefField_ReturnsExpectedValue) {
110 uint64_t value = reinterpret_cast<uint64_t>(dummyObj.get());
111 RefField<false> field(value);
112
113 BaseObject* result = barrier.ReadRefField(nullptr, field);
114 EXPECT_EQ(result, dummyObj.get());
115 }
116
HWTEST_F_L0(BarrierTest,WriteRefField_SetsTargetObject)117 HWTEST_F_L0(BarrierTest, WriteRefField_SetsTargetObject) {
118 uint64_t initValue = 0;
119 RefField<false> field(initValue);
120 BaseObject* newRef = dummyObj.get();
121
122 barrier.WriteRefField(nullptr, field, newRef);
123 EXPECT_EQ(field.GetTargetObject(), newRef);
124 }
125
HWTEST_F_L0(BarrierTest,WriteStaticRef_SetsTargetObject)126 HWTEST_F_L0(BarrierTest, WriteStaticRef_SetsTargetObject) {
127 uint64_t initValue = 0;
128 RefField<false> field(initValue);
129 BaseObject* newRef = dummyObj.get();
130
131 barrier.WriteStaticRef(field, newRef);
132 EXPECT_EQ(field.GetTargetObject(), newRef);
133 }
134
HWTEST_F_L0(BarrierTest,AtomicWriteRefField_UpdatesWithMemoryOrder)135 HWTEST_F_L0(BarrierTest, AtomicWriteRefField_UpdatesWithMemoryOrder) {
136 uint64_t initValue = 0;
137 RefField<true> field(initValue);
138 BaseObject* newRef = dummyObj.get();
139
140 barrier.AtomicWriteRefField(nullptr, field, newRef, std::memory_order_relaxed);
141 EXPECT_EQ(field.GetTargetObject(std::memory_order_relaxed), newRef);
142 }
143
HWTEST_F_L0(BarrierTest,CompareAndSwapRefField_WorksWithSuccessAndFailure)144 HWTEST_F_L0(BarrierTest, CompareAndSwapRefField_WorksWithSuccessAndFailure) {
145 uint64_t initValue = 0;
146 RefField<true> field(initValue);
147 BaseObject* oldRef = nullptr;
148 BaseObject* newRef = dummyObj.get();
149
150 bool result = barrier.CompareAndSwapRefField(nullptr, field, oldRef, newRef,
151 std::memory_order_seq_cst, std::memory_order_relaxed);
152 EXPECT_TRUE(result);
153 EXPECT_EQ(field.GetTargetObject(std::memory_order_relaxed), newRef);
154 }
155
HWTEST_F_L0(BarrierTest,WriteStruct_HandlesDifferentLengths)156 HWTEST_F_L0(BarrierTest, WriteStruct_HandlesDifferentLengths) {
157 size_t srcBufferSize = 512;
158 size_t dstBufferSize = 1024;
159 char* srcBuffer = new char[srcBufferSize];
160 char* dstBuffer = new char[dstBufferSize];
161
162 for (size_t i = 0; i < srcBufferSize; ++i) {
163 srcBuffer[i] = static_cast<char>(i % 256);
164 }
165
166 barrier.WriteStruct(nullptr, reinterpret_cast<HeapAddress>(dstBuffer), dstBufferSize,
167 reinterpret_cast<HeapAddress>(srcBuffer), srcBufferSize);
168
169 EXPECT_EQ(memcmp(dstBuffer, srcBuffer, srcBufferSize), 0);
170
171 for (size_t i = srcBufferSize; i < dstBufferSize; ++i) {
172 EXPECT_EQ(dstBuffer[i], 0);
173 }
174
175 delete[] srcBuffer;
176 delete[] dstBuffer;
177 }
178
HWTEST_F_L0(BarrierTest,ReadStaticRef_ReturnsExpectedValue)179 HWTEST_F_L0(BarrierTest, ReadStaticRef_ReturnsExpectedValue) {
180 uint64_t value = reinterpret_cast<uint64_t>(dummyObj.get());
181 RefField<false> field(value);
182
183 BaseObject* result = barrier.ReadStaticRef(field);
184 EXPECT_EQ(result, dummyObj.get());
185 }
186
HWTEST_F_L0(BarrierTest,AtomicSwapRefField_ExchangesCorrectly)187 HWTEST_F_L0(BarrierTest, AtomicSwapRefField_ExchangesCorrectly) {
188 uint64_t initValue = reinterpret_cast<uint64_t>(dummyObj.get());
189 RefField<true> field(initValue);
190 BaseObject* newRef = reinterpret_cast<BaseObject*>(0x1234567890);
191 BaseObject* oldValue = barrier.AtomicSwapRefField(nullptr, field, newRef, std::memory_order_seq_cst);
192
193 EXPECT_EQ(oldValue, dummyObj.get());
194 EXPECT_EQ(field.GetTargetObject(std::memory_order_relaxed), newRef);
195 }
196
HWTEST_F_L0(BarrierTest,AtomicReadRefField_ReadsCorrectly)197 HWTEST_F_L0(BarrierTest, AtomicReadRefField_ReadsCorrectly) {
198 uint64_t initValue = reinterpret_cast<uint64_t>(dummyObj.get());
199 RefField<true> field(initValue);
200
201 BaseObject* value = barrier.AtomicReadRefField(nullptr, field, std::memory_order_seq_cst);
202
203 EXPECT_EQ(value, dummyObj.get());
204 }
205
HWTEST_F_L0(BarrierTest,CopyStructArray_CopiesDataCorrectly)206 HWTEST_F_L0(BarrierTest, CopyStructArray_CopiesDataCorrectly) {
207 constexpr size_t arraySize = 100;
208 char* srcBuffer = new char[arraySize];
209 char* dstBuffer = new char[arraySize];
210
211 for (size_t i = 0; i < arraySize; ++i) {
212 srcBuffer[i] = static_cast<char>(i % 256);
213 }
214
215 BaseObject srcObj;
216 BaseObject dstObj;
217
218 HeapAddress srcFieldAddr = reinterpret_cast<HeapAddress>(srcBuffer);
219 HeapAddress dstFieldAddr = reinterpret_cast<HeapAddress>(dstBuffer);
220
221 barrier.CopyStructArray(&dstObj, dstFieldAddr, arraySize, &srcObj, srcFieldAddr, arraySize);
222
223 EXPECT_EQ(memcmp(dstBuffer, srcBuffer, arraySize), 0);
224
225 delete[] srcBuffer;
226 delete[] dstBuffer;
227 }
228
HWTEST_F_L0(BarrierTest,ReadStruct_ReadsCorrectly)229 HWTEST_F_L0(BarrierTest, ReadStruct_ReadsCorrectly) {
230 struct TestStruct {
231 int a;
232 double b;
233 };
234
235 TestStruct* initValue = new TestStruct{42, 3.14};
236 RefField<false> field(reinterpret_cast<uint64_t>(initValue));
237
238 char dstBuffer[sizeof(TestStruct)];
239 HeapAddress dstAddr = reinterpret_cast<HeapAddress>(dstBuffer);
240
241 BaseObject dummyObj;
242 HeapAddress srcAddr = reinterpret_cast<HeapAddress>(field.GetTargetObject());
243
244 barrier.ReadStruct(dstAddr, &dummyObj, srcAddr, sizeof(TestStruct));
245
246 TestStruct* result = reinterpret_cast<TestStruct*>(dstBuffer);
247 EXPECT_EQ(result->a, initValue->a);
248 EXPECT_EQ(result->b, initValue->b);
249
250 delete initValue;
251 }
252
HWTEST_F_L0(BarrierTest,AtomicWriteStaticRef_NonConcurrent)253 HWTEST_F_L0(BarrierTest, AtomicWriteStaticRef_NonConcurrent)
254 {
255 DummyObject* targetObj = new DummyObject();
256 DummyObject* initialObj = new DummyObject();
257
258 RefField<true> field(reinterpret_cast<BaseObject*>(0x1));
259 field.SetTargetObject(initialObj);
260
261 MockCollector collector;
262 Barrier barrier(collector);
263
264 barrier.AtomicWriteRefField(nullptr, field, targetObj, std::memory_order_relaxed);
265
266 EXPECT_EQ(field.GetTargetObject(std::memory_order_relaxed), targetObj);
267 }