• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ecma_vm.h"
18 #include "ecmascript/mem/full_gc.h"
19 #include "ecmascript/object_factory.h"
20 #include "ecmascript/mem/concurrent_marker.h"
21 #include "ecmascript/mem/stw_young_gc.h"
22 #include "ecmascript/mem/partial_gc.h"
23 #include "ecmascript/tests/test_helper.h"
24 
25 using namespace panda;
26 
27 using namespace panda::ecmascript;
28 
29 namespace panda::test {
30 class GCTest : public testing::Test {
31 public:
SetUpTestCase()32     static void SetUpTestCase()
33     {
34         GTEST_LOG_(INFO) << "SetUpTestCase";
35     }
36 
TearDownTestCase()37     static void TearDownTestCase()
38     {
39         GTEST_LOG_(INFO) << "TearDownCase";
40     }
41 
SetUp()42     void SetUp() override
43     {
44         JSRuntimeOptions options;
45         instance = JSNApi::CreateEcmaVM(options);
46         ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
47         thread = instance->GetJSThread();
48         scope = new EcmaHandleScope(thread);
49         auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
50         heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::ENABLE);
51         heap->GetSweeper()->EnableConcurrentSweep(EnableConcurrentSweepType::ENABLE);
52     }
53 
TearDown()54     void TearDown() override
55     {
56         TestHelper::DestroyEcmaVMWithScope(instance, scope);
57     }
58 
59     EcmaVM *instance {nullptr};
60     ecmascript::EcmaHandleScope *scope {nullptr};
61     JSThread *thread {nullptr};
62 };
63 
HWTEST_F_L0(GCTest,FullGCOne)64 HWTEST_F_L0(GCTest, FullGCOne)
65 {
66     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
67     auto heap = thread->GetEcmaVM()->GetHeap();
68     auto fullGc = heap->GetFullGC();
69     fullGc->RunPhases();
70     auto oldSizebase = heap->GetOldSpace()->GetHeapObjectSize();
71     size_t oldSizeBefore = 0;
72     {
73         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
74         for (int i = 0; i < 1024; i++) {
75             factory->NewTaggedArray(512, JSTaggedValue::Undefined(), MemSpaceType::OLD_SPACE);
76         }
77         oldSizeBefore = heap->GetOldSpace()->GetHeapObjectSize();
78         EXPECT_TRUE(oldSizeBefore > oldSizebase);
79     }
80     fullGc->RunPhases();
81     auto oldSizeAfter = heap->GetOldSpace()->GetHeapObjectSize();
82     EXPECT_TRUE(oldSizeBefore > oldSizeAfter);
83 }
84 
HWTEST_F_L0(GCTest,ChangeGCParams)85 HWTEST_F_L0(GCTest, ChangeGCParams)
86 {
87     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
88     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::HIGH_THROUGHPUT);
89 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
90     EXPECT_TRUE(heap->GetConcurrentMarker()->IsEnabled());
91     uint32_t markTaskNum = heap->GetMaxMarkTaskCount();
92 #endif
93     EXPECT_TRUE(heap->GetSweeper()->ConcurrentSweepEnabled());
94     uint32_t evacuateTaskNum = heap->GetMaxEvacuateTaskCount();
95 
96     auto partialGc = heap->GetPartialGC();
97     partialGc->RunPhases();
98     heap->ChangeGCParams(true);
99     heap->Prepare();
100 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
101     uint32_t markTaskNumBackground = heap->GetMaxMarkTaskCount();
102     EXPECT_TRUE(markTaskNum > markTaskNumBackground);
103     EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
104 #endif
105     uint32_t evacuateTaskNumBackground = heap->GetMaxEvacuateTaskCount();
106     EXPECT_TRUE(evacuateTaskNum > evacuateTaskNumBackground);
107     EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
108     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::CONSERVATIVE);
109 
110     partialGc->RunPhases();
111     heap->ChangeGCParams(false);
112     heap->Prepare();
113 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
114     uint32_t markTaskNumForeground = heap->GetMaxMarkTaskCount();
115     EXPECT_EQ(markTaskNum, markTaskNumForeground);
116     EXPECT_TRUE(heap->GetConcurrentMarker()->IsEnabled());
117 #endif
118     uint32_t evacuateTaskNumForeground = heap->GetMaxEvacuateTaskCount();
119     EXPECT_EQ(evacuateTaskNum, evacuateTaskNumForeground);
120     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::HIGH_THROUGHPUT);
121     EXPECT_TRUE(heap->GetSweeper()->ConcurrentSweepEnabled());
122 }
123 
HWTEST_F_L0(GCTest,ConfigDisable)124 HWTEST_F_L0(GCTest, ConfigDisable)
125 {
126     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
127     heap->GetConcurrentMarker()->EnableConcurrentMarking(EnableConcurrentMarkType::CONFIG_DISABLE);
128     heap->GetSweeper()->EnableConcurrentSweep(EnableConcurrentSweepType::CONFIG_DISABLE);
129 
130     EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
131     EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
132 
133     auto partialGc = heap->GetPartialGC();
134     partialGc->RunPhases();
135     heap->ChangeGCParams(false);
136     heap->Prepare();
137 
138     EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
139     EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
140 }
141 
HWTEST_F_L0(GCTest,NotifyMemoryPressure)142 HWTEST_F_L0(GCTest, NotifyMemoryPressure)
143 {
144     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
145     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::HIGH_THROUGHPUT);
146 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
147     uint32_t markTaskNum = heap->GetMaxMarkTaskCount();
148 #endif
149     uint32_t evacuateTaskNum = heap->GetMaxEvacuateTaskCount();
150 
151     auto partialGc = heap->GetPartialGC();
152     partialGc->RunPhases();
153     heap->ChangeGCParams(true);
154     heap->NotifyMemoryPressure(true);
155     heap->Prepare();
156 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
157     uint32_t markTaskNumBackground = heap->GetMaxMarkTaskCount();
158     EXPECT_TRUE(markTaskNum > markTaskNumBackground);
159     EXPECT_FALSE(heap->GetConcurrentMarker()->IsEnabled());
160 #endif
161     uint32_t evacuateTaskNumBackground = heap->GetMaxEvacuateTaskCount();
162     EXPECT_TRUE(evacuateTaskNum > evacuateTaskNumBackground);
163     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::PRESSURE);
164     EXPECT_FALSE(heap->GetSweeper()->ConcurrentSweepEnabled());
165 
166     partialGc->RunPhases();
167     heap->ChangeGCParams(false);
168     heap->Prepare();
169 #if !ECMASCRIPT_DISABLE_CONCURRENT_MARKING
170     uint32_t markTaskNumForeground = heap->GetMaxMarkTaskCount();
171     EXPECT_EQ(markTaskNum, markTaskNumForeground);
172 #endif
173     uint32_t evacuateTaskNumForeground = heap->GetMaxEvacuateTaskCount();
174     EXPECT_EQ(evacuateTaskNum, evacuateTaskNumForeground);
175     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::PRESSURE);
176 
177     heap->NotifyMemoryPressure(false);
178     EXPECT_EQ(heap->GetMemGrowingType(), MemGrowingType::CONSERVATIVE);
179 }
180 
HWTEST_F_L0(GCTest,NativeBindingCheckGCTest)181 HWTEST_F_L0(GCTest, NativeBindingCheckGCTest)
182 {
183     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
184     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
185     size_t oldNativeSize = heap->GetNativeBindingSize();
186     size_t newNativeSize = heap->GetNativeBindingSize();
187     {
188         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
189 
190         auto newData = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
191         [[maybe_unused]] JSHandle<JSNativePointer> obj = factory->NewJSNativePointer(newData,
192             NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
193         newNativeSize = heap->GetNativeBindingSize();
194         EXPECT_EQ(newNativeSize - oldNativeSize, 1UL * 1024 * 1024);
195 
196         auto newData1 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
197         [[maybe_unused]] JSHandle<JSNativePointer> obj2 = factory->NewJSNativePointer(newData1,
198             NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
199 
200         EXPECT_TRUE(newNativeSize - oldNativeSize > 0);
201         EXPECT_TRUE(newNativeSize - oldNativeSize <= 2 * 1024 *1024);
202         for (int i = 0; i < 20; i++) {
203             auto newData2 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
204             [[maybe_unused]] JSHandle<JSNativePointer> obj3 = factory->NewJSNativePointer(newData2,
205                 NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
206         }
207         // Young GC should be trigger here, so the size should be reduced.
208         EXPECT_TRUE(newNativeSize - oldNativeSize < 22 * 1024 *1024);
209     }
210     auto partialGc = heap->GetPartialGC();
211     heap->SetMarkType(MarkType::MARK_FULL);
212     partialGc->RunPhases();
213     newNativeSize = heap->GetNativeBindingSize();
214     EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
215 }
216 
HWTEST_F_L0(GCTest,NonNewSpaceNativeBindingCheckGCTest)217 HWTEST_F_L0(GCTest, NonNewSpaceNativeBindingCheckGCTest)
218 {
219     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
220     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
221     size_t oldNativeSize = heap->GetNonNewSpaceNativeBindingSize();
222     size_t newNativeSize = heap->GetNonNewSpaceNativeBindingSize();
223     {
224         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
225         auto newData = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
226         [[maybe_unused]] JSHandle<JSNativePointer> obj = factory->NewJSNativePointer(newData,
227             NativeAreaAllocator::FreeBufferFunc, nullptr, true, 1 * 1024 * 1024);
228         newNativeSize = heap->GetNonNewSpaceNativeBindingSize();
229         EXPECT_EQ(newNativeSize - oldNativeSize, 1UL * 1024 * 1024);
230 
231         auto newData1 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
232         [[maybe_unused]] JSHandle<JSNativePointer> obj2 = factory->NewJSNativePointer(newData1,
233             NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
234 
235         EXPECT_TRUE(newNativeSize - oldNativeSize > 0);
236         EXPECT_TRUE(newNativeSize - oldNativeSize <= 2 * 1024 *1024);
237         for (int i = 0; i < 300; i++) {
238             auto newData2 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1024);
239             // malloc size is smaller to avoid test fail in the small devices.
240             [[maybe_unused]] JSHandle<JSNativePointer> obj3 = factory->NewJSNativePointer(newData2,
241                 NativeAreaAllocator::FreeBufferFunc, nullptr, true, 1 * 1024 * 1024);
242         }
243         // Old GC should be trigger here, so the size should be reduced.
244         EXPECT_TRUE(newNativeSize - oldNativeSize < 256 * 1024 *1024);
245     }
246     auto partialGc = heap->GetPartialGC();
247     heap->SetMarkType(MarkType::MARK_FULL);
248     partialGc->RunPhases();
249     newNativeSize = heap->GetNonNewSpaceNativeBindingSize();
250     EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
251 }
252 
HWTEST_F_L0(GCTest,NativeGCTestConcurrentMarkDisabled)253 HWTEST_F_L0(GCTest, NativeGCTestConcurrentMarkDisabled)
254 {
255     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
256     // Disable concurrent mark.
257     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
258     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
259     size_t oldNativeSize = heap->GetNativeBindingSize();
260     size_t newNativeSize = heap->GetNativeBindingSize();
261     {
262         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
263 
264         auto newData = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
265         [[maybe_unused]] JSHandle<JSNativePointer> obj = factory->NewJSNativePointer(newData,
266             NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
267         newNativeSize = heap->GetNativeBindingSize();
268         EXPECT_EQ(newNativeSize - oldNativeSize, 1UL * 1024 * 1024);
269 
270         auto newData1 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
271         [[maybe_unused]] JSHandle<JSNativePointer> obj2 = factory->NewJSNativePointer(newData1,
272             NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
273 
274         EXPECT_TRUE(newNativeSize - oldNativeSize > 0);
275         EXPECT_TRUE(newNativeSize - oldNativeSize <= 2 * 1024 *1024);
276         for (int i = 0; i < 20; i++) {
277             auto newData2 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
278             [[maybe_unused]] JSHandle<JSNativePointer> obj3 = factory->NewJSNativePointer(newData2,
279                 NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
280         }
281         // Young GC should be trigger here, so the size should be reduced.
282         EXPECT_TRUE(newNativeSize - oldNativeSize < 22 * 1024 *1024);
283     }
284     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::OLD_GC);
285     newNativeSize = heap->GetNativeBindingSize();
286     EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
287 }
288 
HWTEST_F_L0(GCTest,NonNewSpaceNativeGCTestConcurrentMarkDisabled)289 HWTEST_F_L0(GCTest, NonNewSpaceNativeGCTestConcurrentMarkDisabled)
290 {
291     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
292     // Disable concurrent mark.
293     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
294     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
295     size_t oldNativeSize = heap->GetNonNewSpaceNativeBindingSize();
296     size_t newNativeSize = heap->GetNonNewSpaceNativeBindingSize();
297     {
298         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
299         auto newData = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
300         [[maybe_unused]] JSHandle<JSNativePointer> obj = factory->NewJSNativePointer(newData,
301             NativeAreaAllocator::FreeBufferFunc, nullptr, true, 1 * 1024 * 1024);
302         newNativeSize = heap->GetNonNewSpaceNativeBindingSize();
303         EXPECT_EQ(newNativeSize - oldNativeSize, 1UL * 1024 * 1024);
304 
305         auto newData1 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1 * 1024 * 1024);
306         [[maybe_unused]] JSHandle<JSNativePointer> obj2 = factory->NewJSNativePointer(newData1,
307             NativeAreaAllocator::FreeBufferFunc, nullptr, false, 1 * 1024 * 1024);
308 
309         EXPECT_TRUE(newNativeSize - oldNativeSize > 0);
310         EXPECT_TRUE(newNativeSize - oldNativeSize <= 2 * 1024 *1024);
311         for (int i = 0; i < 300; i++) {
312             auto newData2 = thread->GetEcmaVM()->GetNativeAreaAllocator()->AllocateBuffer(1024);
313             // malloc size is smaller to avoid test fail in the small devices.
314             [[maybe_unused]] JSHandle<JSNativePointer> obj3 = factory->NewJSNativePointer(newData2,
315                 NativeAreaAllocator::FreeBufferFunc, nullptr, true, 1 * 1024 * 1024);
316         }
317         // Old GC should be trigger here, so the size should be reduced.
318         EXPECT_TRUE(newNativeSize - oldNativeSize < 256 * 1024 *1024);
319     }
320     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::OLD_GC);
321     newNativeSize = heap->GetNonNewSpaceNativeBindingSize();
322     EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
323 }
324 
HWTEST_F_L0(GCTest,ArkToolsForceFullGC)325 HWTEST_F_L0(GCTest, ArkToolsForceFullGC)
326 {
327     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::FULL_GC);
328     size_t originalHeapSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
329     size_t newSize = originalHeapSize;
330     {
331         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
332 
333         for (int i = 0; i < 10; i++) {
334             [[maybe_unused]] JSHandle<TaggedArray> obj = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(1024 * 1024);
335         }
336         newSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
337     }
338     EXPECT_TRUE(newSize > originalHeapSize);
339     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 0);
340 
341     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
342     [[maybe_unused]] JSTaggedValue result1 = builtins::BuiltinsArkTools::ForceFullGC(ecmaRuntimeCallInfo);
343 
344     ASSERT_TRUE(thread->GetEcmaVM()->GetHeap()->GetCommittedSize() < newSize);
345 }
346 
347 }  // namespace panda::test
348