/* * 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 "common_components/heap/ark_collector/ark_collector.h" #include "common_components/heap/verification.cpp" #include "common_components/heap/heap_manager.h" #include "common_components/tests/test_helper.h" #include "common_interfaces/objects/base_object_operator.h" using namespace common; namespace common::test { class TestBaseObjectOperator : public common::BaseObjectOperatorInterfaces { public: bool IsValidObject([[maybe_unused]] const BaseObject *object) const override { return enbaleValidObject_; } void ForEachRefField(const BaseObject *object, const common::RefFieldVisitor &visitor) const override {} size_t GetSize(const BaseObject *object) const override{ return size_; } BaseObject *GetForwardingPointer(const BaseObject *object) const override { return nullptr; } void SetForwardingPointerAfterExclusive(BaseObject *object, BaseObject *fwdPtr) override {} void SetValidObject(bool value) { enbaleValidObject_ = value; } void SetSize(size_t size) { size_ = size; } private: bool enbaleValidObject_ = false; size_t size_ = 0; }; class VerificationTest : public common::test::BaseTestWithScope { protected: static void SetUpTestCase() { BaseRuntime::GetInstance()->Init(); } static void TearDownTestCase() { BaseRuntime::GetInstance()->Fini(); } void SetUp() override { MutatorManager::Instance().CreateRuntimeMutator(ThreadType::GC_THREAD); } void TearDown() override { MutatorManager::Instance().DestroyRuntimeMutator(ThreadType::GC_THREAD); } }; HWTEST_F_L0(VerificationTest, GetObjectInfoTest) { BaseObject* obj = nullptr; std::string result = GetObjectInfo(obj); EXPECT_NE(result.find("address: 0x0"), std::string::npos); EXPECT_NE(result.find("Skip: nullptr"), std::string::npos); EXPECT_NE(result.find("Skip: Object is not in heap range"), std::string::npos); } HWTEST_F_L0(VerificationTest, GetObjectInfoTest2) { BaseObject obj; std::string result = GetObjectInfo(&obj); EXPECT_NE(result.find("address: 0x"), std::string::npos); EXPECT_NE(result.find("Skip: Object is not in heap range"), std::string::npos); } HWTEST_F_L0(VerificationTest, GetRefInfoTest) { BaseObject oldObj; RefField oldField(&oldObj); MAddress oldAddress = oldField.GetFieldValue(); std::string result = GetRefInfo(oldField); EXPECT_NE(result.find("address: 0x"), std::string::npos); EXPECT_NE(result.find("Skip: Object is not in heap range"), std::string::npos); } HWTEST_F_L0(VerificationTest, VerifyRefImplTest2) { RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0U); BaseObject* obj = reinterpret_cast(addr); RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast(obj)); ASSERT_NE(region, nullptr); region->SetRegionType(RegionDesc::RegionType::FROM_REGION); RefField field(obj); auto refObj = field.GetTargetObject(); AfterForwardVisitor visitor; visitor.VerifyRefImpl(obj, field); ASSERT_FALSE(RegionSpace::IsMarkedObject(refObj)); ASSERT_FALSE(RegionSpace::IsResurrectedObject(refObj)); } HWTEST_F_L0(VerificationTest, VerifyRefImplTest3) { RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0U); BaseObject* obj = reinterpret_cast(addr); RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast(obj)); ASSERT_NE(region, nullptr); region->SetRegionType(RegionDesc::RegionType::FULL_PINNED_REGION); RefField field(obj); auto refObj = field.GetTargetObject(); ReadBarrierSetter visitor; visitor.VerifyRefImpl(nullptr, field); visitor.VerifyRefImpl(obj, field); EXPECT_EQ(RegionDesc::RegionType::FULL_PINNED_REGION, RegionDesc::GetRegionDescAt(reinterpret_cast(field.GetTargetObject()))->GetRegionType()); region->SetRegionType(RegionDesc::RegionType::RECENT_PINNED_REGION); visitor.VerifyRefImpl(obj, field); EXPECT_EQ(RegionDesc::RegionType::RECENT_PINNED_REGION, RegionDesc::GetRegionDescAt(reinterpret_cast(field.GetTargetObject()))->GetRegionType()); region->SetRegionType(RegionDesc::RegionType::FIXED_PINNED_REGION); visitor.VerifyRefImpl(obj, field); EXPECT_EQ(RegionDesc::RegionType::FIXED_PINNED_REGION, RegionDesc::GetRegionDescAt(reinterpret_cast(field.GetTargetObject()))->GetRegionType()); region->SetRegionType(RegionDesc::RegionType::FULL_FIXED_PINNED_REGION); visitor.VerifyRefImpl(obj, field); EXPECT_EQ(RegionDesc::RegionType::FULL_FIXED_PINNED_REGION, RegionDesc::GetRegionDescAt(reinterpret_cast(field.GetTargetObject()))->GetRegionType()); region->SetRegionType(RegionDesc::RegionType::READ_ONLY_REGION); auto oldRefValue = field.GetFieldValue(); visitor.VerifyRefImpl(obj, field); auto newRefValue = field.GetFieldValue(); EXPECT_NE(oldRefValue, newRefValue); } std::unique_ptr GetArkCollector() { CollectorResources &resources = Heap::GetHeap().GetCollectorResources(); Allocator &allocator = Heap::GetHeap().GetAllocator(); return std::make_unique(allocator, resources); } HWTEST_F_L0(VerificationTest, VerifyAfterMarkTest1) { Heap::GetHeap().SetGCPhase(GCPhase::GC_PHASE_POST_MARK); std::unique_ptr arkCollector = GetArkCollector(); ASSERT_TRUE(arkCollector != nullptr); WVerify verify; verify.VerifyAfterMark(*arkCollector); ASSERT_FALSE(MutatorManager::Instance().WorldStopped()); } HWTEST_F_L0(VerificationTest, VerifyAfterForwardTest1) { Heap::GetHeap().SetGCPhase(GCPhase::GC_PHASE_COPY); std::unique_ptr arkCollector = GetArkCollector(); ASSERT_TRUE(arkCollector != nullptr); WVerify verify; verify.VerifyAfterForward(*arkCollector); ASSERT_FALSE(MutatorManager::Instance().WorldStopped()); } HWTEST_F_L0(VerificationTest, VerifyAfterFixTest1) { Heap::GetHeap().SetGCPhase(GCPhase::GC_PHASE_FIX); std::unique_ptr arkCollector = GetArkCollector(); ASSERT_TRUE(arkCollector != nullptr); WVerify verify; verify.VerifyAfterFix(*arkCollector); ASSERT_FALSE(MutatorManager::Instance().WorldStopped()); } HWTEST_F_L0(VerificationTest, EnableReadBarrierDFXTest1) { std::unique_ptr arkCollector = GetArkCollector(); ASSERT_TRUE(arkCollector != nullptr); WVerify verify; verify.EnableReadBarrierDFX(*arkCollector); ASSERT_FALSE(MutatorManager::Instance().WorldStopped()); } HWTEST_F_L0(VerificationTest, DisableReadBarrierDFXTest1) { std::unique_ptr arkCollector = GetArkCollector(); ASSERT_TRUE(arkCollector != nullptr); WVerify verify; verify.DisableReadBarrierDFX(*arkCollector); ASSERT_FALSE(MutatorManager::Instance().WorldStopped()); } HWTEST_F_L0(VerificationTest, GetObjectInfoTest3) { HeapAddress addr = HeapManager::Allocate(sizeof(BaseObject), AllocType::PINNED_OBJECT, true); BaseObject *obj = reinterpret_cast(addr); std::string result = GetObjectInfo(obj); EXPECT_NE(result.find("address: 0x"), std::string::npos); EXPECT_NE(result.find("Type: 0x"), std::string::npos); EXPECT_NE(result.find("Base: 0x"), std::string::npos); EXPECT_NE(result.find("Start: 0x"), std::string::npos); EXPECT_NE(result.find("End: 0x"), std::string::npos); EXPECT_NE(result.find("AllocPtr: 0x"), std::string::npos); EXPECT_NE(result.find("MarkingLine: 0x"), std::string::npos); EXPECT_NE(result.find("CopyLine: 0x"), std::string::npos); } HWTEST_F_L0(VerificationTest, GetRefInfoTest2) { RefField field(nullptr); uintptr_t taggedValue = 0x04; field.SetFieldValue(static_cast(taggedValue)); std::string result = GetRefInfo(field); EXPECT_NE(result.find("> Raw memory:"), std::string::npos); EXPECT_NE(result.find("Skip: primitive"), std::string::npos); } HWTEST_F_L0(VerificationTest, VerifyRefImplTest) { HeapAddress addr = HeapManager::Allocate(sizeof(BaseObject), AllocType::PINNED_OBJECT, true); BaseObject *obj = reinterpret_cast(addr); RefField oldField(obj); TestBaseObjectOperator operatorImpl; BaseObject::RegisterDynamic(&operatorImpl); operatorImpl.SetValidObject(true); Heap::GetHeap().SetGCReason(GCReason::GC_REASON_YOUNG); operatorImpl.SetSize(BaseObject::BaseObjectSize()); AfterMarkVisitor visitor; visitor.VerifyRefImpl(nullptr, oldField); ASSERT_TRUE(Heap::GetHeap().GetGCReason() == GCReason::GC_REASON_YOUNG); ASSERT_TRUE(Heap::IsTaggedObject(oldField.GetFieldValue())); AfterMarkVisitor visitor1; visitor1.VerifyRefImpl(nullptr, oldField); ASSERT_TRUE(Heap::IsTaggedObject(oldField.GetFieldValue())); } HWTEST_F_L0(VerificationTest, VerifyRefImplTest1) { HeapAddress addr = HeapManager::Allocate(sizeof(BaseObject), AllocType::PINNED_OBJECT, true); BaseObject *obj = reinterpret_cast(addr); RefField oldField(obj); TestBaseObjectOperator operatorImpl; BaseObject::RegisterDynamic(&operatorImpl); operatorImpl.SetValidObject(true); Heap::GetHeap().SetGCReason(GCReason::GC_REASON_YOUNG); operatorImpl.SetSize(BaseObject::BaseObjectSize()); AfterMarkVisitor visitor; visitor.VerifyRefImpl(obj, oldField); ASSERT_TRUE(Heap::GetHeap().GetGCReason() == GCReason::GC_REASON_YOUNG); ASSERT_TRUE(Heap::IsTaggedObject(oldField.GetFieldValue())); } static BaseObject* testObj = nullptr; static void CustomVisitRoot(const RefFieldVisitor& visitorFunc) { RefField<> field(testObj); visitorFunc(field); } HWTEST_F_L0(VerificationTest, IterateRemarked_VerifyAllRefs) { RegionSpace regionSpace; VerifyIterator verify(regionSpace); AfterForwardVisitor visitor; std::unordered_set markSet; HeapAddress addr = HeapManager::Allocate(sizeof(BaseObject), AllocType::PINNED_OBJECT, true); testObj = reinterpret_cast(addr); markSet.insert(testObj); verify.IterateRemarked(visitor, markSet, true); verify.IterateRemarked(visitor, markSet, false); EXPECT_EQ(markSet.size(), 1); EXPECT_TRUE(markSet.find(testObj) != markSet.end()); } } // namespace common::test