• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_manager.h"
17 #include "common_components/heap/collector/marking_collector.h"
18 #include "common_components/heap/heap.cpp"
19 #include "common_components/common_runtime/base_runtime_param.h"
20 #include "common_components/heap/heap_manager.h"
21 #include "common_components/tests/test_helper.h"
22 #include <cstdint>
23 
24 using namespace common;
25 
26 namespace common::test {
27 const size_t SIZE_SIXTEEN = 16;
28 const size_t SIZE_MAX_TEST = 1024;
29 const size_t SIZE_HALF_MAX_TEST = 512;
30 const uint32_t NUM_TEN = 10;
31 const uint32_t NUM_TWO = 2;
32 const uint32_t NUM_THREE = 3;
33 const uint32_t NUM_FIVE = 5;
34 
35 class RegionManagerTest : public common::test::BaseTestWithScope {
36 protected:
37     void* regionMemory_;
38     size_t totalUnits_ = SIZE_MAX_TEST;
39     size_t heapSize_;
40     Mutator* mutator_ = nullptr;
41 
SetUpTestCase()42     static void SetUpTestCase()
43     {
44         BaseRuntime::GetInstance()->Init();
45     }
46 
TearDownTestCase()47     static void TearDownTestCase()
48     {
49         BaseRuntime::GetInstance()->Fini();
50     }
51 
SetUp()52     void SetUp() override
53     {
54         heapSize_ = totalUnits_ * RegionDesc::UNIT_SIZE;
55         size_t allocSize = heapSize_ + totalUnits_ * sizeof(RegionDesc);
56         regionMemory_ = malloc(allocSize);
57         ASSERT_NE(regionMemory_, nullptr);
58         uintptr_t unitInfoStart = reinterpret_cast<uintptr_t>(regionMemory_);
59         size_t metadataSize = totalUnits_ * sizeof(RegionDesc);
60         uintptr_t heapStartAddress = unitInfoStart + metadataSize;
61         RegionDesc::Initialize(totalUnits_, unitInfoStart, heapStartAddress);
62         mutator_ = Mutator::NewMutator();
63         ASSERT_NE(mutator_, nullptr);
64         mutator_->InitTid();
65         ThreadLocal::GetThreadLocalData()->mutator = mutator_;
66     }
67 
TearDown()68     void TearDown() override
69     {
70         if (mutator_) {
71             delete mutator_;
72             mutator_ = nullptr;
73         }
74         if (regionMemory_) {
75             free(regionMemory_);
76             regionMemory_ = nullptr;
77         }
78     }
79 };
80 
HWTEST_F_L0(RegionManagerTest,VisitLiveObjectsUntilFalse_LiveByteCountZero)81 HWTEST_F_L0(RegionManagerTest, VisitLiveObjectsUntilFalse_LiveByteCountZero)
82 {
83     size_t unitIdx = 0;
84     size_t nUnit = 1;
85     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::SMALL_SIZED_UNITS);
86     region->AddLiveByteCount(0);
87 
88     bool callbackCalled = false;
89     bool result = region->VisitLiveObjectsUntilFalse([&callbackCalled](BaseObject* obj) {
90         callbackCalled = true;
91         return true;
92     });
93     EXPECT_TRUE(result);
94     EXPECT_FALSE(callbackCalled);
95 }
96 
HWTEST_F_L0(RegionManagerTest,VisitLiveObjectsUntilFalse_IsSmallRegion)97 HWTEST_F_L0(RegionManagerTest, VisitLiveObjectsUntilFalse_IsSmallRegion)
98 {
99     size_t unitIdx = 0;
100     size_t nUnit = 1;
101     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::SMALL_SIZED_UNITS);
102     ASSERT_NE(region, nullptr);
103     region->AddLiveByteCount(SIZE_SIXTEEN);
104 
105     bool callbackCalled = false;
106     bool result = region->VisitLiveObjectsUntilFalse(
107         [&callbackCalled](BaseObject* obj) {
108             callbackCalled = true;
109             return true;
110         });
111     EXPECT_FALSE(callbackCalled);
112     EXPECT_TRUE(result);
113 }
114 
HWTEST_F_L0(RegionManagerTest,VisitLiveObjectsUntilFalse_IsLargeRegion)115 HWTEST_F_L0(RegionManagerTest, VisitLiveObjectsUntilFalse_IsLargeRegion)
116 {
117     size_t unitIdx = 0;
118     size_t nUnit = 4;
119     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::LARGE_SIZED_UNITS);
120     ASSERT_NE(region, nullptr);
121     region->AddLiveByteCount(SIZE_SIXTEEN);
122     bool callbackCalled = false;
123 
124     bool result = region->VisitLiveObjectsUntilFalse(
125         [&callbackCalled](BaseObject* obj) {
126             callbackCalled = true;
127             return true;
128         });
129     EXPECT_TRUE(callbackCalled);
130     EXPECT_TRUE(result);
131 }
132 
HWTEST_F_L0(RegionManagerTest,VisitLiveObjectsUntilFalse)133 HWTEST_F_L0(RegionManagerTest, VisitLiveObjectsUntilFalse)
134 {
135     size_t unitIdx = 0;
136     size_t nUnit = 1;
137     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::SMALL_SIZED_UNITS);
138     ASSERT_NE(region, nullptr);
139     region->AddLiveByteCount(SIZE_SIXTEEN);
140     bool callbackCalled = false;
141 
142     bool result = region->VisitLiveObjectsUntilFalse(
143         [&callbackCalled](BaseObject* obj) {
144             callbackCalled = true;
145             return true;
146         });
147     EXPECT_FALSE(callbackCalled);
148     EXPECT_TRUE(result);
149 }
HWTEST_F_L0(RegionManagerTest,VisitAllObjectsBeforeFix1)150 HWTEST_F_L0(RegionManagerTest, VisitAllObjectsBeforeFix1)
151 {
152     size_t unitIdx = 0;
153     size_t nUnit = 4;
154     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::LARGE_SIZED_UNITS);
155     ASSERT_NE(region, nullptr);
156 
157     uintptr_t start = region->GetRegionStart();
158     region->SetRegionAllocPtr(start + SIZE_SIXTEEN);
159     bool callbackCalled = false;
160     region->VisitAllObjectsBeforeCopy([&](BaseObject* obj) {
161         callbackCalled = true;
162         EXPECT_EQ(obj, reinterpret_cast<BaseObject*>(region->GetRegionStart()));
163     });
164     EXPECT_TRUE(callbackCalled);
165 }
166 
HWTEST_F_L0(RegionManagerTest,VisitAllObjectsBeforeFix2)167 HWTEST_F_L0(RegionManagerTest, VisitAllObjectsBeforeFix2)
168 {
169     size_t unitIdx = 0;
170     size_t nUnit = 1;
171     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::SMALL_SIZED_UNITS);
172     RegionDesc::InitFreeRegion(unitIdx, nUnit);
173     ASSERT_NE(region, nullptr);
174 
175     uintptr_t start = region->GetRegionStart();
176     region->SetRegionAllocPtr(start + SIZE_SIXTEEN);
177     bool callbackCalled = false;
178     region->VisitAllObjectsBeforeCopy([&](BaseObject* obj) {
179         callbackCalled = true;
180         EXPECT_EQ(obj, reinterpret_cast<BaseObject*>(region->GetRegionStart()));
181     });
182     EXPECT_FALSE(callbackCalled);
183 }
184 
HWTEST_F_L0(RegionManagerTest,VisitAllObjectsBeforeFix3)185 HWTEST_F_L0(RegionManagerTest, VisitAllObjectsBeforeFix3)
186 {
187     size_t unitIdx = 0;
188     size_t nUnit = 4;
189 
190     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::LARGE_SIZED_UNITS);
191     ASSERT_NE(region, nullptr);
192 
193     bool callbackCalled = false;
194     region->VisitAllObjectsBeforeCopy([&](BaseObject* obj) {
195         callbackCalled = true;
196         EXPECT_EQ(obj, reinterpret_cast<BaseObject*>(region->GetRegionStart()));
197     });
198     EXPECT_FALSE(callbackCalled);
199 }
200 
HWTEST_F_L0(RegionManagerTest,VisitAllObjectsBeforeFix4)201 HWTEST_F_L0(RegionManagerTest, VisitAllObjectsBeforeFix4)
202 {
203     size_t unitIdx = 0;
204     size_t nUnit = 1;
205 
206     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::SMALL_SIZED_UNITS);
207     ASSERT_NE(region, nullptr);
208 
209     bool callbackCalled = false;
210     region->VisitAllObjectsBeforeCopy([&](BaseObject* obj) {
211         callbackCalled = true;
212         EXPECT_EQ(obj, reinterpret_cast<BaseObject*>(region->GetRegionStart()));
213     });
214     EXPECT_FALSE(callbackCalled);
215 }
216 
HWTEST_F_L0(RegionManagerTest,PrependRegionLockedTest)217 HWTEST_F_L0(RegionManagerTest, PrependRegionLockedTest)
218 {
219     RegionList list("list");
220     list.PrependRegionLocked(nullptr, RegionDesc::RegionType::FREE_REGION);
221     EXPECT_EQ(list.GetHeadRegion(), nullptr);
222 }
223 
HWTEST_F_L0(RegionManagerTest,ReleaseGarbageRegions)224 HWTEST_F_L0(RegionManagerTest, ReleaseGarbageRegions)
225 {
226     size_t targetCachedSize = 0;
227     RegionManager manager;
228     FreeRegionManager freeRegionManager(manager);
229     freeRegionManager.Initialize(NUM_TEN);
230     freeRegionManager.AddGarbageUnits(0, 1);
231     freeRegionManager.AddGarbageUnits(NUM_TWO, NUM_TWO);
232     freeRegionManager.AddGarbageUnits(NUM_FIVE, NUM_THREE);
233     size_t released = freeRegionManager.ReleaseGarbageRegions(targetCachedSize);
234     EXPECT_GT(released, 0);
235 }
236 
HWTEST_F_L0(RegionManagerTest,ReclaimRegion1)237 HWTEST_F_L0(RegionManagerTest, ReclaimRegion1)
238 {
239     size_t huge_page = (2048 * KB) / getpagesize();
240     size_t nUnit = 1;
241     size_t unitIdx = 0;
242     RegionManager manager;
243     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
244     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit,
245         RegionDesc::UnitRole::SMALL_SIZED_UNITS);
246     ASSERT_NE(region, nullptr);
247     EXPECT_FALSE(region->IsLargeRegion());
248     manager.ReclaimRegion(region);
249     EXPECT_GT(manager.GetDirtyUnitCount(), 0);
250 }
251 
HWTEST_F_L0(RegionManagerTest,ReclaimRegion2)252 HWTEST_F_L0(RegionManagerTest, ReclaimRegion2)
253 {
254     size_t huge_page = (2048 * KB) / getpagesize();
255     size_t nUnit = huge_page;
256     size_t unitIdx = 0;
257     RegionManager manager;
258     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
259     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit,
260         RegionDesc::UnitRole::LARGE_SIZED_UNITS);
261     ASSERT_NE(region, nullptr);
262     manager.ReclaimRegion(region);
263     EXPECT_GT(manager.GetDirtyUnitCount(), 0);
264 }
265 
HWTEST_F_L0(RegionManagerTest,ReleaseRegion)266 HWTEST_F_L0(RegionManagerTest, ReleaseRegion)
267 {
268     size_t huge_page = (2048 * KB) / getpagesize();
269     size_t nUnit = 1;
270     size_t unitIdx = 0;
271     RegionManager manager;
272     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
273     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit,
274         RegionDesc::UnitRole::LARGE_SIZED_UNITS);
275     ASSERT_NE(region, nullptr);
276     auto ret = manager.ReleaseRegion(region);
277     EXPECT_EQ(ret, region->GetRegionSize());
278 }
279 
HWTEST_F_L0(RegionManagerTest,TakeRegion1)280 HWTEST_F_L0(RegionManagerTest, TakeRegion1)
281 {
282     ASSERT_NE(mutator_, nullptr);
283     mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
284     RegionManager manager;
285     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
286     size_t nUnit = 4;
287     RegionDesc* garbageRegion = RegionDesc::InitRegion(SIZE_HALF_MAX_TEST, nUnit,
288         RegionDesc::UnitRole::LARGE_SIZED_UNITS);
289     auto size = manager.CollectRegion(garbageRegion);
290     RegionDesc* region = manager.TakeRegion(1, RegionDesc::UnitRole::SMALL_SIZED_UNITS, false, false);
291     EXPECT_GT(manager.GetDirtyUnitCount(), 0);
292 }
293 
HWTEST_F_L0(RegionManagerTest,TakeRegion2)294 HWTEST_F_L0(RegionManagerTest, TakeRegion2)
295 {
296     ASSERT_NE(mutator_, nullptr);
297     mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
298     RegionManager manager;
299     size_t nUnit = 1;
300     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
301     RegionDesc* garbageRegion = RegionDesc::InitRegion(SIZE_HALF_MAX_TEST, nUnit,
302         RegionDesc::UnitRole::LARGE_SIZED_UNITS);
303     auto size = manager.CollectRegion(garbageRegion);
304     RegionDesc* region = manager.TakeRegion(16, RegionDesc::UnitRole::LARGE_SIZED_UNITS, true, false);
305     EXPECT_NE(region, nullptr);
306 }
307 
HWTEST_F_L0(RegionManagerTest,AllocPinnedFromFreeList)308 HWTEST_F_L0(RegionManagerTest, AllocPinnedFromFreeList)
309 {
310     ASSERT_NE(mutator_, nullptr);
311     mutator_->SetMutatorPhase(GCPhase::GC_PHASE_FIX);
312     RegionManager manager;
313     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
314     EXPECT_EQ(manager.AllocPinnedFromFreeList(0), 0);
315 }
316 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly1)317 HWTEST_F_L0(RegionManagerTest, AllocReadOnly1)
318 {
319     auto* mutator = common::Mutator::GetMutator();
320     mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM);
321     RegionManager manager;
322     manager.ClearAllGCInfo();
323     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
324     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
325     EXPECT_EQ(ret, 0);
326 }
327 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly2)328 HWTEST_F_L0(RegionManagerTest, AllocReadOnly2)
329 {
330     auto* mutator = common::Mutator::GetMutator();
331     mutator->SetMutatorPhase(GCPhase::GC_PHASE_MARK);
332     RegionManager manager;
333     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
334     manager.ClearAllGCInfo();
335     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
336     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
337     EXPECT_NE(ret, 0);
338 }
339 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly3)340 HWTEST_F_L0(RegionManagerTest, AllocReadOnly3)
341 {
342     auto* mutator = common::Mutator::GetMutator();
343     mutator->SetMutatorPhase(GCPhase::GC_PHASE_POST_MARK);
344     RegionManager manager;
345     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
346     manager.ClearAllGCInfo();
347     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
348     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
349     EXPECT_NE(ret, 0);
350 }
351 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly4)352 HWTEST_F_L0(RegionManagerTest, AllocReadOnly4)
353 {
354     auto* mutator = common::Mutator::GetMutator();
355     mutator->SetMutatorPhase(GCPhase::GC_PHASE_PRECOPY);
356     RegionManager manager;
357     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
358     manager.ClearAllGCInfo();
359     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
360     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
361     EXPECT_NE(ret, 0);
362 }
363 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly5)364 HWTEST_F_L0(RegionManagerTest, AllocReadOnly5)
365 {
366     auto* mutator = common::Mutator::GetMutator();
367     mutator->SetMutatorPhase(GCPhase::GC_PHASE_COPY);
368     RegionManager manager;
369     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
370     manager.ClearAllGCInfo();
371     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
372     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
373     EXPECT_NE(ret, 0);
374 }
375 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly6)376 HWTEST_F_L0(RegionManagerTest, AllocReadOnly6)
377 {
378     auto* mutator = common::Mutator::GetMutator();
379     mutator->SetMutatorPhase(GCPhase::GC_PHASE_FIX);
380     RegionManager manager;
381     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
382     manager.ClearAllGCInfo();
383     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
384     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
385     EXPECT_NE(ret, 0);
386 }
387 
HWTEST_F_L0(RegionManagerTest,AllocReadOnly7)388 HWTEST_F_L0(RegionManagerTest, AllocReadOnly7)
389 {
390     auto* mutator = common::Mutator::GetMutator();
391     mutator->SetMutatorPhase(GCPhase::GC_PHASE_UNDEF);
392     RegionManager manager;
393     manager.Initialize(SIZE_MAX_TEST, reinterpret_cast<uintptr_t>(regionMemory_));
394     manager.ClearAllGCInfo();
395     ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR);
396     uintptr_t ret = manager.AllocReadOnly(sizeof(RegionDesc), false);
397     EXPECT_NE(ret, 0);
398 }
399 
HWTEST_F_L0(RegionManagerTest,VisitRememberSetTest)400 HWTEST_F_L0(RegionManagerTest, VisitRememberSetTest)
401 {
402     size_t totalUnits = 1024;
403     size_t heapSize = totalUnits * RegionDesc::UNIT_SIZE;
404 
405     void* regionMemory = malloc(heapSize + 4096);
406     ASSERT_NE(regionMemory, nullptr);
407 
408     uintptr_t heapStartAddress = reinterpret_cast<uintptr_t>(regionMemory);
409     uintptr_t regionInfoAddr = heapStartAddress + 4096;
410 
411     RegionManager manager;
412     manager.Initialize(totalUnits, regionInfoAddr);
413 
414     size_t unitIdx = 0;
415     size_t nUnit = 4;
416     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::LARGE_SIZED_UNITS);
417     ASSERT_NE(region, nullptr);
418 
419     manager.MarkRememberSet([&](BaseObject* obj) {});
420 
421     int callbackCount = 0;
422     region->VisitRememberSet([&](BaseObject* obj) {
423         callbackCount++;
424     });
425 
426     EXPECT_GE(callbackCount, 0);
427     free(regionMemory);
428 }
429 
HWTEST_F_L0(RegionManagerTest,VisitRememberSetBeforeCopyTest)430 HWTEST_F_L0(RegionManagerTest, VisitRememberSetBeforeCopyTest)
431 {
432     size_t totalUnits = 1024;
433     size_t heapSize = totalUnits * RegionDesc::UNIT_SIZE;
434 
435     void* regionMemory = malloc(heapSize + 4096);
436     ASSERT_NE(regionMemory, nullptr);
437 
438     uintptr_t heapStartAddress = reinterpret_cast<uintptr_t>(regionMemory);
439     uintptr_t regionInfoAddr = heapStartAddress + 4096;
440 
441     RegionManager manager;
442     manager.Initialize(totalUnits, regionInfoAddr);
443 
444     size_t unitIdx = 0;
445     size_t nUnit = 4;
446     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::LARGE_SIZED_UNITS);
447     ASSERT_NE(region, nullptr);
448 
449     manager.MarkRememberSet([&](BaseObject* obj) {});
450 
451     int callbackCount = 0;
452     region->VisitRememberSetBeforeCopy([&](BaseObject* obj) {
453         callbackCount++;
454     });
455 
456     EXPECT_GE(callbackCount, 0);
457     free(regionMemory);
458 }
459 
HWTEST_F_L0(RegionManagerTest,VisitRememberSetBeforeMarkingTest)460 HWTEST_F_L0(RegionManagerTest, VisitRememberSetBeforeMarkingTest)
461 {
462     size_t totalUnits = 1024;
463     size_t heapSize = totalUnits * RegionDesc::UNIT_SIZE;
464 
465     void* regionMemory = malloc(heapSize + 4096);
466     ASSERT_NE(regionMemory, nullptr);
467 
468     uintptr_t heapStartAddress = reinterpret_cast<uintptr_t>(regionMemory);
469     uintptr_t regionInfoAddr = heapStartAddress + 4096;
470 
471     RegionManager manager;
472     manager.Initialize(totalUnits, regionInfoAddr);
473 
474     size_t unitIdx = 0;
475     size_t nUnit = 4;
476     RegionDesc* region = RegionDesc::InitRegion(unitIdx, nUnit, RegionDesc::UnitRole::LARGE_SIZED_UNITS);
477     ASSERT_NE(region, nullptr);
478 
479     manager.MarkRememberSet([&](BaseObject* obj) {});
480 
481     int callbackCount = 0;
482     region->VisitRememberSetBeforeMarking([&](BaseObject* obj) {
483         callbackCount++;
484     });
485 
486     EXPECT_GE(callbackCount, 0);
487     free(regionMemory);
488 }
489 }
490