/* * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/tests/ecma_test_common.h" using namespace panda; using namespace panda::ecmascript; namespace panda::test { class SharedTestSpace; class SharedPartialGCTest : public BaseTestWithScope<false> { public: JSHandle<TaggedObject> CreateSharedObjectsInOneRegion(std::shared_ptr<SharedTestSpace> space, double aliveRate); void InitTaggedArray(TaggedObject *obj, size_t arrayLen); void CreateTaggedArray(); }; class SharedTestSpace : public Space { public: static constexpr size_t CAP = 10 * 1024 * 1024; explicit SharedTestSpace(SharedHeap *heap) : Space(heap, heap->GetHeapRegionAllocator(), MemSpaceType::SHARED_OLD_SPACE, CAP, CAP), sHeap_(heap) {} ~SharedTestSpace() override = default; NO_COPY_SEMANTIC(SharedTestSpace); NO_MOVE_SEMANTIC(SharedTestSpace); void Expand(JSThread *thread) { Region *region = heapRegionAllocator_->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE, thread, sHeap_); FillBumpPointer(); allocator_.Reset(region->GetBegin(), region->GetEnd()); } uintptr_t Allocate(size_t size) { return allocator_.Allocate(size); } uintptr_t GetTop() { return allocator_.GetTop(); } void FillBumpPointer() { auto begin = allocator_.GetTop(); auto size = allocator_.Available(); FreeObject::FillFreeObject(sHeap_, begin, size); } uintptr_t GetEnd() { return allocator_.GetEnd(); } private: SharedHeap *sHeap_ {nullptr}; BumpPointerAllocator allocator_; }; void SharedPartialGCTest::InitTaggedArray(TaggedObject *obj, size_t arrayLen) { JSHClass *arrayClass = JSHClass::Cast(thread->GlobalConstants()->GetTaggedArrayClass().GetTaggedObject()); obj->SynchronizedSetClass(thread, arrayClass); TaggedArray::Cast(obj)->InitializeWithSpecialValue(JSTaggedValue::Undefined(), arrayLen); } JSHandle<TaggedObject> SharedPartialGCTest::CreateSharedObjectsInOneRegion(std::shared_ptr<SharedTestSpace> space, double aliveRate) { constexpr size_t TAGGED_TYPE_SIZE = 8; space->Expand(thread); size_t totalSize = space->GetEnd() - space->GetTop(); size_t alive = totalSize * aliveRate; size_t arrayLen = alive / TAGGED_TYPE_SIZE; size_t size = TaggedArray::ComputeSize(TAGGED_TYPE_SIZE, arrayLen); TaggedObject *obj = reinterpret_cast<TaggedObject *>(space->Allocate(size)); EXPECT_TRUE(obj != nullptr); InitTaggedArray(obj, arrayLen); return JSHandle<TaggedObject>(thread, obj); } HWTEST_F_L0(SharedPartialGCTest, PartialGCTest) { constexpr double ALIVE_RATE = 0.1; constexpr size_t ARRAY_SIZE = SharedOldSpace::MIN_COLLECT_REGION_SIZE; instance->GetJSOptions().SetEnableForceGC(false); Heap *heap = const_cast<Heap *>(instance->GetHeap()); SharedHeap *sHeap = SharedHeap::GetInstance(); ObjectFactory *factory = heap->GetEcmaVM()->GetFactory(); JSHandle<TaggedArray> localObj = factory->NewTaggedArray(ARRAY_SIZE, JSTaggedValue::Undefined(), false); heap->CollectGarbage(TriggerGCType::FULL_GC); sHeap->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::OTHER>(thread); heap->GetHeapPrepare(); SharedOldSpace *sOldSpace = sHeap->GetOldSpace(); std::shared_ptr<SharedTestSpace> space= std::make_shared<SharedTestSpace>(sHeap); std::vector<std::pair<Region*, JSHandle<TaggedObject>>> checkObjList; for (size_t i = 0; i < SharedOldSpace::MIN_COLLECT_REGION_SIZE; i++) { auto obj = CreateSharedObjectsInOneRegion(space, ALIVE_RATE); Region *region = Region::ObjectAddressToRange(*obj); checkObjList.emplace_back(region, obj); sOldSpace->AddRegion(region); } space->FillBumpPointer(); EXPECT_TRUE(sHeap->CheckCanTriggerConcurrentMarking(thread)); sHeap->TriggerConcurrentMarking<TriggerGCType::SHARED_PARTIAL_GC, MarkReason::OTHER>(thread); while (!thread->HasSuspendRequest()); thread->CheckSafepointIfSuspended(); if (thread->IsSharedConcurrentMarkingOrFinished()) { EXPECT_TRUE(sOldSpace->GetCollectSetRegionCount() > 0); Region *localRegion = Region::ObjectAddressToRange(*localObj); for (uint32_t i = 0; i < SharedOldSpace::MIN_COLLECT_REGION_SIZE; i++) { auto each = checkObjList[i]; Region *checkRegion = each.first; JSHandle<TaggedObject> checkObj = each.second; EXPECT_TRUE(checkRegion->InSCollectSet()); localObj->Set(thread, i, checkObj); JSTaggedType *localSlot = localObj->GetData() + i; EXPECT_TRUE(localRegion->TestLocalToShare(reinterpret_cast<uintptr_t>(localSlot))); } } sHeap->WaitGCFinished(thread); } } // namespace panda::test