1 /**
2 * Copyright (c) 2021-2022 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 <sys/mman.h>
17
18 #include "libpandabase/mem/mem.h"
19 #include "libpandabase/os/mem.h"
20 #include "libpandabase/utils/asan_interface.h"
21 #include "libpandabase/utils/logger.h"
22 #include "libpandabase/utils/math_helpers.h"
23 #include "runtime/include/runtime.h"
24 #include "runtime/mem/alloc_config.h"
25 #include "runtime/mem/region_allocator-inl.h"
26 #include "runtime/mem/tlab.h"
27 #include "runtime/tests/allocator_test_base.h"
28
29 #include "runtime/mem/rem_set-inl.h"
30 #include "runtime/mem/region_space.h"
31 #include "runtime/mem/gc/gc.h"
32
33 namespace panda::mem::test {
34
35 using NonObjectRegionAllocator = RegionAllocator<EmptyAllocConfigWithCrossingMap>;
36 using RemSetWithCommonLock = RemSet<RemSetLockConfig::CommonLock>;
37
38 class RemSetTest : public testing::Test {
39 public:
RemSetTest()40 RemSetTest()
41 {
42 options_.SetShouldLoadBootPandaFiles(false);
43 options_.SetShouldInitializeIntrinsics(false);
44 Runtime::Create(options_);
45 // For tests we don't limit spaces
46 size_t space_size = options_.GetHeapSizeLimit();
47 spaces_.young_space_.Initialize(space_size, space_size);
48 spaces_.mem_space_.Initialize(space_size, space_size);
49 spaces_.InitializePercentages(0, 100);
50 spaces_.is_initialized_ = true;
51 thread_ = panda::MTManagedThread::GetCurrent();
52 thread_->ManagedCodeBegin();
53 Init();
54 }
55
~RemSetTest()56 ~RemSetTest()
57 {
58 thread_->ManagedCodeEnd();
59 card_table_ = nullptr;
60 Runtime::Destroy();
61 }
62
Init()63 void Init()
64 {
65 auto lang = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
66 ext_ = Runtime::GetCurrent()->GetClassLinker()->GetExtension(lang);
67 card_table_ = MakePandaUnique<CardTable>(Runtime::GetCurrent()->GetInternalAllocator(),
68 PoolManager::GetMmapMemPool()->GetMinObjectAddress(),
69 PoolManager::GetMmapMemPool()->GetTotalObjectSize());
70 card_table_->Initialize();
71 }
72
SetCardTable(RemSetT * rset,CardTable * card_table)73 static void SetCardTable(RemSetT *rset, CardTable *card_table)
74 {
75 rset->SetCardTable(card_table);
76 }
77
78 protected:
79 panda::MTManagedThread *thread_;
80 RuntimeOptions options_;
81 ClassLinkerExtension *ext_;
82 GenerationalSpaces spaces_;
83 PandaUniquePtr<CardTable> card_table_ {nullptr};
84 };
85
TEST_F(RemSetTest,AddRefTest)86 TEST_F(RemSetTest, AddRefTest)
87 {
88 mem::MemStatsType *mem_stats = new mem::MemStatsType();
89 NonObjectRegionAllocator allocator(mem_stats, &spaces_);
90 auto cls = ext_->CreateClass(nullptr, 0, 0, sizeof(panda::Class));
91 cls->SetObjectSize(allocator.GetMaxRegularObjectSize());
92
93 auto obj1 = static_cast<ObjectHeader *>(allocator.Alloc(allocator.GetMaxRegularObjectSize()));
94 obj1->SetClass(cls);
95 auto region1 = ObjectToRegion(obj1);
96
97 auto obj2 = static_cast<ObjectHeader *>(allocator.Alloc(allocator.GetMaxRegularObjectSize()));
98 obj2->SetClass(cls);
99 auto region2 = ObjectToRegion(obj2);
100
101 // simulate gc process: mark obj2 and update live bitmap with mark bitmap
102 region2->GetMarkBitmap()->Set(obj2);
103 region2->CreateLiveBitmap();
104 region2->SwapMarkBitmap();
105
106 auto remset1 = region1->GetRemSet();
107 SetCardTable(remset1, card_table_.get());
108 remset1->AddRef(obj2);
109
110 PandaVector<void *> test_list;
111 auto visitor = [&test_list](void *obj) { test_list.push_back(obj); };
112 remset1->VisitMarkedCards(visitor);
113 ASSERT_EQ(test_list.size(), 1);
114 auto first = test_list.front();
115 ASSERT_EQ(first, obj2);
116
117 ext_->FreeClass(cls);
118 delete mem_stats;
119 }
120
TEST_F(RemSetTest,AddRefWithAddrTest)121 TEST_F(RemSetTest, AddRefWithAddrTest)
122 {
123 mem::MemStatsType *mem_stats = new mem::MemStatsType();
124 NonObjectRegionAllocator allocator(mem_stats, &spaces_);
125 auto cls = ext_->CreateClass(nullptr, 0, 0, sizeof(panda::Class));
126 cls->SetObjectSize(allocator.GetMaxRegularObjectSize());
127
128 auto obj1 = static_cast<ObjectHeader *>(allocator.Alloc(allocator.GetMaxRegularObjectSize()));
129 obj1->SetClass(cls);
130 auto region1 = ObjectToRegion(obj1);
131
132 auto obj2 = static_cast<ObjectHeader *>(allocator.Alloc(allocator.GetMaxRegularObjectSize()));
133 obj2->SetClass(cls);
134 auto region2 = ObjectToRegion(obj2);
135
136 region1->CreateLiveBitmap()->Set(obj1);
137
138 RemSetWithCommonLock::AddRefWithAddr(obj1, obj2);
139 auto remset2 = region2->GetRemSet();
140
141 PandaVector<void *> test_list;
142 auto visitor = [&test_list](void *obj) { test_list.push_back(obj); };
143 remset2->VisitMarkedCards(visitor);
144 ASSERT_EQ(1, test_list.size());
145
146 auto first = test_list.front();
147 ASSERT_EQ(first, obj1);
148
149 ext_->FreeClass(cls);
150 delete mem_stats;
151 }
152
TEST_F(RemSetTest,TravelObjectToAddRefTest)153 TEST_F(RemSetTest, TravelObjectToAddRefTest)
154 {
155 mem::MemStatsType *mem_stats = new mem::MemStatsType();
156 NonObjectRegionAllocator allocator(mem_stats, &spaces_);
157 auto cls = ext_->CreateClass(nullptr, 0, 0, sizeof(panda::Class));
158 cls->SetObjectSize(allocator.GetMaxRegularObjectSize());
159 cls->SetRefFieldsNum(1, false);
160 auto offset = ObjectHeader::ObjectHeaderSize();
161 cls->SetRefFieldsOffset(offset, false);
162
163 auto obj1 = static_cast<ObjectHeader *>(allocator.Alloc(allocator.GetMaxRegularObjectSize()));
164 obj1->SetClass(cls);
165 auto region1 = ObjectToRegion(obj1);
166
167 auto obj2 = static_cast<ObjectHeader *>(allocator.Alloc(allocator.GetMaxRegularObjectSize()));
168 obj2->SetClass(cls);
169 auto region2 = ObjectToRegion(obj2);
170
171 // simulate gc process: mark obj2 and update live bitmap with mark bitmap
172 region1->CreateLiveBitmap()->Set(obj1);
173
174 static_cast<ObjectHeader *>(obj1)->SetFieldObject<false, false>(offset, static_cast<ObjectHeader *>(obj2));
175
176 RemSetWithCommonLock::TraverseObjectToAddRef(obj1);
177 auto remset2 = region2->GetRemSet();
178
179 PandaVector<void *> test_list;
180 auto visitor = [&test_list](void *obj) { test_list.push_back(obj); };
181 remset2->VisitMarkedCards(visitor);
182 ASSERT_EQ(1, test_list.size());
183
184 auto first = test_list.front();
185 ASSERT_EQ(first, obj1);
186
187 ext_->FreeClass(cls);
188 delete mem_stats;
189 }
190
191 } // namespace panda::mem::test
192