1 /*
2 * Copyright (c) 2025 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/tests/ecma_test_common.h"
17
18 using namespace panda;
19
20 using namespace panda::ecmascript;
21
22 namespace panda::test {
23 class SharedTestSpace;
24 class SharedPartialGCTest : public BaseTestWithScope<false> {
25 public:
26 JSHandle<TaggedObject> CreateSharedObjectsInOneRegion(std::shared_ptr<SharedTestSpace> space, double aliveRate);
27 void InitTaggedArray(TaggedObject *obj, size_t arrayLen);
28 void CreateTaggedArray();
29 };
30
31 class SharedTestSpace : public Space {
32 public:
33 static constexpr size_t CAP = 10 * 1024 * 1024;
SharedTestSpace(SharedHeap * heap)34 explicit SharedTestSpace(SharedHeap *heap)
35 : Space(heap, heap->GetHeapRegionAllocator(), MemSpaceType::SHARED_OLD_SPACE, CAP, CAP), sHeap_(heap) {}
36 ~SharedTestSpace() override = default;
37 NO_COPY_SEMANTIC(SharedTestSpace);
38 NO_MOVE_SEMANTIC(SharedTestSpace);
39
Expand(JSThread * thread)40 void Expand(JSThread *thread)
41 {
42 Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, sHeap_);
43 FillBumpPointer();
44 allocator_.Reset(region->GetBegin(), region->GetEnd());
45 }
46
Allocate(size_t size)47 uintptr_t Allocate(size_t size)
48 {
49 return allocator_.Allocate(size);
50 }
51
GetTop()52 uintptr_t GetTop()
53 {
54 return allocator_.GetTop();
55 }
56
FillBumpPointer()57 void FillBumpPointer()
58 {
59 auto begin = allocator_.GetTop();
60 auto size = allocator_.Available();
61 FreeObject::FillFreeObject(sHeap_, begin, size);
62 }
63
GetEnd()64 uintptr_t GetEnd()
65 {
66 return allocator_.GetEnd();
67 }
68 private:
69 SharedHeap *sHeap_ {nullptr};
70 BumpPointerAllocator allocator_;
71 };
72
InitTaggedArray(TaggedObject * obj,size_t arrayLen)73 void SharedPartialGCTest::InitTaggedArray(TaggedObject *obj, size_t arrayLen)
74 {
75 JSHClass *arrayClass = JSHClass::Cast(thread->GlobalConstants()->GetArrayClass().GetTaggedObject());
76 obj->SynchronizedSetClass(thread, arrayClass);
77 TaggedArray::Cast(obj)->InitializeWithSpecialValue(JSTaggedValue::Undefined(), arrayLen);
78 }
79
CreateSharedObjectsInOneRegion(std::shared_ptr<SharedTestSpace> space,double aliveRate)80 JSHandle<TaggedObject> SharedPartialGCTest::CreateSharedObjectsInOneRegion(std::shared_ptr<SharedTestSpace> space,
81 double aliveRate)
82 {
83 constexpr size_t TAGGED_TYPE_SIZE = 8;
84 space->Expand(thread);
85 size_t totalSize = space->GetEnd() - space->GetTop();
86 size_t alive = totalSize * aliveRate;
87 size_t arrayLen = alive / TAGGED_TYPE_SIZE;
88 size_t size = TaggedArray::ComputeSize(TAGGED_TYPE_SIZE, arrayLen);
89 TaggedObject *obj = reinterpret_cast<TaggedObject *>(space->Allocate(size));
90 EXPECT_TRUE(obj != nullptr);
91 InitTaggedArray(obj, arrayLen);
92 return JSHandle<TaggedObject>(thread, obj);
93 }
94
HWTEST_F_L0(SharedPartialGCTest,PartialGCTest)95 HWTEST_F_L0(SharedPartialGCTest, PartialGCTest)
96 {
97 constexpr double ALIVE_RATE = 0.1;
98 constexpr size_t ARRAY_SIZE = SharedOldSpace::MIN_COLLECT_REGION_SIZE;
99 instance->GetJSOptions().SetEnableForceGC(false);
100 Heap *heap = const_cast<Heap *>(instance->GetHeap());
101 SharedHeap *sHeap = SharedHeap::GetInstance();
102 ObjectFactory *factory = heap->GetEcmaVM()->GetFactory();
103 JSHandle<TaggedArray> localObj = factory->NewTaggedArray(ARRAY_SIZE, JSTaggedValue::Undefined(), false);
104 heap->CollectGarbage(TriggerGCType::FULL_GC);
105 sHeap->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::OTHER>(thread);
106 heap->GetHeapPrepare();
107 SharedOldSpace *sOldSpace = sHeap->GetOldSpace();
108 std::shared_ptr<SharedTestSpace> space= std::make_shared<SharedTestSpace>(sHeap);
109 std::vector<std::pair<Region*, JSHandle<TaggedObject>>> checkObjList;
110 for (size_t i = 0; i < SharedOldSpace::MIN_COLLECT_REGION_SIZE; i++) {
111 auto obj = CreateSharedObjectsInOneRegion(space, ALIVE_RATE);
112 Region *region = Region::ObjectAddressToRange(*obj);
113 checkObjList.emplace_back(region, obj);
114 sOldSpace->AddRegion(region);
115 }
116 space->FillBumpPointer();
117 EXPECT_TRUE(sHeap->CheckCanTriggerConcurrentMarking(thread));
118 sHeap->TriggerConcurrentMarking<TriggerGCType::SHARED_PARTIAL_GC, GCReason::OTHER>(thread);
119 while (!thread->HasSuspendRequest());
120 thread->CheckSafepointIfSuspended();
121 if (thread->IsSharedConcurrentMarkingOrFinished()) {
122 EXPECT_TRUE(sOldSpace->GetCollectSetRegionCount() > 0);
123 Region *localRegion = Region::ObjectAddressToRange(*localObj);
124 for (uint32_t i = 0; i < SharedOldSpace::MIN_COLLECT_REGION_SIZE; i++) {
125 auto each = checkObjList[i];
126 Region *checkRegion = each.first;
127 JSHandle<TaggedObject> checkObj = each.second;
128 EXPECT_TRUE(checkRegion->InSCollectSet());
129 localObj->Set(thread, i, checkObj);
130 JSTaggedType *localSlot = localObj->GetData() + i;
131 EXPECT_TRUE(localRegion->TestLocalToShare(reinterpret_cast<uintptr_t>(localSlot)));
132 }
133 }
134 sHeap->WaitGCFinished(thread);
135 }
136 } // namespace panda::test