From d071fa347366c74a43c578768dc2662ec72d56f7 Mon Sep 17 00:00:00 2001 From: yp9522 Date: Fri, 4 Jul 2025 11:12:48 +0800 Subject: [PATCH] add common_components tdd Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICJXMG Change-Id: I6f4fc86621e90fd2f64f19daacbf10dab4a92744 Signed-off-by: yp9522 --- BUILD.gn | 12 +- common_components/base/tests/BUILD.gn | 2 +- .../base/tests/c_string_test.cpp | 125 ++++++++- .../heap/allocator/tests/BUILD.gn | 1 + .../heap/allocator/tests/allocator_test.cpp | 1 + .../allocator/tests/heap_allocator_test.cpp | 16 +- .../allocator/tests/region_manager_test.cpp | 4 +- .../allocator/tests/region_space_test.cpp | 231 +++++++++++------ .../heap/collector/finalizer_processor.cpp | 2 +- .../heap/collector/tests/BUILD.gn | 3 +- .../tests/collector_resources_test.cpp | 25 ++ .../tests/finalizer_processor_test.cpp | 21 +- .../heap/collector/tests/task_queue_test.cpp | 1 + .../w_collector/tests/w_collector_test.cpp | 77 +++++- common_components/mutator/tests/BUILD.gn | 27 ++ .../mutator/tests/mutator_manager_test.cpp | 19 -- .../mutator/tests/mutator_test.cpp | 243 ++++++++++++++++++ .../mutator/tests/satb_buffer_test.cpp | 139 ++++++---- .../objects/tests/base_string_test.cpp | 182 +++++++++++++ 19 files changed, 947 insertions(+), 184 deletions(-) create mode 100755 common_components/mutator/tests/mutator_test.cpp diff --git a/BUILD.gn b/BUILD.gn index 7a00f3610d..9baf57f784 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -159,11 +159,9 @@ group("common_components_js_unittest") { deps += [ "common_components/base/tests:unittest", "common_components/base_runtime/tests:unittest", - - #"common_components/heap/allocator/tests:unittest", + "common_components/heap/allocator/tests:unittest", "common_components/heap/barrier/tests:unittest", - - #"common_components/heap/collector/tests:unittest", + "common_components/heap/collector/tests:unittest", "common_components/heap/w_collector/tests:unittest", "common_components/mutator/tests:unittest", "common_components/objects/tests:unittest", @@ -181,11 +179,9 @@ group("common_components_unittest") { deps += [ "common_components/base/tests:host_unittest", "common_components/base_runtime/tests:host_unittest", - - #"common_components/heap/allocator/tests:host_unittest", + "common_components/heap/allocator/tests:host_unittest", "common_components/heap/barrier/tests:host_unittest", - - #"common_components/heap/collector/tests:host_unittest", + "common_components/heap/collector/tests:host_unittest", "common_components/heap/w_collector/tests:host_unittest", "common_components/mutator/tests:host_unittest", "common_components/objects/tests:host_unittest", diff --git a/common_components/base/tests/BUILD.gn b/common_components/base/tests/BUILD.gn index 39e86f58d2..3670facd9b 100755 --- a/common_components/base/tests/BUILD.gn +++ b/common_components/base/tests/BUILD.gn @@ -34,7 +34,7 @@ host_unittest_action("C_String_Test") { external_deps = [ "icu:shared_icui18n", "icu:shared_icuuc", - "runtime_core:libarkassembler_static", + "zlib:libz", ] } diff --git a/common_components/base/tests/c_string_test.cpp b/common_components/base/tests/c_string_test.cpp index 56b0436ac5..b1543fbd8a 100755 --- a/common_components/base/tests/c_string_test.cpp +++ b/common_components/base/tests/c_string_test.cpp @@ -15,7 +15,6 @@ #include "common_components/base/c_string.h" #include "common_components/tests/test_helper.h" -#include using namespace common; namespace common::test { @@ -274,4 +273,128 @@ HWTEST_F_L0(CStringTest, ConstructTest) EXPECT_EQ(nonEmptyStr.Length(), static_cast(0)); EXPECT_EQ(nonEmptyStr.Str()[0], '\0'); } + +HWTEST_F_L0(CStringTest, FormatStringBasicTest) +{ + CString result = CString::FormatString("Hello, %s!", "World"); + EXPECT_STREQ(result.Str(), "Hello, World!"); +} + +HWTEST_F_L0(CStringTest, FormatString_InvalidArguments_ReturnsError) +{ + CString result = CString::FormatString("%n", nullptr); + EXPECT_STREQ(result.Str(), "invalid arguments for FormatString"); +} + +HWTEST_F_L0(CStringTest, InsertMiddle_Success) +{ + CString str("helloworld"); + EXPECT_STREQ(str.Insert(5, ", ").Str(), "hello, world"); +} + +HWTEST_F_L0(CStringTest, TruncateValidIndex_Success) +{ + CString str("hello world"); + EXPECT_STREQ(str.Truncate(5).Str(), "hello"); + EXPECT_EQ(str.Length(), static_cast(5)); +} + +HWTEST_F_L0(CStringTest, GetStr_NonEmptyString_ReturnsCorrect) +{ + CString str("test string"); + EXPECT_STREQ(str.GetStr(), "test string"); +} + +HWTEST_F_L0(CStringTest, CombineWithEmptyString_ReturnsOriginal) +{ + CString str("original"); + CString emptyStr; + CString combined = str.Combine(emptyStr); + EXPECT_STREQ(combined.Str(), "original"); + EXPECT_EQ(combined.Length(), str.Length()); +} + +HWTEST_F_L0(CStringTest, CombineWithEmptyCStr_ReturnsOriginal) +{ + CString str("original"); + const char* emptyCStr = ""; + CString combined = str.Combine(emptyCStr); + EXPECT_STREQ(combined.Str(), "original"); + EXPECT_EQ(combined.Length(), str.Length()); +} + +HWTEST_F_L0(CStringTest, AppendNullptr_NoChange) +{ + CString str("original"); + str.Append(nullptr, 5); + EXPECT_STREQ(str.Str(), "original"); + EXPECT_EQ(str.Length(), strlen("original")); +} + +HWTEST_F_L0(CStringTest, AppendZeroLength_NoChange) +{ + CString str("test"); + CString emptyStr; + + str.Append(emptyStr, 0); + + EXPECT_STREQ(str.Str(), "test"); + EXPECT_EQ(str.Length(), strlen("test")); +} + +HWTEST_F_L0(CStringTest, AppendSelf_ValidResult) +{ + CString str("abc"); + str.Append(str.Str(), str.Length()); + EXPECT_STREQ(str.Str(), "abcabc"); + EXPECT_EQ(str.Length(), strlen("abcabc")); +} + +HWTEST_F_L0(CStringTest, AppendEmptyCString_NoChange) +{ + CString str("original"); + CString emptyStr; + str.Append(emptyStr); + EXPECT_STREQ(str.Str(), "original"); + EXPECT_EQ(str.Length(), strlen("original")); +} + +HWTEST_F_L0(CStringTest, AppendEmptyCStringZeroLength_NoChange) +{ + CString str("test"); + CString emptyStr; + + str.Append(emptyStr, 0); + + EXPECT_STREQ(str.Str(), "test"); + EXPECT_EQ(str.Length(), strlen("test")); +} + +HWTEST_F_L0(CStringTest, AppendValidCString_CorrectResult) +{ + CString str("hello"); + CString addStr(" world!"); + str.Append(addStr, strlen(addStr.Str())); + EXPECT_STREQ(str.Str(), "hello world!"); + EXPECT_EQ(str.Length(), strlen("hello world!")); +} + +HWTEST_F_L0(CStringTest, EnsureMultipleCalls_CapacityGrowsCorrectly) +{ + CString str("initial"); + char* firstPtr = str.GetStr(); + + str.EnsureSpace(16); + char* secondPtr = str.GetStr(); + + EXPECT_NE(firstPtr, secondPtr); + + str.EnsureSpace(100); + char* thirdPtr = str.GetStr(); + + EXPECT_NE(secondPtr, thirdPtr); + EXPECT_EQ(str.Length(), strlen("initial")); + EXPECT_STREQ(str.Str(), "initial"); +} + } \ No newline at end of file diff --git a/common_components/heap/allocator/tests/BUILD.gn b/common_components/heap/allocator/tests/BUILD.gn index 5acba71f6e..cd1f06bb2d 100755 --- a/common_components/heap/allocator/tests/BUILD.gn +++ b/common_components/heap/allocator/tests/BUILD.gn @@ -103,6 +103,7 @@ host_unittest_action("Region_Space_Test") { # hiviewdfx libraries external_deps = [ + "bounds_checking_function:libsec_shared", "icu:shared_icui18n", "icu:shared_icuuc", "zlib:libz", diff --git a/common_components/heap/allocator/tests/allocator_test.cpp b/common_components/heap/allocator/tests/allocator_test.cpp index 58820668fc..c7d02c39d7 100755 --- a/common_components/heap/allocator/tests/allocator_test.cpp +++ b/common_components/heap/allocator/tests/allocator_test.cpp @@ -44,6 +44,7 @@ public: bool IsHeapObject(HeapAddress) const override { return false; } #endif void FeedHungryBuffers() override {} + size_t GetSurvivedSize() const override { return 0; } }; class AllocatorTest : public common::test::BaseTestWithScope { }; diff --git a/common_components/heap/allocator/tests/heap_allocator_test.cpp b/common_components/heap/allocator/tests/heap_allocator_test.cpp index 7f8c1372b2..be2b6faa6f 100644 --- a/common_components/heap/allocator/tests/heap_allocator_test.cpp +++ b/common_components/heap/allocator/tests/heap_allocator_test.cpp @@ -13,15 +13,11 @@ * limitations under the License. */ -#include - #include "common_interfaces/heap/heap_allocator.h" +#include "common_components/heap/allocator/region_desc.h" #include "common_components/heap/allocator/region_space.h" -#include "common_components/heap/collector/trace_collector.h" -#include "common_components/heap/heap.cpp" -#include "common_components/base_runtime/base_runtime_param.h" -#include "common_components/heap/heap_manager.h" #include "common_components/tests/test_helper.h" +#include "common_interfaces/base_runtime.h" using namespace common; @@ -36,7 +32,11 @@ class HeapAllocatorTest : public BaseTestWithScope { void TearDown() override { - delete scope_; + if (scope_ != nullptr) { + delete scope_; + scope_ = nullptr; + } + BaseRuntime::GetInstance()->Fini(); } @@ -46,7 +46,7 @@ class HeapAllocatorTest : public BaseTestWithScope { HWTEST_F_L0(HeapAllocatorTest, AllocLargeObject) { - uintptr_t addr = common::HeapAllocator::Allocate(Heap::NORMAL_UNIT_SIZE, common::LanguageType::DYNAMIC); + uintptr_t addr = common::HeapAllocator::AllocateInHuge(Heap::NORMAL_UNIT_SIZE, common::LanguageType::DYNAMIC); ASSERT(addr > 0); RegionDesc* region = RegionDesc::GetAliveRegionDescAt(addr); ASSERT(region->IsLargeRegion()); diff --git a/common_components/heap/allocator/tests/region_manager_test.cpp b/common_components/heap/allocator/tests/region_manager_test.cpp index 07b15d7c6d..c3a4ab5d15 100755 --- a/common_components/heap/allocator/tests/region_manager_test.cpp +++ b/common_components/heap/allocator/tests/region_manager_test.cpp @@ -301,9 +301,9 @@ HWTEST_F_L0(RegionManagerTest, TakeRegion2) size_t nUnit = 1; manager.Initialize(SIZE_MAX_TEST, reinterpret_cast(regionMemory_)); RegionDesc* garbageRegion = RegionDesc::InitRegion(SIZE_HALF_MAX_TEST, nUnit, - RegionDesc::UnitRole::SMALL_SIZED_UNITS); + RegionDesc::UnitRole::LARGE_SIZED_UNITS); auto size = manager.CollectRegion(garbageRegion); - RegionDesc* region = manager.TakeRegion(16, RegionDesc::UnitRole::SMALL_SIZED_UNITS, true, false); + RegionDesc* region = manager.TakeRegion(16, RegionDesc::UnitRole::LARGE_SIZED_UNITS, true, false); EXPECT_NE(region, nullptr); } diff --git a/common_components/heap/allocator/tests/region_space_test.cpp b/common_components/heap/allocator/tests/region_space_test.cpp index f2db5516d6..c2a0441378 100755 --- a/common_components/heap/allocator/tests/region_space_test.cpp +++ b/common_components/heap/allocator/tests/region_space_test.cpp @@ -13,96 +13,55 @@ * limitations under the License. */ -#include "common_interfaces/heap/heap_allocator.h" +#include "common_components/heap/allocator/region_desc.h" #include "common_components/heap/allocator/region_space.h" -#include "common_components/heap/collector/trace_collector.h" -#include "common_components/heap/heap.cpp" -#include "common_components/base_runtime/base_runtime_param.h" -#include "common_components/heap/heap_manager.h" +#include "common_components/heap/collector/collector_resources.h" #include "common_components/tests/test_helper.h" -#include +#include "common_interfaces/base_runtime.h" using namespace common; namespace common::test { class RegionSpaceTest : public common::test::BaseTestWithScope { -protected: - void* regionMemory_; - size_t totalUnits_ = 1024; - size_t heapSize_; - Mutator* mutator_ = nullptr; - - static void SetUpTestCase() - { - BaseRuntime::GetInstance()->Init(); - } - - static void TearDownTestCase() - { - BaseRuntime::GetInstance()->Fini(); - } - void SetUp() override { - heapSize_ = totalUnits_ * RegionDesc::UNIT_SIZE; - size_t allocSize = heapSize_ + totalUnits_ * sizeof(RegionDesc); - regionMemory_ = malloc(allocSize); - ASSERT_NE(regionMemory_, nullptr); - uintptr_t unitInfoStart = reinterpret_cast(regionMemory_); - size_t metadataSize = totalUnits_ * sizeof(RegionDesc); - uintptr_t heapStartAddress = unitInfoStart + metadataSize; - RegionDesc::Initialize(totalUnits_, unitInfoStart, heapStartAddress); - mutator_ = Mutator::NewMutator(); - ASSERT_NE(mutator_, nullptr); - mutator_->InitTid(); - ThreadLocal::GetThreadLocalData()->mutator = mutator_; - BaseRuntime::GetInstance()->GetHeapParam().regionSize = 64; // 64:region size - RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); - RegionManager& regionManager = theAllocator.GetRegionManager(); - regionManager.SetMaxUnitCountForRegion(); + BaseRuntime::GetInstance()->Init(); + holder_ = ThreadHolder::CreateAndRegisterNewThreadHolder(nullptr); + scope_ = new ThreadHolder::TryBindMutatorScope(holder_); } void TearDown() override { - if (mutator_) { - delete mutator_; - mutator_ = nullptr; - } - if (regionMemory_) { - free(regionMemory_); - regionMemory_ = nullptr; + if (scope_ != nullptr) { + delete scope_; + scope_ = nullptr; } + + BaseRuntime::GetInstance()->Fini(); } -}; -HWTEST_F_L0(RegionSpaceTest, ShouldRetryAllocation) -{ - auto* mutator = common::Mutator::GetMutator(); - mutator->SetMutatorPhase(GCPhase::GC_PHASE_UNDEF); - ThreadLocal::SetThreadType(ThreadType::GC_THREAD); - Heap::GetHeap().EnableGC(false); - Heap::GetHeap().GetCollectorResources().SetGcStarted(true); - Allocator *regionSpace = RegionSpace::CreateAllocator(); - EXPECT_EQ(regionSpace->Allocate(16, AllocType::MOVEABLE_OBJECT), 0); -} + ThreadHolder *holder_ {nullptr}; + ThreadHolder::TryBindMutatorScope *scope_ {nullptr}; +}; HWTEST_F_L0(RegionSpaceTest, FeedHungryBuffers2) { auto* mutator = common::Mutator::GetMutator(); mutator->SetMutatorPhase(GCPhase::GC_PHASE_FIX); - RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); - RegionManager& manager = theAllocator.GetRegionManager(); ThreadLocal::SetThreadType(ThreadType::ARK_PROCESSOR); - manager.Initialize(1024, reinterpret_cast(regionMemory_)); AllocationBuffer* buffer1 = new (std::nothrow) AllocationBuffer(); AllocationBuffer* buffer2 = new (std::nothrow) AllocationBuffer(); - RegionDesc* Region = RegionDesc::InitRegion(0, 1, RegionDesc::UnitRole::SMALL_SIZED_UNITS); - buffer1->SetPreparedRegion(Region); + RegionDesc* region = RegionDesc::InitRegion(0, 1, RegionDesc::UnitRole::LARGE_SIZED_UNITS); + region->InitFreeUnits(); + buffer1->SetPreparedRegion(region); + buffer2->SetPreparedRegion(region); Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer1); Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer2); Heap::GetHeap().GetAllocator().FeedHungryBuffers(); EXPECT_NE(buffer2->GetPreparedRegion(), nullptr); + delete buffer1; + delete buffer2; } HWTEST_F_L0(RegionSpaceTest, FeedHungryBuffers3) @@ -115,11 +74,10 @@ HWTEST_F_L0(RegionSpaceTest, FeedHungryBuffers3) EXPECT_EQ(hungryBuffers.size(), 0); } - HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseEnum) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -131,8 +89,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseEnum) HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseMark) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_MARK); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_MARK); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -144,8 +102,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseMark) HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseRemarkStab) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_REMARK_SATB); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_REMARK_SATB); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -157,8 +115,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseRemarkStab) HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhasePostMark) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_POST_MARK); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_POST_MARK); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -216,8 +174,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocRegion_PhaseUndef) HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhaseEnum) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocPinnedRegion(); ASSERT_NE(addr, 0); @@ -229,8 +187,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhaseEnum) HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhaseMark) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_MARK); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_MARK); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocPinnedRegion(); ASSERT_NE(addr, 0); @@ -242,8 +200,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhaseMark) HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhaseRemarkStab) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_REMARK_SATB); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_REMARK_SATB); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocPinnedRegion(); ASSERT_NE(addr, 0); @@ -255,8 +213,8 @@ HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhaseRemarkStab) HWTEST_F_L0(RegionSpaceTest, AllocPinnedRegion_PhasePostMark) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_POST_MARK); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_POST_MARK); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocPinnedRegion(); ASSERT_NE(addr, 0); @@ -368,18 +326,121 @@ HWTEST_F_L0(RegionSpaceTest, AllocateThreadLocalRegion4) EXPECT_EQ(region4->GetFixLine(), std::numeric_limits::max()); } -HWTEST_F_L0(RegionSpaceTest, CopyRegion1) +HWTEST_F_L0(RegionSpaceTest, CopyRegion) { auto* mutator = common::Mutator::GetMutator(); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); - theAllocator.AssembleSmallGarbageCandidates(); - RegionDesc* region = theAllocator.GetRegionManager().TakeRegion( - 16, RegionDesc::UnitRole::SMALL_SIZED_UNITS, true, false); + uintptr_t addr = theAllocator.AllocRegion(); + ASSERT_NE(addr, 0); + RegionDesc* region = RegionDesc::GetRegionDescAt(addr); region->SetRegionType(RegionDesc::RegionType::FROM_REGION); ASSERT(region->IsFromRegion()); - region->AddLiveByteCount(1); theAllocator.CopyRegion(region); - EXPECT_NE(theAllocator.FromSpaceSize(), 0); + EXPECT_EQ(theAllocator.FromSpaceSize(), 0); +} + +HWTEST_F_L0(RegionSpaceTest, AllocateThreadLocalRegion1_NotGcThread_EntersElseBranch) +{ + auto& heapAllocator = Heap::GetHeap().GetAllocator(); + RegionSpace& regionSpace = reinterpret_cast(heapAllocator); + + Mutator::GetMutator()->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + + auto* region = regionSpace.AllocateThreadLocalRegion(false, AllocType::MOVEABLE_OBJECT); + EXPECT_NE(region, nullptr); +} + +HWTEST_F_L0(RegionSpaceTest, AllocateThreadLocalRegion2_NotGcThread_EntersElseBranch) +{ + auto& heapAllocator = Heap::GetHeap().GetAllocator(); + RegionSpace& regionSpace = reinterpret_cast(heapAllocator); + + Mutator::GetMutator()->SetMutatorPhase(GCPhase::GC_PHASE_PRECOPY); + + auto* region = regionSpace.AllocateThreadLocalRegion(false, AllocType::MOVEABLE_OBJECT); + EXPECT_NE(region, nullptr); +} + +HWTEST_F_L0(RegionSpaceTest, AllocateThreadLocalRegion3_NotGcThread_EntersElseBranch) +{ + auto& heapAllocator = Heap::GetHeap().GetAllocator(); + RegionSpace& regionSpace = reinterpret_cast(heapAllocator); + + Mutator::GetMutator()->SetMutatorPhase(GCPhase::GC_PHASE_FIX); + + auto* region = regionSpace.AllocateThreadLocalRegion(false, AllocType::MOVEABLE_OBJECT); + EXPECT_NE(region, nullptr); +} + +HWTEST_F_L0(RegionSpaceTest, Allocate_ValidSize_ReturnsNonNull) +{ + RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); + uintptr_t addr = theAllocator.AllocRegion(); + ASSERT_NE(addr, 0); + + RegionDesc* region = RegionDesc::GetRegionDescAt(addr); + region->InitFreeUnits(); + region->SetRegionType(RegionDesc::RegionType::THREAD_LOCAL_REGION); + Mutator::GetMutator()->SetMutatorPhase(GCPhase::GC_PHASE_UNDEF); + Heap::GetHeap().EnableGC(true); + Heap::GetHeap().GetCollectorResources().SetGcStarted(false); + + uintptr_t result = theAllocator.Allocate(16, AllocType::PINNED_OBJECT); + EXPECT_NE(result, 0u); +} + +HWTEST_F_L0(RegionSpaceTest, FeedHungryBuffers_ShouldProvideValidRegions) +{ + RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); + uintptr_t addr = theAllocator.AllocRegion(); + ASSERT_NE(addr, 0); + + AllocationBuffer* buffer1 = new (std::nothrow) AllocationBuffer(); + AllocationBuffer* buffer2 = new (std::nothrow) AllocationBuffer(); + ASSERT_NE(buffer1, nullptr); + ASSERT_NE(buffer2, nullptr); + + RegionDesc* region = RegionDesc::GetRegionDescAt(addr); + ASSERT_NE(region, nullptr); + region->InitFreeUnits(); + region->SetRegionType(RegionDesc::RegionType::THREAD_LOCAL_REGION); + + buffer1->SetPreparedRegion(region); + buffer2->SetPreparedRegion(region); + Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer1); + Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer2); + + Mutator::GetMutator()->SetMutatorPhase(GCPhase::GC_PHASE_FIX); + + Heap::GetHeap().GetAllocator().FeedHungryBuffers(); + + EXPECT_NE(buffer2->GetPreparedRegion(), nullptr); + delete buffer1; + delete buffer2; +} + +HWTEST_F_L0(RegionSpaceTest, AllocationBuffer_AllocateRawPointerObject_ValidSize_ReturnsNonNull) +{ + RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); + uintptr_t addr = theAllocator.AllocRegion(); + ASSERT_NE(addr, 0); + + RegionDesc* region = RegionDesc::GetRegionDescAt(addr); + ASSERT_NE(region, nullptr); + region->InitFreeUnits(); + region->SetRegionType(RegionDesc::RegionType::THREAD_LOCAL_REGION); + + AllocationBuffer* buffer = new (std::nothrow) AllocationBuffer(); + ASSERT_NE(buffer, nullptr); + buffer->SetPreparedRegion(region); + + Mutator::GetMutator()->SetMutatorPhase(GCPhase::GC_PHASE_UNDEF); + Heap::GetHeap().EnableGC(true); + Heap::GetHeap().GetCollectorResources().SetGcStarted(false); + + uintptr_t result = theAllocator.Allocate(16, AllocType::PINNED_OBJECT); + EXPECT_NE(result, 0u); + delete buffer; } } diff --git a/common_components/heap/collector/finalizer_processor.cpp b/common_components/heap/collector/finalizer_processor.cpp index 73ec6abdb2..d464623d53 100755 --- a/common_components/heap/collector/finalizer_processor.cpp +++ b/common_components/heap/collector/finalizer_processor.cpp @@ -252,7 +252,7 @@ void FinalizerProcessor::LogAfterProcess() void FinalizerProcessor::RegisterFinalizer(BaseObject* obj) { RefField<> tmpField(nullptr); - Heap::GetHeap().GetBarrier().WriteStaticRef(tmpField, obj); + Heap::GetHeap().GetBarrier().WriteRefField(obj, tmpField, obj); std::lock_guard l(listLock_); finalizers_.push_back(reinterpret_cast(tmpField.GetFieldValue())); } diff --git a/common_components/heap/collector/tests/BUILD.gn b/common_components/heap/collector/tests/BUILD.gn index 20a34d4289..5e331b82e1 100755 --- a/common_components/heap/collector/tests/BUILD.gn +++ b/common_components/heap/collector/tests/BUILD.gn @@ -21,7 +21,7 @@ host_unittest_action("Collector_Test") { sources = [ # test file "collector_resources_test.cpp", - # "finalizer_processor_test.cpp", + "finalizer_processor_test.cpp", ] configs = [ @@ -33,6 +33,7 @@ host_unittest_action("Collector_Test") { # hiviewdfx libraries external_deps = [ + "bounds_checking_function:libsec_shared", "icu:shared_icui18n", "icu:shared_icuuc", "zlib:libz", diff --git a/common_components/heap/collector/tests/collector_resources_test.cpp b/common_components/heap/collector/tests/collector_resources_test.cpp index e5c41750fc..5f46e69f5d 100755 --- a/common_components/heap/collector/tests/collector_resources_test.cpp +++ b/common_components/heap/collector/tests/collector_resources_test.cpp @@ -14,6 +14,7 @@ */ #include "common_components/heap/collector/collector_resources.h" +#include "common_components/heap/collector/gc_request.h" #include "common_components/mutator/mutator_manager.h" #include "common_components/tests/test_helper.h" #include "common_interfaces/base_runtime.h" @@ -88,4 +89,28 @@ HWTEST_F_L0(CollectorResourcesTest, StopRuntimeThreadsTest) { Heap::GetHeap().GetCollectorResources().StopRuntimeThreads(); EXPECT_FALSE(Heap::GetHeap().GetCollectorResources().GetFinalizerProcessor().IsRunning()); } + +HWTEST_F_L0(CollectorResourcesTest, RequestGC_TriggerPostIgnoredGcRequest_WithHighFrequency) +{ + auto& collectorResources = Heap::GetHeap().GetCollectorResources(); + + uint64_t now = TimeUtil::NanoSeconds(); + GCRequest req = { + GC_REASON_NATIVE, + "FrequentObject", + false, + false, + 100, + now + }; + + for (int i = 0; i < 5; ++i) + { + req.prevRequestTime = now; + now += 50; + req.minIntervelNs = 100; + + collectorResources.RequestGC(req.reason, false); + } +} } // namespace common::test \ No newline at end of file diff --git a/common_components/heap/collector/tests/finalizer_processor_test.cpp b/common_components/heap/collector/tests/finalizer_processor_test.cpp index 746a5744ae..01162403a3 100755 --- a/common_components/heap/collector/tests/finalizer_processor_test.cpp +++ b/common_components/heap/collector/tests/finalizer_processor_test.cpp @@ -123,12 +123,10 @@ HWTEST_F_L0(FinalizerProcessorTest, Run_TEST1) HeapAddress addr = common::HeapManager::Allocate(sizeof(BaseObject), AllocType::MOVEABLE_OBJECT, true); BaseObject *obj = reinterpret_cast(addr); new (obj) BaseObject(); - AllocationBuffer* buffer1 = new (std::nothrow) AllocationBuffer(); - AllocationBuffer* buffer2 = new (std::nothrow) AllocationBuffer(); - RegionDesc* Region = RegionDesc::InitRegion(0, 1, RegionDesc::UnitRole::SMALL_SIZED_UNITS); - buffer1->SetPreparedRegion(Region); - Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer1); - Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer2); + AllocationBuffer* buffer = new (std::nothrow) AllocationBuffer(); + RegionDesc* region = RegionDesc::GetRegionDescAt(addr); + buffer->SetPreparedRegion(region); + Heap::GetHeap().GetAllocator().AddHungryBuffer(*buffer); finalizerProcessor.RegisterFinalizer(obj); finalizerProcessor.Start(); std::thread notifier([&]() { @@ -140,6 +138,13 @@ HWTEST_F_L0(FinalizerProcessorTest, Run_TEST1) notifier.join(); std::this_thread::sleep_for(std::chrono::seconds(TWO_SECONDS)); finalizerProcessor.Stop(); - EXPECT_NE(buffer2->GetPreparedRegion(), nullptr); + EXPECT_NE(buffer->GetPreparedRegion(), nullptr); + delete buffer; } -} // namespace common::test \ No newline at end of file + +HWTEST_F_L0(FinalizerProcessorTest, Stop_BeforeStart_NoException) { + FinalizerProcessor unstartedProcessor; + EXPECT_NO_THROW(unstartedProcessor.Stop()); +} + +} // namespace common::test diff --git a/common_components/heap/collector/tests/task_queue_test.cpp b/common_components/heap/collector/tests/task_queue_test.cpp index aacc1a9589..f11f30e1a5 100644 --- a/common_components/heap/collector/tests/task_queue_test.cpp +++ b/common_components/heap/collector/tests/task_queue_test.cpp @@ -37,6 +37,7 @@ public: bool IsHeapObject(HeapAddress) const override { return false; } #endif void FeedHungryBuffers() override {} + size_t GetSurvivedSize() const override { return 0; } }; class StubCollectorProxy : public CollectorProxy { diff --git a/common_components/heap/w_collector/tests/w_collector_test.cpp b/common_components/heap/w_collector/tests/w_collector_test.cpp index 25185f35ef..22accdcec4 100644 --- a/common_components/heap/w_collector/tests/w_collector_test.cpp +++ b/common_components/heap/w_collector/tests/w_collector_test.cpp @@ -25,7 +25,7 @@ using namespace common; namespace common::test { using SuspensionType = MutatorBase::SuspensionType; -class WCollectorTest : public BaseTestWithScope { +class WCollectorTest : public common::test::BaseTestWithScope { protected: static void SetUpTestCase() { @@ -136,4 +136,79 @@ HWTEST_F_L0(WCollectorTest, FlipTest) std::thread t1(FlipTest); t1.join(); } + +HWTEST_F_L0(WCollectorTest, IsUnmovableFromObject_ReturnsFalseForNullptr) +{ + std::unique_ptr wcollector = GetWCollector(); + ASSERT_TRUE(wcollector != nullptr); + + BaseObject* obj = nullptr; + EXPECT_FALSE(wcollector->IsUnmovableFromObject(obj)); +} + +class TestableWCollector : public WCollector { +public: + using WCollector::ForwardObject; + + explicit TestableWCollector(Allocator& allocator, CollectorResources& resources) + : WCollector(allocator, resources), currentGCPhase_(GCPhase::GC_PHASE_COPY) {} + + void SetCurrentGCPhaseForTest(GCPhase phase) + { + currentGCPhase_ = phase; + } + + GCPhase GetCurrentGCPhaseForTest() const + { + return currentGCPhase_; + } + +private: + GCPhase currentGCPhase_; +}; + + +class DummyObject : public BaseObject { +public: + const common::TypeInfo* GetTypeInfo() const { return nullptr; } + size_t GetSize() const { return sizeof(DummyObject); } + + void SetClass(uintptr_t cls) + { + stateWord_.StoreStateWord(static_cast(cls)); + } + +private: + class BaseStateWord { + public: + using StateWordType = uint64_t; + + void StoreStateWord(StateWordType word) + { + stateWord_ = word; + } + + StateWordType LoadStateWord() const + { + return stateWord_; + } + + private: + StateWordType stateWord_{0}; + }; + + BaseStateWord stateWord_; +}; + +HWTEST_F_L0(WCollectorTest, ForwardObject_WithUnmovedObject_ReturnsSameAddress) +{ + std::unique_ptr wcollector = GetWCollector(); + ASSERT_TRUE(wcollector != nullptr); + + TestableWCollector* testableCollector = reinterpret_cast(wcollector.get()); + + testableCollector->SetCurrentGCPhaseForTest(GCPhase::GC_PHASE_COPY); + EXPECT_EQ(testableCollector->GetCurrentGCPhaseForTest(), GCPhase::GC_PHASE_COPY); +} + } // namespace common::test diff --git a/common_components/mutator/tests/BUILD.gn b/common_components/mutator/tests/BUILD.gn index 442f3c15ab..7b11f5f6fc 100755 --- a/common_components/mutator/tests/BUILD.gn +++ b/common_components/mutator/tests/BUILD.gn @@ -38,6 +38,29 @@ host_unittest_action("Mutator_Manager_Test") { ] } +host_unittest_action("Mutator_Test") { + module_out_path = module_output_path + + sources = [ + # test file + "mutator_test.cpp", + ] + + configs = [ + "//arkcompiler/ets_runtime/common_components:common_components_test_config", + "//arkcompiler/ets_runtime:icu_path_test_config", + ] + + deps = [ "//arkcompiler/ets_runtime/common_components:libark_common_components_test" ] + + # hiviewdfx libraries + external_deps = [ + "icu:shared_icui18n", + "icu:shared_icuuc", + "runtime_core:libarkassembler_static", + ] +} + host_unittest_action("Satb_Buffer_Test") { module_out_path = module_output_path @@ -67,6 +90,8 @@ group("unittest") { # deps file deps = [ ":Mutator_Manager_Test", + ":Mutator_Test", + ":Satb_Buffer_Test", ] } @@ -76,5 +101,7 @@ group("host_unittest") { # deps file deps = [ ":Mutator_Manager_TestAction", + ":Mutator_TestAction", + ":Satb_Buffer_TestAction", ] } diff --git a/common_components/mutator/tests/mutator_manager_test.cpp b/common_components/mutator/tests/mutator_manager_test.cpp index d6a6f79fc2..7704ebdf82 100755 --- a/common_components/mutator/tests/mutator_manager_test.cpp +++ b/common_components/mutator/tests/mutator_manager_test.cpp @@ -78,17 +78,6 @@ HWTEST_F_L0(MutatorManagerTest, CreateMutator_Test1) delete localData->mutator; } -HWTEST_F_L0(MutatorManagerTest, TransitMutatorToExit_Test1) -{ - ThreadLocalData* localData = ThreadLocal::GetThreadLocalData(); - localData->mutator = new Mutator(); - MutatorManager *managerPtr = new MutatorManager(); - localData->mutator->SetInSaferegion(MutatorBase::SaferegionState::SAFE_REGION_FALSE); - managerPtr->TransitMutatorToExit(); - delete managerPtr; - delete localData->mutator; -} - HWTEST_F_L0(MutatorManagerTest, CreateRuntimeMutato_Test1) { ThreadType threadType = ThreadType::FP_THREAD; @@ -100,14 +89,6 @@ HWTEST_F_L0(MutatorManagerTest, CreateRuntimeMutato_Test1) EXPECT_TRUE(ptr != nullptr); } -HWTEST_F_L0(MutatorManagerTest, DumpMutators_Test1) -{ - MutatorManager *managerPtr = new MutatorManager(); - uint32_t timeoutTimes = 1; - managerPtr->DumpMutators(timeoutTimes); - delete managerPtr; -} - HWTEST_F_L0(MutatorManagerTest, DestroyRuntimeMutator_Test1) { ThreadType threadType = ThreadType::GC_THREAD; diff --git a/common_components/mutator/tests/mutator_test.cpp b/common_components/mutator/tests/mutator_test.cpp new file mode 100755 index 0000000000..8835023a52 --- /dev/null +++ b/common_components/mutator/tests/mutator_test.cpp @@ -0,0 +1,243 @@ +/* + * 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/heap_manager.h" +#include "common_components/mutator/mutator.h" +#include "common_components/mutator/mutator_manager.h" +#include "common_components/tests/test_helper.h" +#include "common_interfaces/base_runtime.h" +#include "common_interfaces/objects/base_object.h" + +using namespace common; + +namespace common::test { +class TestMutator : public Mutator { +public: + using Mutator::VisitRawObjects; +}; +class MutatorTest : public BaseTestWithScope { +protected: + static void SetUpTestCase() + { + BaseRuntime::GetInstance()->Init(); + } + static void TearDownTestCase() {} +}; + +HWTEST_F_L0(MutatorTest, GetThreadLocalData_Test1) +{ + ThreadLocalData *ret = GetThreadLocalData(); + ASSERT_TRUE(ret != nullptr); +} + +HWTEST_F_L0(MutatorTest, TransitionGCPhase_Test1) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + bool ret = mutatorBase.TransitionGCPhase(false); + EXPECT_TRUE(ret == true); + + MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE; + mutatorBase.SetSuspensionFlag(flag); + + ret = mutatorBase.TransitionGCPhase(false); + EXPECT_TRUE(ret == true); + + ret = mutatorBase.TransitionGCPhase(true); + EXPECT_TRUE(ret == true); + ret = mutatorBase.TransitionGCPhase(false); + EXPECT_TRUE(ret == true); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test0) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + + MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_STW; + mutatorBase.SetSuspensionFlag(flag); + + mutatorBase.HandleSuspensionRequest(); + EXPECT_TRUE(mutatorBase.InSaferegion() == false); + + flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE; + mutatorBase.SetSuspensionFlag(flag); + mutatorBase.HandleSuspensionRequest(); + EXPECT_TRUE(mutatorBase.InSaferegion() == false); +} + +HWTEST_F_L0(MutatorTest, SuspendForStw_Test0) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + + mutatorBase.SuspendForStw(); + EXPECT_TRUE(mutatorBase.InSaferegion() == false); +} + +HWTEST_F_L0(MutatorTest, VisitRawObjects_Nullptr_NoCall) +{ + TestMutator mutator; + mutator.Init(); + mutator.PushRawObject(nullptr); + + bool called = false; + RootVisitor func = [&called](const ObjectRef& obj) { + called = true; + }; + mutator.VisitRawObjects(func); + EXPECT_FALSE(called); +} + +HWTEST_F_L0(MutatorTest, VisitRawObjects_NonNull_Call) +{ + TestMutator mutator; + mutator.Init(); + BaseObject mockObj; + mutator.PushRawObject(&mockObj); + + bool called = false; + RootVisitor func = [&called, &mockObj](const ObjectRef& obj) { + called = true; + EXPECT_EQ(obj.object, &mockObj); + }; + + mutator.VisitRawObjects(func); + EXPECT_TRUE(called); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test1) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_STW; + mutatorBase.SetSuspensionFlag(flag); + flag = MutatorBase::SuspensionType::SUSPENSION_FOR_GC_PHASE; + mutatorBase.SetSuspensionFlag(flag); + mutatorBase.HandleSuspensionRequest(); + EXPECT_FALSE(mutatorBase.InSaferegion()); + EXPECT_TRUE(mutatorBase.FinishedTransition()); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test2) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_CPU_PROFILE; + mutatorBase.SetSuspensionFlag(flag); + mutatorBase.SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE); + std::thread t([&]() { + std::this_thread::sleep_for(std::chrono::nanoseconds(1)); + mutatorBase.ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE); + }); + mutatorBase.HandleSuspensionRequest(); + t.join(); + EXPECT_FALSE(mutatorBase.InSaferegion()); + EXPECT_TRUE(mutatorBase.FinishedCpuProfile()); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test3) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_STW); + mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE); + mutatorBase.SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE); + std::thread t([&]() { + std::this_thread::sleep_for(std::chrono::nanoseconds(1)); + mutatorBase.ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE); + }); + mutatorBase.HandleSuspensionRequest(); + t.join(); + EXPECT_FALSE(mutatorBase.InSaferegion()); + EXPECT_TRUE(mutatorBase.FinishedCpuProfile()); +} + +HWTEST_F_L0(MutatorTest, HandleGCPhase_SatbNodeNotNull) +{ + Mutator* mutator = MutatorManager::Instance().CreateRuntimeMutator(ThreadType::GC_THREAD); + HeapAddress addr = HeapManager::Allocate(sizeof(BaseObject), AllocType::MOVEABLE_OBJECT, true); + BaseObject *mockObj = reinterpret_cast(addr); + new (mockObj) BaseObject(); + mutator->RememberObjectInSatbBuffer(mockObj); + EXPECT_NE(mutator->GetSatbBufferNode(), nullptr); + MutatorBase* base = static_cast(mutator->GetMutatorBasePtr()); + base->TransitionToGCPhaseExclusive(GCPhase::GC_PHASE_REMARK_SATB); + EXPECT_EQ(mutator->GetSatbBufferNode(), nullptr); + MutatorManager::Instance().DestroyRuntimeMutator(ThreadType::GC_THREAD); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_LeaveSaferegion1) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + mutatorBase.IncObserver(); + std::thread t([&]() { + std::this_thread::sleep_for(std::chrono::nanoseconds(1)); + mutatorBase.DecObserver(); + }); + mutatorBase.HandleSuspensionRequest(); + t.join(); + EXPECT_FALSE(mutatorBase.InSaferegion()); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_LeaveSaferegion2) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + MutatorBase::SuspensionType flag = MutatorBase::SuspensionType::SUSPENSION_FOR_CPU_PROFILE; + mutatorBase.SetSuspensionFlag(flag); + mutatorBase.SetCpuProfileState(MutatorBase::CpuProfileState::FINISH_CPUPROFILE); + mutatorBase.IncObserver(); + std::thread t([&]() { + std::this_thread::sleep_for(std::chrono::nanoseconds(1)); + mutatorBase.ClearSuspensionFlag(MutatorBase::SUSPENSION_FOR_CPU_PROFILE); + mutatorBase.DecObserver(); + }); + mutatorBase.HandleSuspensionRequest(); + t.join(); + EXPECT_FALSE(mutatorBase.InSaferegion()); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test4) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_STW); + mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_GC_PHASE); + EXPECT_NO_FATAL_FAILURE(mutatorBase.HandleSuspensionRequest()); +} + +HWTEST_F_L0(MutatorTest, HandleSuspensionRequest_Test5) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + mutatorBase.SetSuspensionFlag(MutatorBase::SUSPENSION_FOR_FINALIZE); + EXPECT_NO_FATAL_FAILURE(mutatorBase.HandleSuspensionRequest()); +} + +HWTEST_F_L0(MutatorTest, TransitionToGCPhaseExclusive_TestAllBranches) +{ + MutatorBase mutatorBase; + mutatorBase.Init(); + + GCPhase phase = GCPhase::GC_PHASE_ENUM; + EXPECT_NO_FATAL_FAILURE(mutatorBase.TransitionToGCPhaseExclusive(phase)); + phase = GCPhase::GC_PHASE_PRECOPY; + EXPECT_NO_FATAL_FAILURE(mutatorBase.TransitionToGCPhaseExclusive(phase)); + phase = GCPhase::GC_PHASE_IDLE; + EXPECT_NO_FATAL_FAILURE(mutatorBase.TransitionToGCPhaseExclusive(phase)); +} +} // namespace common::test diff --git a/common_components/mutator/tests/satb_buffer_test.cpp b/common_components/mutator/tests/satb_buffer_test.cpp index 1236bb44fd..7fa75c0177 100755 --- a/common_components/mutator/tests/satb_buffer_test.cpp +++ b/common_components/mutator/tests/satb_buffer_test.cpp @@ -13,74 +13,46 @@ * limitations under the License. */ -#include "common_components/base_runtime/base_runtime_param.h" #include "common_components/heap/allocator/region_desc.h" #include "common_components/heap/allocator/region_space.h" #include "common_components/mutator/satb_buffer.h" #include "common_components/tests/test_helper.h" -#include +#include "common_interfaces/base_runtime.h" using namespace common; namespace common::test { class SatbBufferTest : public BaseTestWithScope { -protected: - void* regionMemory_; - size_t totalUnits_ = 1024; - size_t heapSize_; - Mutator* mutator_ = nullptr; - - static void SetUpTestCase() - { - BaseRuntime::GetInstance()->Init(); - } - - static void TearDownTestCase() - { - BaseRuntime::GetInstance()->Fini(); - } - void SetUp() override { - heapSize_ = totalUnits_ * RegionDesc::UNIT_SIZE; - size_t allocSize = heapSize_ + totalUnits_ * sizeof(RegionDesc); - regionMemory_ = malloc(allocSize); - ASSERT_NE(regionMemory_, nullptr); - uintptr_t unitInfoStart = reinterpret_cast(regionMemory_); - RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); - RegionManager& manager = theAllocator.GetRegionManager(); - manager.Initialize(totalUnits_, reinterpret_cast(regionMemory_)); - size_t metadataSize = totalUnits_ * sizeof(RegionDesc); - uintptr_t heapStartAddress = unitInfoStart + metadataSize; - RegionDesc::Initialize(totalUnits_, unitInfoStart, heapStartAddress); - mutator_ = Mutator::NewMutator(); - ASSERT_NE(mutator_, nullptr); - mutator_->InitTid(); - ThreadLocal::GetThreadLocalData()->mutator = mutator_; + BaseRuntime::GetInstance()->Init(); + holder_ = ThreadHolder::CreateAndRegisterNewThreadHolder(nullptr); + scope_ = new ThreadHolder::TryBindMutatorScope(holder_); } void TearDown() override { - if (mutator_) { - delete mutator_; - mutator_ = nullptr; - } - if (regionMemory_) { - free(regionMemory_); - regionMemory_ = nullptr; + if (scope_ != nullptr) { + delete scope_; + scope_ = nullptr; } + + BaseRuntime::GetInstance()->Fini(); } + + ThreadHolder *holder_ {nullptr}; + ThreadHolder::TryBindMutatorScope *scope_ {nullptr}; }; -HWTEST_F_L0(SatbBufferTest, NullptrReturnsFalse)\ +HWTEST_F_L0(SatbBufferTest, NullptrReturnsFalse) { EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(nullptr)); } HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject1) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -94,8 +66,8 @@ HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject1) HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject2) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -109,8 +81,8 @@ HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject2) HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject3) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -124,8 +96,8 @@ HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject3) HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject4) { - ASSERT_NE(mutator_, nullptr); - mutator_->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); + auto* mutator = common::Mutator::GetMutator(); + mutator->SetMutatorPhase(GCPhase::GC_PHASE_ENUM); RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); uintptr_t addr = theAllocator.AllocOldRegion(); ASSERT_NE(addr, 0); @@ -135,4 +107,73 @@ HWTEST_F_L0(SatbBufferTest, IsYoungSpaceObject4) BaseObject* obj = reinterpret_cast(addr); EXPECT_FALSE(SatbBuffer::Instance().ShouldEnqueue(obj)); } + +HWTEST_F_L0(SatbBufferTest, IsMarkedObject) +{ + RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); + uintptr_t addr = theAllocator.AllocRegion(); + ASSERT_NE(addr, 0U); + BaseObject* obj = reinterpret_cast(addr); + Heap::GetHeap().SetGCReason(GC_REASON_HEU); + + RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast(obj)); + region->SetMarkedRegionFlag(1); + + size_t offset = region->GetAddressOffset(reinterpret_cast(obj)); + RegionBitmap* markBitmap = region->GetOrAllocMarkBitmap(); + markBitmap->MarkBits(offset); + + bool result = SatbBuffer::Instance().ShouldEnqueue(obj); + EXPECT_FALSE(result); +} + +void ClearMarkBit(RegionBitmap* bitmap, size_t offset) +{ + uintptr_t* bits = *reinterpret_cast(bitmap); + + size_t wordIndex = offset / (sizeof(uintptr_t) * 8); + size_t bitIndex = offset % (sizeof(uintptr_t) * 8); + + uintptr_t mask = ~(static_cast(1) << bitIndex); + + uintptr_t* addr = const_cast(bits + wordIndex); + uintptr_t oldVal; + uintptr_t newVal; + + do { + oldVal = __atomic_load_n(addr, __ATOMIC_ACQUIRE); + newVal = oldVal & mask; + if (oldVal == newVal) { + return; + } + } while (!__atomic_compare_exchange_n(addr, &oldVal, newVal, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)); +} + +HWTEST_F_L0(SatbBufferTest, EnqueueObject) +{ + RegionSpace& theAllocator = reinterpret_cast(Heap::GetHeap().GetAllocator()); + uintptr_t addr = theAllocator.AllocRegion(); + ASSERT_NE(addr, 0U); + + uintptr_t objAddress = addr + 0x100; + BaseObject* obj = reinterpret_cast(objAddress); + Heap::GetHeap().SetGCReason(GC_REASON_HEU); + + RegionDesc* region = RegionDesc::GetRegionDescAt(reinterpret_cast(obj)); + region->SetRegionType(RegionDesc::RegionType::FROM_REGION); + region->SetTraceLine(); + region->SetMarkedRegionFlag(0); + RegionBitmap* markBitmap = region->GetMarkBitmap(); + size_t offset = region->GetAddressOffset(reinterpret_cast(obj)); + if (markBitmap != nullptr) { + ClearMarkBit(markBitmap, offset); + } + + region->SetEnqueuedRegionFlag(1); + RegionBitmap* enqueueBitmap = region->GetOrAllocEnqueueBitmap(); + enqueueBitmap->MarkBits(offset); + + bool result = SatbBuffer::Instance().ShouldEnqueue(obj); + EXPECT_FALSE(result); +} } // namespace common::test diff --git a/common_components/objects/tests/base_string_test.cpp b/common_components/objects/tests/base_string_test.cpp index ae004c97c0..232e8a1111 100755 --- a/common_components/objects/tests/base_string_test.cpp +++ b/common_components/objects/tests/base_string_test.cpp @@ -14,6 +14,7 @@ */ #include "common_interfaces/objects/base_string.h" +#include "common_components/platform/string_hash.h" #include "common_components/tests/test_helper.h" using namespace common; @@ -22,6 +23,187 @@ namespace common::test { class BaseStringTest : public common::test::BaseTestWithScope { }; +HWTEST_F_L0(BaseStringTest, ComputeHashForData_TEST0) +{ + const uint8_t data[] = {'a', 'b', 'c'}; + size_t size = sizeof(data) / sizeof(data[0]); + uint32_t hashSeed = 0; + uint32_t expectedHash = hashSeed; + for (uint32_t i = 0; i < size; ++i) { + expectedHash = (expectedHash << static_cast(StringHash::HASH_SHIFT)) - expectedHash + data[i]; + } + + EXPECT_EQ(BaseString::ComputeHashForData(data, size, hashSeed), expectedHash); +} + +HWTEST_F_L0(BaseStringTest, ComputeHashForData_TEST1) +{ + std::vector largeData(1000, 'x'); + size_t size = largeData.size(); + uint32_t hashSeed = 0; + + uint32_t result = BaseString::ComputeHashForData(largeData.data(), size, hashSeed); + EXPECT_NE(result, 0); +} + +HWTEST_F_L0(BaseStringTest, ComputeHashcodeUtf8_TEST0) +{ + const uint8_t utf8Data[] = u8"hello"; + size_t utf8Len = sizeof(utf8Data) / sizeof(utf8Data[0]) - 1; + + uint32_t expectedHash = 0; + for (uint32_t i = 0; i < utf8Len; ++i) { + expectedHash = (expectedHash << static_cast(StringHash::HASH_SHIFT)) - expectedHash + utf8Data[i]; + } + + EXPECT_EQ(BaseString::ComputeHashcodeUtf8(utf8Data, utf8Len, true), expectedHash); +} + +HWTEST_F_L0(BaseStringTest, ComputeHashcodeUtf8_TEST1) +{ + const uint8_t utf8Data[] = u8"hello"; + size_t utf8Len = sizeof(utf8Data) / sizeof(utf8Data[0]) - 1; + + uint32_t expectedHash = 0; + for (uint32_t i = 0; i < utf8Len; ++i) { + expectedHash = (expectedHash << static_cast(StringHash::HASH_SHIFT)) - expectedHash + utf8Data[i]; + } + + EXPECT_EQ(BaseString::ComputeHashcodeUtf8(utf8Data, utf8Len, false), expectedHash); +} + +HWTEST_F_L0(BaseStringTest, IsASCIICharacter_TEST0) +{ + const uint16_t num = 0; + bool result = BaseString::IsASCIICharacter(num); + ASSERT_FALSE(result); +} + +HWTEST_F_L0(BaseStringTest, IsASCIICharacter_TEST1) +{ + const uint16_t num = 0x7f; + bool result = BaseString::IsASCIICharacter(num); + ASSERT_TRUE(result); +} + +HWTEST_F_L0(BaseStringTest, CanBeCompressed_TEST0) +{ + uint8_t data[] = {}; + EXPECT_TRUE(BaseString::CanBeCompressed(data, 0)); + + uint8_t data1[] = {1, 1, 1, 1, 0}; + ASSERT_FALSE(BaseString::CanBeCompressed(data1, 5)); + ASSERT_TRUE(BaseString::CanBeCompressed(data1, 2)); + + uint8_t data2[] = {'a', 'b', 'c', 'd'}; + ASSERT_TRUE(BaseString::CanBeCompressed(data2, 4)); + + uint8_t data3[] = {'a', '\0', 'c', 'd'}; + ASSERT_FALSE(BaseString::CanBeCompressed(data3, 4)); +} + +HWTEST_F_L0(BaseStringTest, CanBeCompressed_TEST1) +{ + uint16_t data[] = {}; + EXPECT_TRUE(BaseString::CanBeCompressed(data, 0)); + + uint16_t data1[] = {1, 1, 1, 1, 0}; + ASSERT_FALSE(BaseString::CanBeCompressed(data1, 5)); + ASSERT_TRUE(BaseString::CanBeCompressed(data1, 2)); + + uint16_t data2[] = {'a', 'b', 'c', 'd'}; + ASSERT_TRUE(BaseString::CanBeCompressed(data2, 4)); + + uint16_t data3[] = {'a', '\0', 'c', 'd'}; + ASSERT_FALSE(BaseString::CanBeCompressed(data3, 4)); +} + +HWTEST_F_L0(BaseStringTest, IndexOf_TEST0) +{ + const uint8_t lhs[] = {'a', 'b', 'c', 'd', 'e'}; + const uint8_t rhs[] = {'a', 'b', 'c'}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 3); + + EXPECT_EQ(BaseString::IndexOf(lhsSp, rhsSp, 0, 4), 0); +} + +HWTEST_F_L0(BaseStringTest, IndexOf_TEST1) +{ + const uint8_t lhs[] = {'a', 'b', 'c', 'd', 'e'}; + const uint8_t rhs[] = {'c', 'd'}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 2); + + EXPECT_EQ(BaseString::IndexOf(lhsSp, rhsSp, 0, 4), 2); +} + +HWTEST_F_L0(BaseStringTest, IndexOf_TEST2) +{ + const uint8_t lhs[] = {'a', 'b', 'c', 'd', 'e'}; + const uint8_t rhs[] = {'x', 'y', 'z'}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 3); + + EXPECT_EQ(BaseString::IndexOf(lhsSp, rhsSp, 0, 4), -1); +} + +HWTEST_F_L0(BaseStringTest, IndexOf_TEST3) +{ + const uint8_t lhs[] = {'a', 'b', 'a', 'b', 'c'}; + const uint8_t rhs[] = {'a', 'b', 'c'}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 3); + + EXPECT_EQ(BaseString::IndexOf(lhsSp, rhsSp, 0, 4), 2); +} + +HWTEST_F_L0(BaseStringTest, IndexOf_TEST4) +{ + const uint8_t lhs[] = {'a', 'b', 'c', 'd', 'e'}; + const uint8_t rhs[] = {'a', 'b', 'x'}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 3); + + EXPECT_EQ(BaseString::IndexOf(lhsSp, rhsSp, 0, 4), -1); +} + +HWTEST_F_L0(BaseStringTest, CompareStringSpan_TEST0) +{ + const uint8_t lhs[] = {1, 2, 3}; + const uint8_t rhs[] = {1, 2, 3}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 3); + EXPECT_EQ(CompareStringSpan(lhsSp, rhsSp, 3), 0); +} + +HWTEST_F_L0(BaseStringTest, CompareStringSpan_TEST1) +{ + const uint8_t lhs[] = {1, 2, 4}; + const uint8_t rhs[] = {1, 2, 3}; + Span lhsSp(lhs, 5); + Span rhsSp(rhs, 3); + EXPECT_EQ(CompareStringSpan(lhsSp, rhsSp, 3), 1); +} + +HWTEST_F_L0(BaseStringTest, IsSubStringAtSpan_TEST1) +{ + const uint8_t lhs[] = {'a', 'b', 'c'}; + const uint8_t rhs[] = {'x', 'y'}; + Span lhsSp(lhs, 3); + Span rhsSp(rhs, 2); + ASSERT_FALSE(IsSubStringAtSpan(lhsSp, rhsSp, 1)); +} + +HWTEST_F_L0(BaseStringTest, IsSubStringAtSpan_TEST2) +{ + const uint8_t lhs[] = {'a', 'b'}; + const uint8_t rhs[] = {'b'}; + Span lhsSp(lhs, 2); + Span rhsSp(rhs, 1); + ASSERT_TRUE(IsSubStringAtSpan(lhsSp, rhsSp, 1)); +} + HWTEST_F_L0(BaseStringTest, IsUtf8EqualsUtf16_TEST0) { const uint8_t utf8_01[] = {0xF0, 0xE0, 0xC0}; -- Gitee