• 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-inl.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/ecma_test_common.h"
24 #include "ecmascript/napi/include/jsnapi_expo.h"
25 
26 using namespace panda;
27 
28 using namespace panda::ecmascript;
29 using TRIGGER_IDLE_GC_TYPE = panda::JSNApi::TRIGGER_IDLE_GC_TYPE;
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,NativeGCTestConcurrentMarkDisabled)50 HWTEST_F_L0(GCTest, NativeGCTestConcurrentMarkDisabled)
51 {
52     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
53     // Disable concurrent mark.
54     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
55     size_t oldNativeSize = heap->GetNativeBindingSize();
56     EcmaTestCommon::GcCommonCase(thread, heap, false);
57     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::OLD_GC);
58     auto newNativeSize = heap->GetNativeBindingSize();
59     EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
60 }
61 
HWTEST_F_L0(GCTest,NonNewSpaceNativeGCTestConcurrentMarkDisabled)62 HWTEST_F_L0(GCTest, NonNewSpaceNativeGCTestConcurrentMarkDisabled)
63 {
64     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
65     // Disable concurrent mark.
66     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
67     size_t oldNativeSize = heap->GetNativeBindingSize();
68     EcmaTestCommon::GcCommonCase(thread, heap);
69     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::OLD_GC);
70     auto newNativeSize = heap->GetNativeBindingSize();
71     EXPECT_EQ(newNativeSize - oldNativeSize, 0UL);
72 }
73 
HWTEST_F_L0(GCTest,ArkToolsForceFullGC)74 HWTEST_F_L0(GCTest, ArkToolsForceFullGC)
75 {
76     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->CollectGarbage(TriggerGCType::FULL_GC);
77     size_t originalHeapSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
78     size_t newSize = originalHeapSize;
79     {
80         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
81 
82         for (int i = 0; i < 10; i++) {
83             [[maybe_unused]] JSHandle<TaggedArray> obj = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(1024 * 1024);
84         }
85         newSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
86     }
87     EXPECT_TRUE(newSize > originalHeapSize);
88     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 0);
89 
90     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
91     [[maybe_unused]] JSTaggedValue result1 = builtins::BuiltinsArkTools::ForceFullGC(ecmaRuntimeCallInfo);
92 
93     ASSERT_TRUE(thread->GetEcmaVM()->GetHeap()->GetCommittedSize() < newSize);
94 }
95 
HWTEST_F_L0(GCTest,ColdStartForceExpand)96 HWTEST_F_L0(GCTest, ColdStartForceExpand)
97 {
98     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
99     size_t originalHeapSize = heap->GetCommittedSize();
100     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
101     heap->NotifyPostFork();
102     heap->NotifyFinishColdStartSoon();
103     {
104         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
105         for (int i = 0; i < 500; i++) {
106             [[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
107                 10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
108         }
109     }
110     size_t expandHeapSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
111     usleep(2500000);
112     size_t newSize = EcmaTestCommon::GcCommonCase(thread);
113     EXPECT_TRUE(originalHeapSize < expandHeapSize);
114     EXPECT_TRUE(expandHeapSize > newSize);
115 }
116 
HWTEST_F_L0(GCTest,HighSensitiveForceExpand)117 HWTEST_F_L0(GCTest, HighSensitiveForceExpand)
118 {
119     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
120     size_t originalHeapSize = heap->GetCommittedSize();
121     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
122     heap->NotifyHighSensitive(true);
123     {
124         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
125         for (int i = 0; i < 500; i++) {
126             [[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
127                 10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
128         }
129     }
130     size_t expandHeapSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
131     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->NotifyHighSensitive(false);
132     size_t newSize = EcmaTestCommon::GcCommonCase(thread);
133     EXPECT_TRUE(originalHeapSize < expandHeapSize);
134     EXPECT_TRUE(expandHeapSize > newSize);
135 }
136 
HWTEST_F_L0(GCTest,HighSensitiveExceedMaxHeapSize)137 HWTEST_F_L0(GCTest, HighSensitiveExceedMaxHeapSize)
138 {
139     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
140     heap->NotifyHighSensitive(true);
141     // First allocate about 250M TaggedArray, not reach max heap size
142     {
143         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
144         for (int i = 0; i < 16 * 1000; i++) {
145             [[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
146                 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
147         }
148     }
149     // Continue allocate about 250M TaggedArray, now reach max heap size, must trigger gc to avoid OOM
150     {
151         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
152         for (int i = 0; i < 10 * 1000; i++) {
153             [[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
154                 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
155         }
156     }
157     size_t commitSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
158     const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->NotifyHighSensitive(false);
159     EXPECT_TRUE(commitSize < thread->GetEcmaVM()->GetEcmaParamConfiguration().GetMaxHeapSize());
160 }
161 
HWTEST_F_L0(GCTest,CallbackTask)162 HWTEST_F_L0(GCTest, CallbackTask)
163 {
164     auto vm = thread->GetEcmaVM();
165     Heap *heap = const_cast<Heap *>(vm->GetHeap());
166     auto factory = vm->GetFactory();
167     {
168         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
169 
170         for (int i = 0; i < 10; i++) {
171             // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
172             void *externalPointer = malloc(10);
173             [[maybe_unused]] JSHandle<JSNativePointer> nativePointer = factory->NewJSNativePointer(
174                 externalPointer, []([[maybe_unused]] void *env, void* pointer, [[maybe_unused]] void* data) {
175                 if (pointer != nullptr) {
176                     free(pointer);
177                 }
178             },
179             nullptr, false, 10, Concurrent::YES);
180         }
181     }
182     size_t number = heap->concurrentNativePointerList_.size();
183     EXPECT_TRUE(number > 0);
184     heap->CollectGarbage(TriggerGCType::OLD_GC);
185     size_t newNumber = heap->concurrentNativePointerList_.size();
186     EXPECT_TRUE(number > newNumber);
187 }
188 
HWTEST_F_L0(GCTest,RecomputeLimitsTest)189 HWTEST_F_L0(GCTest, RecomputeLimitsTest)
190 {
191     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
192     auto oldCapacity = heap->GetOldSpace()->GetInitialCapacity();
193     heap->CollectGarbage(TriggerGCType::FULL_GC);
194     EXPECT_FALSE(heap->IsConcurrentFullMark());
195     EXPECT_FALSE(heap->IsFullMarkRequested());
196     auto newCapacity = heap->GetOldSpace()->GetInitialCapacity();
197     EXPECT_NE(newCapacity, oldCapacity);
198     double gcSpeed = heap->GetMemController()->CalculateMarkCompactSpeedPerMS();
199     double mutatorSpeed = heap->GetMemController()->GetCurrentOldSpaceAllocationThroughputPerMS();
200     size_t oldSpaceSize = heap->GetOldSpace()->GetHeapObjectSize() + heap->GetHugeObjectSpace()->GetHeapObjectSize() +
201         heap->GetHugeMachineCodeSpace()->GetHeapObjectSize();
202     size_t newSpaceCapacity = heap->GetNewSpace()->GetInitialCapacity();
203     double growingFactor =  heap->GetMemController()->CalculateGrowingFactor(gcSpeed, mutatorSpeed);
204     size_t maxOldSpaceCapacity = heap->GetOldSpace()->GetMaximumCapacity() - newSpaceCapacity;
205     auto newOldSpaceLimit = heap->GetMemController()->CalculateAllocLimit(oldSpaceSize, MIN_OLD_SPACE_LIMIT,
206         maxOldSpaceCapacity, newSpaceCapacity, growingFactor);
207     EXPECT_EQ(newCapacity, newOldSpaceLimit);
208 }
209 
HWTEST_F_L0(GCTest,GlobalNativeSizeLargerThanLimitTest)210 HWTEST_F_L0(GCTest, GlobalNativeSizeLargerThanLimitTest)
211 {
212     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
213     auto ret = heap->GlobalNativeSizeLargerThanLimit();
214     EXPECT_FALSE(ret);
215     heap->GetNativeAreaAllocator()->IncreaseNativeMemoryUsage(300*1000*1000);
216     ret = heap->GlobalNativeSizeLargerThanLimit();
217     EXPECT_TRUE(ret);
218 }
219 #ifdef NDEBUG
HWTEST_F_L0(GCTest,IdleGCTriggerTest)220 HWTEST_F_L0(GCTest, IdleGCTriggerTest)
221 {
222     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
223     auto idleGCTrigger = heap->GetIdleGCTrigger();
224     auto sHeap = SharedHeap::GetInstance();
225     heap->CollectGarbage(TriggerGCType::FULL_GC);
226     int baseLocalGCCount = heap->GetEcmaGCStats()->GetGCCount();
227     int baseSharedGCCount = sHeap->GetEcmaGCStats()->GetGCCount();
228     heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
229     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
230     // Apply for some memory that cannot be released to simulate the actual situation
231     for (int i = 0; i < 5120; i++) {
232         factory->NewTaggedArray(1024, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
233         factory->NewSOldSpaceTaggedArray(1024, JSTaggedValue::Hole());
234     }
235     for (size_t i = 0; i < 10240; i++)
236     {
237         factory->NewTaggedArray(512, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
238         factory->NewSOldSpaceTaggedArray(512, JSTaggedValue::Hole());
239         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
240         [[maybe_unused]] JSHandle<TaggedArray> array = factory->NewTaggedArray(1024, JSTaggedValue::Hole(),
241                     MemSpaceType::OLD_SPACE);
242         [[maybe_unused]] JSHandle<TaggedArray> sArray = factory->NewSOldSpaceTaggedArray(1024,
243                     JSTaggedValue::Hole());
244         if (i%340 == 0) {
245             idleGCTrigger->NotifyVsyncIdleStart();
246         }
247     }
248     idleGCTrigger->TryTriggerIdleGC(TRIGGER_IDLE_GC_TYPE::FULL_GC);
249     idleGCTrigger->TryTriggerIdleGC(TRIGGER_IDLE_GC_TYPE::SHARED_FULL_GC);
250     int afterLocalGCCount = heap->GetEcmaGCStats()->GetGCCount();
251     int afterSharedGCCount = sHeap->GetEcmaGCStats()->GetGCCount();
252     EXPECT_TRUE(afterLocalGCCount - baseLocalGCCount < 10);
253     EXPECT_TRUE(afterSharedGCCount - baseSharedGCCount < 10);
254     heap->CollectGarbage(TriggerGCType::FULL_GC);
255 }
256 #endif  // #ifndef NDEBUG
257 
HWTEST_F_L0(GCTest,AdjustCapacity)258 HWTEST_F_L0(GCTest, AdjustCapacity)
259 {
260 #if defined(PANDA_TARGET_ARM64)
261     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
262     SemiSpace * space = heap->GetNewSpace();
263 
264     EXPECT_EQ(space->GetSurvivalObjectSize(), 0);
265     {
266         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
267         for (int i = 0; i < 300; i++) {
268             [[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
269                 10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
270         }
271     }
272     EXPECT_GT(space->GetSurvivalObjectSize(), 0);
273 
274     EXPECT_FALSE(space->AdjustCapacity(0, thread));
275     size_t size = space->GetInitialCapacity() * GROW_OBJECT_SURVIVAL_RATE / 2;
276     EXPECT_FALSE(space->AdjustCapacity(size, thread));
277 
278     space->SetInitialCapacity(space->GetSurvivalObjectSize() / GROW_OBJECT_SURVIVAL_RATE - 1);
279     size = space->GetSurvivalObjectSize() / GROW_OBJECT_SURVIVAL_RATE - 1;
280     size_t oldMaxCapacity = space->GetMaximumCapacity();
281     space->SetMaximumCapacity(space->GetInitialCapacity());
282     EXPECT_TRUE(space->AdjustCapacity(size, thread));
283     space->SetMaximumCapacity(oldMaxCapacity);
284     EXPECT_TRUE(space->AdjustCapacity(size, thread));
285 #endif
286 }
287 
HWTEST_F_L0(GCTest,NativeMemAllocInSensitive)288 HWTEST_F_L0(GCTest, NativeMemAllocInSensitive)
289 {
290     auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
291     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
292     heap->NotifyHighSensitive(true);
293     for (size_t i = 0; i < 20; i++) {
294         [[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
295         factory->NewJSArrayBuffer(300 * 1024 * 1024); // 300MB
296     }
297     EXPECT_TRUE(heap->GetGlobalNativeSize() < 1 * 1024 * 1024* 1024); // 1GB
298 }
299 } // namespace panda::test
300