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 "common_components/heap/allocator/region_desc.h"
17 #include "common_components/heap/allocator/region_space.h"
18 #include "common_components/mutator/satb_buffer.h"
19 #include "common_components/tests/test_helper.h"
20 #include "common_interfaces/base_runtime.h"
21
22 using namespace common;
23 namespace common::test {
24
25 class SatbBufferTest : public BaseTestWithScope {
26 protected:
SetUpTestCase()27 static void SetUpTestCase()
28 {
29 BaseRuntime::GetInstance()->Init();
30 }
31
TearDownTestCase()32 static void TearDownTestCase()
33 {
34 BaseRuntime::GetInstance()->Fini();
35 }
36
SetUp()37 void SetUp() override
38 {
39 holder_ = ThreadHolder::CreateAndRegisterNewThreadHolder(nullptr);
40 scope_ = new ThreadHolder::TryBindMutatorScope(holder_);
41 }
42
TearDown()43 void TearDown() override
44 {
45 if (scope_ != nullptr) {
46 delete scope_;
47 scope_ = nullptr;
48 }
49 }
50
51 ThreadHolder *holder_ {nullptr};
52 ThreadHolder::TryBindMutatorScope *scope_ {nullptr};
53 };
54
HWTEST_F_L0(SatbBufferTest,NullptrReturnsFalse)55 HWTEST_F_L0(SatbBufferTest, NullptrReturnsFalse)
56 {
57 EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(nullptr));
58 }
59
HWTEST_F_L0(SatbBufferTest,IsYoungSpaceObject1)60 HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject1)
61 {
62 auto* mutator = common::Mutator::GetMutator();
63 mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
64 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
65 uintptr_t addr = theAllocator.AllocOldRegion();
66 ASSERT_NE(addr, 0);
67 RegionDesc* region = RegionDesc::GetRegionDescAt(addr);
68 region->SetRegionType(RegionDesc::RegionType::ALIVE_REGION_FIRST);
69 Heap::GetHeap().SetGCReason(GC_REASON_YOUNG);
70
71 BaseObject* obj = reinterpret_cast<BaseObject*>(addr);
72 EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(obj));
73 }
74
HWTEST_F_L0(SatbBufferTest,IsYoungSpaceObject2)75 HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject2)
76 {
77 auto* mutator = common::Mutator::GetMutator();
78 mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
79 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
80 uintptr_t addr = theAllocator.AllocOldRegion();
81 ASSERT_NE(addr, 0);
82 RegionDesc* region = RegionDesc::GetRegionDescAt(addr);
83 region->SetRegionType(RegionDesc::RegionType::FROM_REGION);
84 Heap::GetHeap().SetGCReason(GC_REASON_HEU);
85
86 BaseObject* obj = reinterpret_cast<BaseObject*>(addr);
87 EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(obj));
88 }
89
HWTEST_F_L0(SatbBufferTest,IsYoungSpaceObject3)90 HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject3)
91 {
92 auto* mutator = common::Mutator::GetMutator();
93 mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
94 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
95 uintptr_t addr = theAllocator.AllocOldRegion();
96 ASSERT_NE(addr, 0);
97 RegionDesc* region = RegionDesc::GetRegionDescAt(addr);
98 region->SetRegionType(RegionDesc::RegionType::FROM_REGION);
99 Heap::GetHeap().SetGCReason(GC_REASON_YOUNG);
100
101 BaseObject* obj = reinterpret_cast<BaseObject*>(addr);
102 EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(obj));
103 }
104
HWTEST_F_L0(SatbBufferTest,IsYoungSpaceObject4)105 HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject4)
106 {
107 auto* mutator = common::Mutator::GetMutator();
108 mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
109 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
110 uintptr_t addr = theAllocator.AllocOldRegion();
111 ASSERT_NE(addr, 0);
112 RegionDesc* region = RegionDesc::GetRegionDescAt(addr);
113 region->SetRegionType(RegionDesc::RegionType::ALIVE_REGION_FIRST);
114 Heap::GetHeap().SetGCReason(GC_REASON_HEU);
115 BaseObject* obj = reinterpret_cast<BaseObject*>(addr);
116 EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(obj));
117 }
118
HWTEST_F_L0(SatbBufferTest,IsMarkedObject)119 HWTEST_F_L0(SatbBufferTest, IsMarkedObject)
120 {
121 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
122 uintptr_t addr = theAllocator.AllocOldRegion();
123 ASSERT_NE(addr, 0U);
124 BaseObject* obj = reinterpret_cast<BaseObject*>(addr);
125 Heap::GetHeap().SetGCReason(GC_REASON_HEU);
126
127 RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast<uintptr_t>(obj));
128 region->SetMarkedRegionFlag(1);
129
130 size_t offset = region->GetAddressOffset(reinterpret_cast<HeapAddress>(obj));
131 RegionBitmap* markBitmap = region->GetOrAllocMarkBitmap();
132 markBitmap->MarkBits(offset);
133
134 bool result = SatbBuffer::Instance().ShouldEnqueue(obj);
135 EXPECT_FALSE(result);
136 }
137
ClearMarkBit(RegionBitmap * bitmap,size_t offset)138 void ClearMarkBit(RegionBitmap* bitmap, size_t offset)
139 {
140 uintptr_t* bits = *reinterpret_cast<uintptr_t**>(bitmap);
141
142 size_t wordIndex = offset / (sizeof(uintptr_t) * 8);
143 size_t bitIndex = offset % (sizeof(uintptr_t) * 8);
144
145 uintptr_t mask = ~(static_cast<uintptr_t>(1) << bitIndex);
146
147 uintptr_t* addr = const_cast<uintptr_t*>(bits + wordIndex);
148 uintptr_t oldVal;
149 uintptr_t newVal;
150
151 do {
152 oldVal = __atomic_load_n(addr, __ATOMIC_ACQUIRE);
153 newVal = oldVal & mask;
154 if (oldVal == newVal) {
155 return;
156 }
157 } while (!__atomic_compare_exchange_n(addr, &oldVal, newVal, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE));
158 }
159
HWTEST_F_L0(SatbBufferTest,EnqueueObject)160 HWTEST_F_L0(SatbBufferTest, EnqueueObject)
161 {
162 RegionSpace& theAllocator = reinterpret_cast<RegionSpace&>(Heap::GetHeap().GetAllocator());
163 uintptr_t addr = theAllocator.AllocOldRegion();
164 ASSERT_NE(addr, 0U);
165
166 uintptr_t objAddress = addr + 0x100;
167 BaseObject* obj = reinterpret_cast<BaseObject*>(objAddress);
168 Heap::GetHeap().SetGCReason(GC_REASON_HEU);
169
170 RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast<uintptr_t>(obj));
171 region->SetRegionType(RegionDesc::RegionType::FROM_REGION);
172 region->SetMarkingLine();
173 region->SetMarkedRegionFlag(0);
174 RegionBitmap* markBitmap = region->GetMarkBitmap();
175 size_t offset = region->GetAddressOffset(reinterpret_cast<HeapAddress>(obj));
176 if (markBitmap != nullptr) {
177 ClearMarkBit(markBitmap, offset);
178 }
179
180 region->SetEnqueuedRegionFlag(1);
181 RegionBitmap* enqueueBitmap = region->GetOrAllocEnqueueBitmap();
182 enqueueBitmap->MarkBits(offset);
183
184 bool result = SatbBuffer::Instance().ShouldEnqueue(obj);
185 EXPECT_FALSE(result);
186 }
187 } // namespace common::test
188