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 <gtest/gtest.h>
17 #include <sys/mman.h>
18
19 #include "libpandabase/mem/mem.h"
20 #include "libpandabase/os/mem.h"
21 #include "libpandabase/utils/asan_interface.h"
22 #include "runtime/include/class_linker.h"
23 #include "runtime/include/runtime.h"
24 #include "runtime/mem/freelist_allocator-inl.h"
25 #include "runtime/mem/gc/hybrid-gc/hybrid_object_allocator.h"
26 #include "runtime/mem/humongous_obj_allocator-inl.h"
27 #include "runtime/tests/class_linker_test_extension.h"
28
29 namespace panda::mem {
30 class HybridObjectAllocatorTest : public testing::Test {
31 public:
HybridObjectAllocatorTest()32 HybridObjectAllocatorTest()
33 {
34 options_.SetShouldLoadBootPandaFiles(false);
35 options_.SetShouldInitializeIntrinsics(false);
36 Runtime::Create(options_);
37 thread_ = panda::MTManagedThread::GetCurrent();
38 thread_->ManagedCodeBegin();
39 }
~HybridObjectAllocatorTest()40 ~HybridObjectAllocatorTest()
41 {
42 thread_->ManagedCodeEnd();
43 Runtime::Destroy();
44 }
45
RemovePools(HybridObjectAllocator * allocator)46 void RemovePools(HybridObjectAllocator *allocator)
47 {
48 auto large_allocator = allocator->GetLargeObjectAllocator();
49 large_allocator->VisitAndRemoveAllPools(
50 [](void *mem, size_t size) { PoolManager::GetMmapMemPool()->FreePool(mem, size); });
51
52 auto humongous_allocator = allocator->GetHumongousObjectAllocator();
53 humongous_allocator->VisitAndRemoveAllPools(
54 [](void *mem, size_t size) { PoolManager::GetMmapMemPool()->FreePool(mem, size); });
55 }
56
Free(HybridObjectAllocator * allocator,void * mem)57 void Free(HybridObjectAllocator *allocator, void *mem)
58 {
59 auto large_allocator = allocator->GetLargeObjectAllocator();
60 if (large_allocator->AllocatedByFreeListAllocator(mem)) {
61 large_allocator->Free(mem);
62 return;
63 }
64
65 auto humongous_allocator = allocator->GetHumongousObjectAllocator();
66 if (humongous_allocator->AllocatedByHumongousObjAllocator(mem)) {
67 humongous_allocator->Free(mem);
68 return;
69 }
70
71 UNREACHABLE();
72 }
73
AllocatedByLargeObjAllocator(FreeListAllocator<ObjectAllocConfig> * allocator,void * mem)74 bool AllocatedByLargeObjAllocator(FreeListAllocator<ObjectAllocConfig> *allocator, void *mem)
75 {
76 return allocator->AllocatedByFreeListAllocator(mem);
77 }
78
AllocatedByHumongousObjAllocator(HumongousObjAllocator<ObjectAllocConfig> * allocator,void * mem)79 bool AllocatedByHumongousObjAllocator(HumongousObjAllocator<ObjectAllocConfig> *allocator, void *mem)
80 {
81 return allocator->AllocatedByHumongousObjAllocator(mem);
82 }
83
84 protected:
85 panda::MTManagedThread *thread_;
86 RuntimeOptions options_;
87 };
88
TEST_F(HybridObjectAllocatorTest,AllocateInLargeAllocator)89 TEST_F(HybridObjectAllocatorTest, AllocateInLargeAllocator)
90 {
91 mem::MemStatsType *mem_stats = new mem::MemStatsType();
92 HybridObjectAllocator allocator(mem_stats, false);
93 ClassLinker *class_linker = Runtime::GetCurrent()->GetClassLinker();
94 ASSERT_NE(class_linker, nullptr);
95 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
96
97 auto allocate_helper = [&ctx](HybridObjectAllocator &hybrid_object_allocator, ClassRoot class_root,
98 size_t size) -> void * {
99 Class *klass = nullptr;
100 klass = Runtime::GetCurrent()->GetClassLinker()->GetExtension(ctx)->GetClassRoot(class_root);
101 return hybrid_object_allocator.AllocateInLargeAllocator(size, DEFAULT_ALIGNMENT, klass);
102 };
103
104 void *mem = nullptr;
105 mem = allocate_helper(allocator, ClassRoot::CLASS, HybridObjectAllocator::GetLargeThreshold());
106 ASSERT_EQ(mem, nullptr);
107
108 mem = allocate_helper(allocator, ClassRoot::ARRAY_I8, HybridObjectAllocator::GetLargeThreshold());
109 ASSERT_NE(mem, nullptr);
110 ASSERT_TRUE(AllocatedByLargeObjAllocator(allocator.GetLargeObjectAllocator(), mem));
111 Free(&allocator, mem);
112
113 size_t size = HybridObjectAllocator::LargeObjectAllocator::GetMaxSize() + 1;
114 mem = allocate_helper(allocator, ClassRoot::ARRAY_I8, size);
115 ASSERT_NE(mem, nullptr);
116 ASSERT_TRUE(AllocatedByHumongousObjAllocator(allocator.GetHumongousObjectAllocator(), mem));
117 Free(&allocator, mem);
118
119 mem = allocate_helper(allocator, ClassRoot::STRING, HybridObjectAllocator::GetLargeThreshold());
120 ASSERT_NE(mem, nullptr);
121 ASSERT_TRUE(AllocatedByLargeObjAllocator(allocator.GetLargeObjectAllocator(), mem));
122 Free(&allocator, mem);
123
124 size = HybridObjectAllocator::LargeObjectAllocator::GetMaxSize() + 1;
125 mem = allocate_helper(allocator, ClassRoot::STRING, size);
126 ASSERT_NE(mem, nullptr);
127 ASSERT_TRUE(AllocatedByHumongousObjAllocator(allocator.GetHumongousObjectAllocator(), mem));
128 Free(&allocator, mem);
129
130 RemovePools(&allocator);
131
132 delete mem_stats;
133 }
134
TEST_F(HybridObjectAllocatorTest,AllocateInNonLargeAllocator)135 TEST_F(HybridObjectAllocatorTest, AllocateInNonLargeAllocator)
136 {
137 mem::MemStatsType *mem_stats = new mem::MemStatsType();
138 HybridObjectAllocator allocator(mem_stats, false);
139
140 void *mem = allocator.Allocate(HybridObjectAllocator::GetLargeThreshold(), DEFAULT_ALIGNMENT, nullptr);
141 ASSERT_NE(mem, nullptr);
142
143 delete mem_stats;
144 }
145
146 } // namespace panda::mem
147