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