1 /*
2 * Copyright (c) 2021 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 "ecmascript/builtins/builtins_ark_tools.h"
17 #include "ecmascript/checkpoint/thread_state_transition.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/mem/full_gc.h"
20 #include "ecmascript/object_factory-inl.h"
21 #include "ecmascript/mem/concurrent_marker.h"
22 #include "ecmascript/mem/stw_young_gc.h"
23 #include "ecmascript/mem/partial_gc.h"
24 #include "ecmascript/serializer/serialize_chunk.h"
25 #include "ecmascript/tests/ecma_test_common.h"
26
27 using namespace panda;
28
29 using namespace panda::ecmascript;
30
31 namespace panda::test {
32 class GCTest : public BaseTestWithScope<false> {
33 public:
SetUp()34 void SetUp() override
35 {
36 JSRuntimeOptions options;
37 options.SetEnableEdenGC(true);
38 options.SetArkProperties(options.GetArkProperties() | ArkProperties::ENABLE_HEAP_VERIFY);
39 instance = JSNApi::CreateEcmaVM(options);
40 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
41 thread = instance->GetJSThread();
42 thread->ManagedCodeBegin();
43 scope = new EcmaHandleScope(thread);
44 auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
45 heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::ENABLE);
46 heap->GetSweeper()->EnableConcurrentSweep(EnableConcurrentSweepType::ENABLE);
47 }
48 };
49
HWTEST_F_L0(GCTest,FullGCOne)50 HWTEST_F_L0(GCTest, FullGCOne)
51 {
52 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
53 auto heap = thread->GetEcmaVM()->GetHeap();
54 auto fullGc = heap->GetFullGC();
55 fullGc->RunPhases();
56 auto oldSizebase = heap->GetOldSpace()->GetHeapObjectSize();
57 size_t oldSizeBefore = 0;
58 {
59 [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
60 for (int i = 0; i < 1024; i++) {
61 factory->NewTaggedArray(512, JSTaggedValue::Undefined(), MemSpaceType::OLD_SPACE);
62 }
63 oldSizeBefore = heap->GetOldSpace()->GetHeapObjectSize();
64 EXPECT_TRUE(oldSizeBefore > oldSizebase);
65 }
66 fullGc->RunPhases();
67 auto oldSizeAfter = heap->GetOldSpace()->GetHeapObjectSize();
68 EXPECT_TRUE(oldSizeBefore > oldSizeAfter);
69 }
70
HWTEST_F_L0(GCTest,ChangeGCParams)71 HWTEST_F_L0(GCTest, ChangeGCParams)
72 {
73 auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
74 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::HIGH_THROUGHPUT);
75 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
76 EXPECT_TRUE(heap->GetConcurrentMarker()->IsEnabled());
77 uint32_t markTaskNum = heap->GetMaxMarkTaskCount();
78 #endif
79 EXPECT_TRUE(heap->GetSweeper()->ConcurrentSweepEnabled());
80 uint32_t evacuateTaskNum = heap->GetMaxEvacuateTaskCount();
81
82 auto partialGc = heap->GetPartialGC();
83 partialGc->RunPhases();
84 heap->ChangeGCParams(true);
85 heap->Prepare();
86 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
87 uint32_t markTaskNumBackground = heap->GetMaxMarkTaskCount();
88 EXPECT_TRUE(markTaskNum > markTaskNumBackground);
89 EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
90 #endif
91 uint32_t evacuateTaskNumBackground = heap->GetMaxEvacuateTaskCount();
92 EXPECT_TRUE(evacuateTaskNum > evacuateTaskNumBackground);
93 EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
94 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::CONSERVATIVE);
95
96 partialGc->RunPhases();
97 heap->ChangeGCParams(false);
98 heap->Prepare();
99 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
100 uint32_t markTaskNumForeground = heap->GetMaxMarkTaskCount();
101 EXPECT_EQ(markTaskNum, markTaskNumForeground);
102 EXPECT_TRUE(heap->GetConcurrentMarker()->IsEnabled());
103 #endif
104 uint32_t evacuateTaskNumForeground = heap->GetMaxEvacuateTaskCount();
105 EXPECT_EQ(evacuateTaskNum, evacuateTaskNumForeground);
106 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::HIGH_THROUGHPUT);
107 EXPECT_TRUE(heap->GetSweeper()->ConcurrentSweepEnabled());
108 }
109
HWTEST_F_L0(GCTest,ConfigDisable)110 HWTEST_F_L0(GCTest, ConfigDisable)
111 {
112 auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
113 heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::CONFIG_DISABLE);
114 heap->GetSweeper()->EnableConcurrentSweep(EnableConcurrentSweepType::CONFIG_DISABLE);
115
116 EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
117 EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
118
119 auto partialGc = heap->GetPartialGC();
120 partialGc->RunPhases();
121 heap->ChangeGCParams(false);
122 heap->Prepare();
123
124 EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
125 EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
126 }
127
HWTEST_F_L0(GCTest,NotifyMemoryPressure)128 HWTEST_F_L0(GCTest, NotifyMemoryPressure)
129 {
130 auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
131 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::HIGH_THROUGHPUT);
132 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
133 uint32_t markTaskNum = heap->GetMaxMarkTaskCount();
134 #endif
135 uint32_t evacuateTaskNum = heap->GetMaxEvacuateTaskCount();
136
137 auto partialGc = heap->GetPartialGC();
138 partialGc->RunPhases();
139 heap->ChangeGCParams(true);
140 heap->NotifyMemoryPressure(true);
141 heap->Prepare();
142 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
143 uint32_t markTaskNumBackground = heap->GetMaxMarkTaskCount();
144 EXPECT_TRUE(markTaskNum > markTaskNumBackground);
145 EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
146 #endif
147 uint32_t evacuateTaskNumBackground = heap->GetMaxEvacuateTaskCount();
148 EXPECT_TRUE(evacuateTaskNum > evacuateTaskNumBackground);
149 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::PRESSURE);
150 EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
151
152 partialGc->RunPhases();
153 heap->ChangeGCParams(false);
154 heap->Prepare();
155 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
156 uint32_t markTaskNumForeground = heap->GetMaxMarkTaskCount();
157 EXPECT_EQ(markTaskNum, markTaskNumForeground);
158 #endif
159 uint32_t evacuateTaskNumForeground = heap->GetMaxEvacuateTaskCount();
160 EXPECT_EQ(evacuateTaskNum, evacuateTaskNumForeground);
161 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::PRESSURE);
162
163 heap->NotifyMemoryPressure(false);
164 EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::CONSERVATIVE);
165 }
166
HWTEST_F_L0(GCTest,NativeBindingCheckGCTest)167 HWTEST_F_L0(GCTest, NativeBindingCheckGCTest)
168 {
169 auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
170 heap->CollectGarbage(TriggerGCType::FULL_GC);
171 size_t oldNativeSize = heap->GetNativeBindingSize();
172 EcmaTestCommon::GcCommonCase(thread, heap);
173 heap->CollectGarbage(TriggerGCType::FULL_GC);
174 auto newNativeSize = heap->GetNativeBindingSize();
175 EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
176 }
177
HWTEST_F_L0(GCTest,SharedGC)178 HWTEST_F_L0(GCTest, SharedGC)
179 {
180 #ifdef NDEBUG
181 constexpr size_t ALLOCATE_COUNT = 100;
182 constexpr size_t ALLOCATE_SIZE = 512;
183 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
184 auto sHeap = SharedHeap::GetInstance();
185 sHeap->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::OTHER>(thread);
186 auto oldSizebase = sHeap->GetOldSpace()->GetHeapObjectSize();
187 {
188 [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
189 for (int i = 0; i < ALLOCATE_COUNT; i++) {
190 factory->NewSOldSpaceTaggedArray(ALLOCATE_SIZE, JSTaggedValue::Undefined());
191 }
192 }
193 size_t oldSizeBefore = sHeap->GetOldSpace()->GetHeapObjectSize();
194 EXPECT_TRUE(oldSizeBefore > oldSizebase);
195 sHeap->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::OTHER>(thread);
196 auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize();
197 EXPECT_TRUE(oldSizeBefore > oldSizeAfter);
198 EXPECT_EQ(oldSizebase, oldSizeAfter);
199 #endif
200 }
201
HWTEST_F_L0(GCTest,SharedFullGC)202 HWTEST_F_L0(GCTest, SharedFullGC)
203 {
204 constexpr size_t ALLOCATE_COUNT = 100;
205 constexpr size_t ALLOCATE_SIZE = 512;
206 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
207 auto sHeap = SharedHeap::GetInstance();
208 sHeap->CollectGarbage<TriggerGCType::SHARED_FULL_GC, GCReason::OTHER>(thread);
209 auto oldSizebase = sHeap->GetOldSpace()->GetHeapObjectSize();
210 EXPECT_TRUE(oldSizebase > 0);
211 {
212 [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
213 for (int i = 0; i < ALLOCATE_COUNT; i++) {
214 factory->NewSOldSpaceTaggedArray(ALLOCATE_SIZE, JSTaggedValue::Undefined());
215 }
216 }
217 size_t oldSizeBefore = sHeap->GetOldSpace()->GetHeapObjectSize();
218 EXPECT_TRUE(oldSizeBefore > oldSizebase);
219 EXPECT_TRUE(oldSizeBefore > TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), ALLOCATE_SIZE));
220 sHeap->CollectGarbage<TriggerGCType::SHARED_FULL_GC, GCReason::OTHER>(thread);
221 auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize();
222 EXPECT_TRUE(oldSizeBefore > oldSizeAfter);
223 }
224
HWTEST_F_L0(GCTest,SharedFullGCInAppspawn)225 HWTEST_F_L0(GCTest, SharedFullGCInAppspawn)
226 {
227 constexpr size_t ALLOCATE_COUNT = 10;
228 constexpr size_t ALLOCATE_SIZE = 512;
229 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
230 auto sHeap = SharedHeap::GetInstance();
231 sHeap->CompactHeapBeforeFork(thread);
232 EXPECT_TRUE(sHeap->GetOldSpace()->GetHeapObjectSize() == 0);
233 auto oldSizebase = sHeap->GetOldSpace()->GetHeapObjectSize();
234 {
235 [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
236 for (int i = 0; i < ALLOCATE_COUNT; i++) {
237 factory->NewSOldSpaceTaggedArray(ALLOCATE_SIZE, JSTaggedValue::Undefined());
238 }
239 }
240 size_t oldSizeBefore = sHeap->GetOldSpace()->GetHeapObjectSize();
241 EXPECT_TRUE(oldSizeBefore > oldSizebase);
242 sHeap->CollectGarbage<TriggerGCType::SHARED_FULL_GC, GCReason::OTHER>(thread);
243 sHeap->GetAppSpawnSpace()->IterateOverMarkedObjects([](TaggedObject *object) {
244 Region *objectRegion = Region::ObjectAddressToRange(object);
245 EXPECT_TRUE(objectRegion->InSharedAppSpawnSpace());
246 });
247 auto oldSizeAfter = sHeap->GetOldSpace()->GetHeapObjectSize();
248 EXPECT_TRUE(oldSizeBefore > oldSizeAfter);
249 EXPECT_EQ(oldSizebase, oldSizeAfter);
250 }
251
HWTEST_F_L0(GCTest,SharedGCSuspendAll)252 HWTEST_F_L0(GCTest, SharedGCSuspendAll)
253 {
254 EXPECT_TRUE(thread->IsInRunningState());
255 {
256 SuspendAllScope suspendScope(thread);
257 EXPECT_TRUE(!thread->IsInRunningState());
258 }
259 EXPECT_TRUE(thread->IsInRunningState());
260 }
261
HWTEST_F_L0(GCTest,SerializeGCCheck)262 HWTEST_F_L0(GCTest, SerializeGCCheck)
263 {
264 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
265 uint32_t index = 0;
266 {
267 [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
268 JSHandle<EcmaString> key1(factory->NewFromASCII("error1"));
269 JSHandle<EcmaString> key2(factory->NewFromASCII("error2"));
270 JSHandle<EcmaString> msg(factory->NewFromASCII("this is error"));
271 auto chunk = std::make_unique<SerializationChunk>();
272 chunk->Emplace(reinterpret_cast<JSTaggedType>(key1.GetTaggedValue().GetTaggedObject()));
273 chunk->Emplace(reinterpret_cast<JSTaggedType>(key2.GetTaggedValue().GetTaggedObject()));
274 chunk->Emplace(reinterpret_cast<JSTaggedType>(msg.GetTaggedValue().GetTaggedObject()));
275 EXPECT_EQ(chunk->Size(), 3); // 3: three elements
276 index = Runtime::GetInstance()->PushSerializationRoot(thread, std::move(chunk));
277 }
278 auto sHeap = SharedHeap::GetInstance();
279 sHeap->CollectGarbage<TriggerGCType::SHARED_FULL_GC, GCReason::OTHER>(thread);
280 Runtime::GetInstance()->RemoveSerializationRoot(thread, index);
281 };
282
HWTEST_F_L0(GCTest,StatisticHeapDetailTest)283 HWTEST_F_L0(GCTest, StatisticHeapDetailTest)
284 {
285 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
286 auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
287 {
288 [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
289 for (int i = 0; i < 1024; i++) {
290 factory->NewTaggedArray(128, JSTaggedValue::Undefined(), MemSpaceType::NON_MOVABLE);
291 }
292 for (int i = 0; i < 1024; i++) {
293 factory->NewTaggedArray(128, JSTaggedValue::Undefined(), MemSpaceType::OLD_SPACE);
294 }
295 for (int i = 0; i < 1024; i++) {
296 factory->NewTaggedArray(128, JSTaggedValue::Undefined(), MemSpaceType::SEMI_SPACE);
297 }
298 }
299 heap->StatisticHeapDetail();
300 };
301
302 } // namespace panda::test
303