• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "common_components/heap/heap.h"
17 #include "ecmascript/base/config.h"
18 #include "ecmascript/dfx/hprof/rawheap_dump.h"
19 #include "ecmascript/dfx/hprof/rawheap_translate/common.h"
20 #include "ecmascript/object_fast_operator-inl.h"
21 
22 namespace panda::ecmascript {
VisitRoot(Root type,ObjectSlot slot)23 void ObjectMarker::VisitRoot([[maybe_unused]]Root type, ObjectSlot slot)
24 {
25     JSTaggedValue value(slot.GetTaggedType());
26     if (value.IsHeapObject()) {
27         MarkObject(slot.GetTaggedType());
28     }
29 }
30 
VisitRangeRoot(Root type,ObjectSlot start,ObjectSlot end)31 void ObjectMarker::VisitRangeRoot(Root type, ObjectSlot start, ObjectSlot end)
32 {
33     for (ObjectSlot slot = start; slot < end; slot++) {
34         VisitRoot(type, slot);
35     }
36 }
37 
VisitBaseAndDerivedRoot(Root type,ObjectSlot base,ObjectSlot derived,uintptr_t baseOldObject)38 void ObjectMarker::VisitBaseAndDerivedRoot(Root type, ObjectSlot base, ObjectSlot derived, uintptr_t baseOldObject)
39 {
40 }
41 
VisitObjectRangeImpl(BaseObject * root,uintptr_t start,uintptr_t endAddr,VisitObjectArea area)42 void ObjectMarker::VisitObjectRangeImpl([[maybe_unused]]BaseObject *root, uintptr_t start,
43                                         uintptr_t endAddr, [[maybe_unused]]VisitObjectArea area)
44 {
45     ObjectSlot end(endAddr);
46     for (ObjectSlot slot(start); slot < end; slot++) {
47         JSTaggedValue value(slot.GetTaggedType());
48         if (value.GetRawData() != 0 && value.IsHeapObject() && !value.IsWeak()) {
49             MarkObject(slot.GetTaggedType());
50         }
51     }
52 }
53 
ProcessMarkObjectsFromRoot()54 void ObjectMarker::ProcessMarkObjectsFromRoot()
55 {
56     while (!bfsQueue_.empty()) {
57         JSTaggedType addr = bfsQueue_.front();
58         bfsQueue_.pop();
59 
60         JSTaggedValue value(addr);
61         TaggedObject *object = value.GetTaggedObject();
62         JSHClass *hclass = object->GetClass();
63         MarkObject(reinterpret_cast<JSTaggedType>(hclass));
64         if (hclass->IsString()) {
65             continue;
66         }
67         ObjectXRay::VisitObjectBody<VisitType::OLD_GC_VISIT>(object, hclass, *this);
68     }
69 }
70 
IterateMarkedObjects(const std::function<void (JSTaggedType)> & visitor)71 void ObjectMarker::IterateMarkedObjects(const std::function<void(JSTaggedType)> &visitor)
72 {
73     for (auto addr : markedObjects_) {
74         visitor(addr);
75     }
76 }
77 
MarkObject(JSTaggedType addr)78 void ObjectMarker::MarkObject(JSTaggedType addr)
79 {
80     if (Mark(addr)) {
81         markedObjects_.push_back(addr);
82         bfsQueue_.push(addr);
83     }
84 }
85 
RawHeapDump(const EcmaVM * vm,Stream * stream,HeapSnapshot * snapshot,EntryIdMap * entryIdMap,const DumpSnapShotOption & dumpOption)86 RawHeapDump::RawHeapDump(const EcmaVM *vm, Stream *stream, HeapSnapshot *snapshot,
87                          EntryIdMap *entryIdMap, const DumpSnapShotOption &dumpOption)
88     : vm_(vm), writer_(stream), snapshot_(snapshot), entryIdMap_(entryIdMap)
89 {
90     isOOM_ = dumpOption.isDumpOOM;
91     isJSLeakWatcher_ = dumpOption.isJSLeakWatcher;
92     startTime_ = std::chrono::steady_clock::now();
93 }
94 
~RawHeapDump()95 RawHeapDump::~RawHeapDump()
96 {
97     writer_.EndOfWriteBinBlock();
98     secIndexVec_.clear();
99     auto endTime = std::chrono::steady_clock::now();
100     double duration = std::chrono::duration<double>(endTime - startTime_).count();
101     LOG_ECMA(INFO) << "rawheap dump success, cost " << duration << "s, " << "file size " << GetRawHeapFileOffset();
102 }
103 
MarkRootForDump(ObjectMarker & marker)104 void RawHeapDump::MarkRootForDump(ObjectMarker &marker)
105 {
106     if (g_isEnableCMCGC) {
107         common::RefFieldVisitor visitor = [&marker](common::RefField<>& refField) {
108             BaseObject *oldObj = refField.GetTargetObject();
109             marker.MarkObject(reinterpret_cast<JSTaggedType>(oldObj));
110         };
111         common::VisitRoots(visitor);
112     } else {
113         HeapRootVisitor rootVisitor;
114         rootVisitor.VisitHeapRoots(vm_->GetAssociatedJSThread(), marker);
115         SharedModuleManager::GetInstance()->Iterate(marker);
116         Runtime::GetInstance()->IterateCachedStringRoot(marker);
117     }
118 }
119 
MarkHeapObjectForDump(ObjectMarker & marker)120 void RawHeapDump::MarkHeapObjectForDump(ObjectMarker &marker)
121 {
122     marker.ProcessMarkObjectsFromRoot();
123     LOG_ECMA(INFO) << "rawheap dump, marked objects count " << marker.Count();
124 }
125 
DumpVersion(const std::string & version)126 void RawHeapDump::DumpVersion(const std::string &version)
127 {
128     char versionId[8];  // 8: means the size of rawheap version
129     if (strcpy_s(versionId, sizeof(versionId), version.c_str()) != 0) {
130         LOG_ECMA(ERROR) << "rawheap dump, version id strcpy_s failed!";
131         return;
132     }
133     WriteChunk(versionId, sizeof(versionId));
134 
135     char timeStamp[8];  // 8: means the size of current timestamp
136     *reinterpret_cast<uint64_t *>(timeStamp) = std::chrono::system_clock::now().time_since_epoch().count();
137     WriteChunk(timeStamp, sizeof(timeStamp));
138     LOG_ECMA(INFO) << "rawheap dump, version " << version;
139 }
140 
DumpSectionIndex()141 void RawHeapDump::DumpSectionIndex()
142 {
143     AddSectionRecord(secIndexVec_.size());
144     AddSectionRecord(sizeof(uint32_t));
145     WriteChunk(reinterpret_cast<char *>(secIndexVec_.data()), secIndexVec_.size() * sizeof(uint32_t));
146     LOG_ECMA(INFO) << "rawheap dump, section count " << secIndexVec_.size();
147 }
148 
149 /*
150 * mixed hash in NodeId, for example:
151 * |----------------- uint64_t -----------------|
152 * |-----high-32-bits-----|----lower-32-bits----|
153 * |--------------------------------------------|
154 * |         hash         | nodeId & 0xFFFFFFFF |
155 * |--------------------------------------------|
156 */
GenerateNodeId(JSTaggedType addr)157 NodeId RawHeapDump::GenerateNodeId(JSTaggedType addr)
158 {
159     NodeId nodeId = isOOM_ ? entryIdMap_->GetNextId() : entryIdMap_->FindOrInsertNodeId(addr);
160     if (!isJSLeakWatcher_) {
161         return nodeId;
162     }
163 
164     JSTaggedValue value {addr};
165     uint64_t hash = value.IsJSObject() ? JSObject::Cast(value)->GetHash(vm_->GetJSThread()) : 0;
166     return (hash << 32) | (nodeId & 0xFFFFFFFF);  // 32: 32-bits means a half of uint64_t
167 }
168 
WriteChunk(char * data,size_t size)169 void RawHeapDump::WriteChunk(char *data, size_t size)
170 {
171     writer_.WriteBinBlock(data, size);
172 }
173 
WriteU64(uint64_t value)174 void RawHeapDump::WriteU64(uint64_t value)
175 {
176     writer_.WriteUInt64(value);
177 }
178 
WriteU32(uint32_t value)179 void RawHeapDump::WriteU32(uint32_t value)
180 {
181     writer_.WriteUInt32(value);
182 }
183 
WriteU16(uint16_t value)184 void RawHeapDump::WriteU16(uint16_t value)
185 {
186     writer_.WriteUInt16(value);
187 }
188 
WriteU8(uint8_t value)189 void RawHeapDump::WriteU8(uint8_t value)
190 {
191     writer_.WriteUInt8(value);
192 }
193 
WriteHeader(uint32_t offset,uint32_t size)194 void RawHeapDump::WriteHeader(uint32_t offset, uint32_t size)
195 {
196     uint32_t header[2] = {offset, size};
197     WriteChunk(reinterpret_cast<char *>(header), sizeof(header));
198 }
199 
WritePadding()200 void RawHeapDump::WritePadding()
201 {
202     uint32_t padding = (8 - fileOffset_ % 8) % 8;
203     if (padding > 0) {
204         char pad[8] = {0};
205         WriteChunk(pad, padding);
206     }
207 }
208 
AddSectionRecord(uint32_t value)209 void RawHeapDump::AddSectionRecord(uint32_t value)
210 {
211     secIndexVec_.push_back(value);
212 }
213 
AddSectionOffset()214 void RawHeapDump::AddSectionOffset()
215 {
216     secIndexVec_.push_back(GetRawHeapFileOffset());
217     preOffset_ = GetRawHeapFileOffset();
218 }
219 
AddSectionBlockSize()220 void RawHeapDump::AddSectionBlockSize()
221 {
222     secIndexVec_.push_back(GetRawHeapFileOffset() - preOffset_);
223 }
224 
GenerateStringId(TaggedObject * object)225 StringId RawHeapDump::GenerateStringId(TaggedObject *object)
226 {
227     JSTaggedValue entry(object);
228     JSThread *thread = vm_->GetAssociatedJSThread();
229 
230     if (entry.IsOnlyJSObject()) {
231         const GlobalEnvConstants *globalConst = thread->GlobalConstants();
232         bool isCallGetter = false;
233         JSHandle<JSTaggedValue> contructorKey = globalConst->GetHandledConstructorString();
234         JSTaggedValue objConstructor = ObjectFastOperator::GetPropertyByName(thread, entry,
235                                                                              contructorKey.GetTaggedValue(), true,
236                                                                              &isCallGetter);
237         auto it = objectStrIds_.find(objConstructor.GetRawData());
238         if (it != objectStrIds_.end()) {
239             return it->second;
240         }
241         StringId strId = snapshot_->GenerateStringId(object);
242         objectStrIds_.emplace(objConstructor.GetRawData(), strId);
243         return strId;
244     }
245 
246     if (entry.IsJSFunction()) {
247         JSFunctionBase *func = JSFunctionBase::Cast(object);
248         Method *method = Method::Cast(func->GetMethod(thread).GetTaggedObject());
249         auto it = functionStrIds_.find(method);
250         if (it != functionStrIds_.end()) {
251             return it->second;
252         }
253         StringId strId = snapshot_->GenerateStringId(object);
254         functionStrIds_.emplace(method, strId);
255         return strId;
256     }
257 
258     return 1;  // 1 : invalid id
259 }
260 
GetEcmaStringTable()261 const StringHashMap *RawHeapDump::GetEcmaStringTable()
262 {
263     return snapshot_->GetEcmaStringTable();
264 }
265 
RawHeapDumpV1(const EcmaVM * vm,Stream * stream,HeapSnapshot * snapshot,EntryIdMap * entryIdMap,const DumpSnapShotOption & dumpOption)266 RawHeapDumpV1::RawHeapDumpV1(const EcmaVM *vm, Stream *stream, HeapSnapshot *snapshot,
267                              EntryIdMap *entryIdMap, const DumpSnapShotOption &dumpOption)
268     : RawHeapDump(vm, stream, snapshot, entryIdMap, dumpOption)
269 {
270 }
271 
~RawHeapDumpV1()272 RawHeapDumpV1::~RawHeapDumpV1()
273 {
274     strIdMapObjVec_.clear();
275 }
276 
277 /*
278  *  |--4 bytes--|--4 bytes--|
279  *  |-----------------------|
280  *  |       versionId       |
281  *  |-----------------------|
282  *  |       timestamp       |
283  *  |-----------------------|
284  *  |  rootCnt  |  rootUnit |
285  *  |-----------------------|
286  *  |                       |
287  *  |                       |
288  *  |-----------------------|
289  *  | stringCnt | 0(unused) |
290  *  |-----------------------|
291  *  |                       |
292  *  |                       |
293  *  |-----------------------|
294  *  |objTotalCnt| tableUnit |
295  *  |-----------------------|
296  *  |                       |
297  *  |                       |
298  *  |-----------------------|
299  *  | rootOffset|  rootSize |
300  *  |-----------------------|
301  *  | strOffset |  strSize  |
302  *  |-----------------------|
303  *  | objOffset |  objSize  |
304  *  |-----------------------|
305 */
BinaryDump()306 void RawHeapDumpV1::BinaryDump()
307 {
308     DumpVersion(std::string(RAWHEAP_VERSION));
309 
310     ObjectMarker marker;
311     MarkRootForDump(marker);
312     DumpRootTable(marker);
313 
314     MarkHeapObjectForDump(marker);
315     DumpStringTable(marker);
316     DumpObjectTable(marker);
317     DumpObjectMemory(marker);
318     DumpSectionIndex();
319 }
320 
DumpRootTable(ObjectMarker & marker)321 void RawHeapDumpV1::DumpRootTable(ObjectMarker &marker)
322 {
323     AddSectionOffset();
324     WriteHeader(marker.Count(), sizeof(JSTaggedType));
325     marker.IterateMarkedObjects([this](JSTaggedType addr) {
326         WriteU64(addr);
327     });
328     AddSectionBlockSize();
329     LOG_ECMA(INFO) << "rawheap dump, root count " << marker.Count();
330 }
331 
DumpStringTable(ObjectMarker & marker)332 void RawHeapDumpV1::DumpStringTable(ObjectMarker &marker)
333 {
334     UpdateStringTable(marker);
335     auto strTable = GetEcmaStringTable();
336     AddSectionOffset();
337     WriteHeader(strTable->GetCapcity(), 0);
338     for (auto key : strTable->GetOrderedKeyStorage()) {
339         auto [strId, str] = strTable->GetStringAndIdPair(key);
340         auto objVec = strIdMapObjVec_[strId];
341         WriteHeader(str->size(), objVec.size());
342         WriteChunk(reinterpret_cast<char *>(objVec.data()), objVec.size() * sizeof(JSTaggedType));
343         WriteChunk(const_cast<char *>(str->c_str()), str->size() + 1);
344     }
345 
346     WritePadding();
347     AddSectionBlockSize();
348     LOG_ECMA(INFO) << "rawheap dump, string table capcity " << strTable->GetCapcity();
349 }
350 
DumpObjectTable(ObjectMarker & marker)351 void RawHeapDumpV1::DumpObjectTable(ObjectMarker &marker)
352 {
353     AddSectionOffset();
354     WriteHeader(marker.Count(), sizeof(AddrTableItem));
355     uint32_t memOffset = marker.Count() * sizeof(AddrTableItem);
356     marker.IterateMarkedObjects([this, &memOffset](JSTaggedType addr) {
357         TaggedObject *obj = reinterpret_cast<TaggedObject *>(addr);
358         AddrTableItem table = { addr, GenerateNodeId(addr), obj->GetSize(), memOffset };
359         if (obj->GetClass()->IsString()) {
360             memOffset += sizeof(JSHClass *);
361         } else {
362             memOffset += table.objSize;
363         }
364         WriteChunk(reinterpret_cast<char *>(&table), sizeof(AddrTableItem));
365     });
366     LOG_ECMA(INFO) << "rawheap dump, objects total count " << marker.Count();
367 }
368 
DumpObjectMemory(ObjectMarker & marker)369 void RawHeapDumpV1::DumpObjectMemory(ObjectMarker &marker)
370 {
371     uint32_t memSize = 0;
372     marker.IterateMarkedObjects([this, &memSize](JSTaggedType addr) {
373         auto obj = reinterpret_cast<TaggedObject *>(addr);
374         size_t size = obj->GetSize();
375         memSize += size;
376         if (obj->GetClass()->IsString()) {
377             size = sizeof(JSHClass *);
378         }
379         if (g_isEnableCMCGC) {
380             WriteU64(reinterpret_cast<JSTaggedType>(obj->GetClass()));
381             WriteChunk(reinterpret_cast<char *>(addr + sizeof(JSTaggedType)), size - sizeof(JSTaggedType));
382         } else {
383             WriteChunk(reinterpret_cast<char *>(addr), size);
384         }
385     });
386     AddSectionBlockSize();
387     LOG_ECMA(INFO) << "rawheap dump, objects memory size " << memSize;
388 }
389 
UpdateStringTable(ObjectMarker & marker)390 void RawHeapDumpV1::UpdateStringTable(ObjectMarker &marker)
391 {
392     uint32_t strCnt = 0;
393     marker.IterateMarkedObjects([&strCnt, this](JSTaggedType addr) {
394         JSTaggedValue value(addr);
395         StringId strId = GenerateStringId(value.GetTaggedObject());
396         if (strId == 1) {  // 1 : invalid str id
397             return;
398         }
399         ++strCnt;
400         auto vec = strIdMapObjVec_.find(strId);
401         if (vec != strIdMapObjVec_.end()) {
402             vec->second.push_back(addr);
403         } else {
404             CVector<uint64_t> objVec;
405             objVec.push_back(addr);
406             strIdMapObjVec_.emplace(strId, objVec);
407         }
408     });
409     LOG_ECMA(INFO) << "rawheap dump, update string table count " << strCnt;
410 }
411 
RawHeapDumpV2(const EcmaVM * vm,Stream * stream,HeapSnapshot * snapshot,EntryIdMap * entryIdMap,const DumpSnapShotOption & dumpOption)412 RawHeapDumpV2::RawHeapDumpV2(const EcmaVM *vm, Stream *stream, HeapSnapshot *snapshot,
413                              EntryIdMap *entryIdMap, const DumpSnapShotOption &dumpOption)
414     : RawHeapDump(vm, stream, snapshot, entryIdMap, dumpOption)
415 {
416 }
417 
~RawHeapDumpV2()418 RawHeapDumpV2::~RawHeapDumpV2()
419 {
420     regionIdMap_.clear();
421 }
422 
BinaryDump()423 void RawHeapDumpV2::BinaryDump()
424 {
425     DumpVersion(std::string(RAWHEAP_VERSION_V2));
426 
427     ObjectMarker marker;
428     MarkRootForDump(marker);
429     DumpRootTable(marker);
430 
431     MarkHeapObjectForDump(marker);
432     DumpStringTable(marker);
433     DumpObjectTable(marker);
434     DumpObjectMemory(marker);
435     DumpSectionIndex();
436 }
437 
DumpRootTable(ObjectMarker & marker)438 void RawHeapDumpV2::DumpRootTable(ObjectMarker &marker)
439 {
440     AddSectionOffset();
441     WriteHeader(marker.Count(), sizeof(uint32_t));
442     marker.IterateMarkedObjects([this](JSTaggedType addr) {
443         WriteU32(GenerateSyntheticAddr(addr));
444     });
445     AddSectionBlockSize();
446     LOG_ECMA(INFO) << "rawheap dump, root count " << marker.Count();
447 }
448 
DumpStringTable(ObjectMarker & marker)449 void RawHeapDumpV2::DumpStringTable(ObjectMarker &marker)
450 {
451     UpdateStringTable(marker);
452     auto strTable = GetEcmaStringTable();
453     AddSectionOffset();
454     WriteHeader(strTable->GetCapcity(), 0);
455     for (auto key : strTable->GetOrderedKeyStorage()) {
456         auto [strId, str] = strTable->GetStringAndIdPair(key);
457         auto objVec = strIdMapObjVec_[strId];
458         WriteHeader(str->size(), objVec.size());
459         WriteChunk(reinterpret_cast<char *>(objVec.data()), objVec.size() * sizeof(uint32_t));
460         WriteChunk(const_cast<char *>(str->c_str()), str->size() + 1);
461     }
462 
463     WritePadding();
464     AddSectionBlockSize();
465     LOG_ECMA(INFO) << "rawheap dump, string table capcity " << strTable->GetCapcity();
466 }
467 
DumpObjectTable(ObjectMarker & marker)468 void RawHeapDumpV2::DumpObjectTable(ObjectMarker &marker)
469 {
470     AddSectionOffset();
471     WriteHeader(marker.Count(), sizeof(AddrTableItem));
472     uint32_t memOffset = marker.Count() * sizeof(AddrTableItem);
473     marker.IterateMarkedObjects([this, &memOffset](JSTaggedType addr) {
474         TaggedObject *obj = reinterpret_cast<TaggedObject *>(addr);
475         AddrTableItem table = {
476             GenerateSyntheticAddr(addr),
477             obj->GetSize(),
478             GenerateNodeId(addr),
479             obj->GetClass()->IsJSNativePointer() ? JSNativePointer::Cast(obj)->GetBindingSize() : 0,
480             static_cast<uint32_t>(obj->GetClass()->GetObjectType())
481         };
482         WriteChunk(reinterpret_cast<char *>(&table), sizeof(AddrTableItem));
483     });
484     LOG_ECMA(INFO) << "rawheap dump, objects total count " << marker.Count();
485 }
486 
DumpObjectMemory(ObjectMarker & marker)487 void RawHeapDumpV2::DumpObjectMemory(ObjectMarker &marker)
488 {
489     uint32_t memSize = 0;
490     marker.IterateMarkedObjects([this, &memSize](JSTaggedType addr) {
491         TaggedObject *object = reinterpret_cast<TaggedObject *>(addr);
492         memSize += object->GetSize();
493 
494         WriteU32(GenerateSyntheticAddr(reinterpret_cast<JSTaggedType>(object->GetClass())));
495         if (object->GetClass()->IsString()) {
496             return;
497         }
498         ObjectSlot end(static_cast<uintptr_t>(addr + object->GetSize()));
499         ObjectSlot slot(static_cast<uintptr_t>(addr + sizeof(JSTaggedType)));
500         for (; slot < end; slot++) {
501             JSTaggedValue value(slot.GetTaggedType());
502             if (value.GetRawData() != 0 && value.IsHeapObject() && !value.IsWeak()) {
503                 WriteU32(GenerateSyntheticAddr(value.GetRawData()));
504             } else {
505                 WriteU8(rawheap_translate::ZERO_VALUE);
506             }
507         }
508     });
509     AddSectionBlockSize();
510     LOG_ECMA(INFO) << "rawheap dump, objects memory size " << memSize;
511 }
512 
UpdateStringTable(ObjectMarker & marker)513 void RawHeapDumpV2::UpdateStringTable(ObjectMarker &marker)
514 {
515     uint32_t strCnt = 0;
516     marker.IterateMarkedObjects([&strCnt, this](JSTaggedType addr) {
517         uint32_t syntheticAddr = GenerateSyntheticAddr(addr);
518         StringId strId = GenerateStringId(reinterpret_cast<TaggedObject *>(addr));
519         if (strId == 1) {  // 1 : invalid str id
520             return;
521         }
522         ++strCnt;
523         auto vec = strIdMapObjVec_.find(strId);
524         if (vec != strIdMapObjVec_.end()) {
525             vec->second.push_back(syntheticAddr);
526         } else {
527             CVector<uint32_t> objVec;
528             objVec.push_back(syntheticAddr);
529             strIdMapObjVec_.emplace(strId, objVec);
530         }
531     });
532     LOG_ECMA(INFO) << "rawheap dump, update string table count " << strCnt;
533 }
534 
GenerateRegionId(JSTaggedType addr)535 uint32_t RawHeapDumpV2::GenerateRegionId(JSTaggedType addr)
536 {
537     Region *region = Region::ObjectAddressToRange(addr);
538     auto [it, inserted] = regionIdMap_.try_emplace(region, regionId_);
539     if (inserted) {
540         regionId_ += sizeof(JSTaggedType);
541     }
542     return it->second;
543 }
544 
545 /* ------------------------------
546  * |  regionId  | indexInRegion |
547  * ------------------------------  ==> uint32_t synthetic addr
548  * |  uint16_t  |   uint16_t    |
549  * ------------------------------
550  */
GenerateSyntheticAddr(JSTaggedType addr)551 uint32_t RawHeapDumpV2::GenerateSyntheticAddr(JSTaggedType addr)
552 {
553 #ifdef OHOS_UNIT_TEST
554     return static_cast<uint32_t>(addr);
555 #else
556     if (g_isEnableCMCGC) {
557         return static_cast<uint32_t>(addr);
558     } else {
559         uint16_t syntheticAddr[2];
560         syntheticAddr[0] = static_cast<uint16_t>(GenerateRegionId(addr));
561         syntheticAddr[1] = static_cast<uint16_t>((addr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG);
562         return *reinterpret_cast<uint32_t *>(syntheticAddr);
563     }
564 #endif
565 }
566 } // namespace panda::ecmascript
567