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