From c5edc3db6494d645a16700cedb6f690a80536e2a Mon Sep 17 00:00:00 2001 From: yangxiaoshuai2022 Date: Wed, 13 Aug 2025 11:40:16 +0800 Subject: [PATCH] mixed hash in nodeId Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICSS9A Signed-off-by: yangxiaoshuai2022 --- .../dfx/hprof/heap_profiler_interface.h | 1 + ecmascript/dfx/hprof/rawheap_dump.cpp | 18 +++- ecmascript/dfx/hprof/rawheap_dump.h | 1 + ecmascript/dfx/hprof/tests/heap_dump_test.cpp | 82 ++++++++++++++++--- 4 files changed, 91 insertions(+), 11 deletions(-) diff --git a/ecmascript/dfx/hprof/heap_profiler_interface.h b/ecmascript/dfx/hprof/heap_profiler_interface.h index 511c6793d2..ca1aac2ea7 100644 --- a/ecmascript/dfx/hprof/heap_profiler_interface.h +++ b/ecmascript/dfx/hprof/heap_profiler_interface.h @@ -37,6 +37,7 @@ struct DumpSnapShotOption { bool isSync = true; // OOM and Ide dump need sync dump. bool isBeforeFill = true; // whether do fillmap on main thread. bool isDumpOOM = false; // whether dump oom heapdump. + bool isJSLeakWatcher = false; // whether dump from jsleak wather. }; enum class RawHeapDumpCropLevel { diff --git a/ecmascript/dfx/hprof/rawheap_dump.cpp b/ecmascript/dfx/hprof/rawheap_dump.cpp index adbef17fb8..c773a16750 100644 --- a/ecmascript/dfx/hprof/rawheap_dump.cpp +++ b/ecmascript/dfx/hprof/rawheap_dump.cpp @@ -88,6 +88,7 @@ RawHeapDump::RawHeapDump(const EcmaVM *vm, Stream *stream, HeapSnapshot *snapsho : vm_(vm), writer_(stream), snapshot_(snapshot), entryIdMap_(entryIdMap) { isOOM_ = dumpOption.isDumpOOM; + isJSLeakWatcher_ = dumpOption.isJSLeakWatcher; startTime_ = std::chrono::steady_clock::now(); } @@ -145,9 +146,24 @@ void RawHeapDump::DumpSectionIndex() LOG_ECMA(INFO) << "rawheap dump, section count " << secIndexVec_.size(); } +/* +* mixed hash in NodeId, for example: +* |----------------- uint64_t -----------------| +* |-----high-32-bits-----|----lower-32-bits----| +* |--------------------------------------------| +* | hash | nodeId & 0xFFFFFFFF | +* |--------------------------------------------| +*/ NodeId RawHeapDump::GenerateNodeId(JSTaggedType addr) { - return isOOM_ ? entryIdMap_->GetNextId() : entryIdMap_->FindOrInsertNodeId(addr); + NodeId nodeId = isOOM_ ? entryIdMap_->GetNextId() : entryIdMap_->FindOrInsertNodeId(addr); + if (!isJSLeakWatcher_) { + return nodeId; + } + + JSTaggedValue value {addr}; + uint64_t hash = value.IsJSObject() ? JSObject::Cast(value)->GetHash(vm_->GetJSThread()) : 0; + return (hash << 32) | (nodeId & 0xFFFFFFFF); // 32: 32-bits means a half of uint64_t } void RawHeapDump::WriteChunk(char *data, size_t size) diff --git a/ecmascript/dfx/hprof/rawheap_dump.h b/ecmascript/dfx/hprof/rawheap_dump.h index bf13399f17..a1f9cfe565 100644 --- a/ecmascript/dfx/hprof/rawheap_dump.h +++ b/ecmascript/dfx/hprof/rawheap_dump.h @@ -87,6 +87,7 @@ private: uint32_t fileOffset_ {0}; uint32_t preOffset_ {0}; bool isOOM_ {false}; + bool isJSLeakWatcher_ {false}; std::chrono::time_point startTime_; }; diff --git a/ecmascript/dfx/hprof/tests/heap_dump_test.cpp b/ecmascript/dfx/hprof/tests/heap_dump_test.cpp index fae9742908..577780c479 100644 --- a/ecmascript/dfx/hprof/tests/heap_dump_test.cpp +++ b/ecmascript/dfx/hprof/tests/heap_dump_test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include "ecmascript/base/number_helper.h" #include "ecmascript/dfx/hprof/heap_snapshot.h" #include "ecmascript/dfx/hprof/heap_profiler.h" #include "ecmascript/dfx/hprof/heap_root_visitor.h" @@ -102,14 +103,11 @@ public: return heapProfile->GetIdCount(); } - bool GenerateRawHeapSnashot(const std::string &filePath, DumpFormat dumpFormat = DumpFormat::BINARY, - bool isSync = true, Progress *progress = nullptr, - std::function callback = [] (uint8_t) {}) + bool GenerateRawHeapSnashot(const std::string &filePath, DumpSnapShotOption &dumpOption, + Progress *progress = nullptr, std::function callback = [] (uint8_t) {}) { HeapProfilerInterface *heapProfile = HeapProfilerInterface::GetInstance(instance); - DumpSnapShotOption dumpOption; - dumpOption.dumpFormat = dumpFormat; - dumpOption.isSync = isSync; + dumpOption.dumpFormat = DumpFormat::BINARY; dumpOption.isDumpOOM = true; dumpOption.isFullGC = false; fstream outputString(filePath, std::ios::out); @@ -139,6 +137,42 @@ public: return true; } + bool CheckHashInNodeId(JSThread *thread, const std::vector &refs, const std::string &filePath) + { + uint64_t fileSize = rawheap_translate::FileReader::GetFileSize(filePath); + rawheap_translate::FileReader file; + rawheap_translate::RawHeapTranslateV1 translate(nullptr); + if (!file.Initialize(filePath) || !translate.Parse(file, fileSize)) { + return false; + } + + int checkCnt = 0; + for (auto const &ref : refs) { + if (!ref.value_.IsJSObject()) { + continue; + } + + auto it = translate.nodesMap_.find(ref.value_.GetRawData()); + if (it == translate.nodesMap_.end()) { + std::cout << "CheckHashInNodeId, missed object in rawheap." << std::endl; + return false; + } + + ++checkCnt; + // 32: 32-bits means a half of uint64_t + if (JSObject::Cast(ref.value_)->GetHash(thread) != static_cast(it->second->nodeId >> 32)) { + std::cout << "CheckHashInNodeId, hash value verification failed!" << std::endl; + return false; + } + } + + if (checkCnt == 0) { + std::cout << "CheckHashInNodeId, no JSObject." << std::endl; + return false; + } + return true; + } + bool DecodeRawHeapObjectTableV2(std::string &filePath, CSet &result) { uint64_t fileSize = rawheap_translate::FileReader::GetFileSize(filePath); @@ -1541,7 +1575,8 @@ HWTEST_F_L0(HeapDumpTest, TestHeapDumpBinaryDumpV0) CreateObjectsForBinaryDump(thread_, factory, &tester, vec); std::string rawHeapPath("test_binary_dump_v0.rawheap"); - ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath)); + DumpSnapShotOption dumpOption; + ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath, dumpOption)); FILE* file = std::fopen(rawHeapPath.c_str(), "rb+"); ASSERT_TRUE(file != nullptr); @@ -1565,7 +1600,8 @@ HWTEST_F_L0(HeapDumpTest, TestHeapDumpBinaryDumpV1) CreateObjectsForBinaryDump(thread_, factory, &tester, vec); std::string rawHeapPath("test_binary_dump_v1.rawheap"); - ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath)); + DumpSnapShotOption dumpOption; + ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath, dumpOption)); CSet dumpObjects; ASSERT_TRUE(tester.DecodeRawHeapObjectTableV1(rawHeapPath, dumpObjects)); @@ -1586,7 +1622,8 @@ HWTEST_F_L0(HeapDumpTest, TestHeapDumpBinaryDumpV2) std::string rawHeapPath("test_binary_dump_v2.rawheap"); Runtime::GetInstance()->SetRawHeapDumpCropLevel(RawHeapDumpCropLevel::LEVEL_V2); - ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath)); + DumpSnapShotOption dumpOption; + ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath, dumpOption)); CSet dumpObjects; ASSERT_TRUE(tester.DecodeRawHeapObjectTableV2(rawHeapPath, dumpObjects)); @@ -1613,9 +1650,34 @@ HWTEST_F_L0(HeapDumpTest, TestHeapDumpBinaryDumpByForkWithCallback) status = false; } }; - ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath, DumpFormat::BINARY, false, nullptr, cb)); + DumpSnapShotOption dumpOption; + dumpOption.isSync = false; + ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath, dumpOption, nullptr, cb)); ASSERT_TRUE(status); } + +HWTEST_F_L0(HeapDumpTest, TestGenerateMixedNodeId) +{ + ObjectFactory *factory = ecmaVm_->GetFactory(); + HeapDumpTestHelper tester(ecmaVm_); + std::vector vec; + CreateObjectsForBinaryDump(thread_, factory, &tester, vec); + + for (auto ref : vec) { + if (ref.value_.IsJSObject()) { + int32_t hash = base::RandomGenerator::GenerateIdentityHash(); + JSHandle ecmaObj(thread_, ref.value_); + ECMAObject::SetHash(thread_, hash, ecmaObj); + } + } + + std::string rawHeapPath("test_binary_dump_for_mixed_node_id.rawheap"); + DumpSnapShotOption dumpOption; + dumpOption.isSync = false; + dumpOption.isJSLeakWatcher = true; + ASSERT_TRUE(tester.GenerateRawHeapSnashot(rawHeapPath, dumpOption)); + ASSERT_TRUE(tester.CheckHashInNodeId(thread_, vec, rawHeapPath)); +} #endif HWTEST_F_L0(HeapDumpTest, TestSharedFullGCInHeapDump) -- Gitee