• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 <algorithm>
17 #include <sstream>
18 #include "ecmascript/dfx/hprof/rawheap_translate/rawheap_translate.h"
19 #include "ecmascript/dfx/hprof/rawheap_translate/utils.h"
20 
21 namespace rawheap_translate {
Translate(const std::string & rawheapPath)22 bool RawHeapTranslate::Translate(const std::string &rawheapPath)
23 {
24     uint32_t fileSize = 0;
25     std::ifstream rawheapFile;
26     if (!FileCheckAndOpenBinary(rawheapPath, rawheapFile, fileSize)) {
27         return false;
28     }
29 
30     std::vector<uint32_t> sections;
31     if (!ParseMetaData(rawheapFile, fileSize) ||
32         !ReadSectionInfo(rawheapFile, fileSize, sections) ||
33         !ReadVersion(rawheapFile, 0, sections[0]) ||
34         !ReadObjTableBySection(rawheapFile, sections) ||
35         !ReadStringTable(rawheapFile, sections[2], sections[3]) ||  // 2: str offset, 3: str size
36         !ReadRootTable(rawheapFile, sections[0], sections[1])) {
37         return false;
38     }
39 
40     FillNodesAndBuildEdges();
41     return true;
42 }
43 
ParseMetaData(std::ifstream & file,uint32_t & offset)44 bool RawHeapTranslate::ParseMetaData(std::ifstream &file, uint32_t &offset)
45 {
46     cJSON *object = nullptr;
47     if (!ReadMetaDataJson(file, offset, &object)) {
48         return false;
49     }
50 
51     bool result = meta_->Parse(object);
52     DelMetaDataJson(object);
53     return result;
54 }
55 
ReadMetaDataJson(std::ifstream & file,uint32_t & offset,cJSON ** json)56 bool RawHeapTranslate::ReadMetaDataJson(std::ifstream &file, uint32_t &offset, cJSON **json)
57 {
58     auto result = CheckAndGetHead(file, offset - sizeof(uint64_t), 0);
59     if (!result.has_value()) {
60         LOG_ERROR("RawHeapTranslate::ReadMetaDataJson: metadata header error!");
61         return false;
62     }
63 
64     auto [metaOffset, metaSize] = result.value();
65     std::vector<char> metaJson(metaSize);
66     if (!ReadFileAtOffset(file, metaOffset, metaSize, metaJson.data())) {
67         return false;
68     }
69 
70     cJSON *object = cJSON_ParseWithOpts(metaJson.data(), nullptr, true);
71     if (!object) {
72         LOG_ERROR("RawHeapTranslate::ReadMetaDataJson: json format error!");
73         return false;
74     }
75 
76     *json = object;
77     offset = metaOffset;
78     return true;
79 }
80 
DelMetaDataJson(cJSON * json)81 void RawHeapTranslate::DelMetaDataJson(cJSON *json)
82 {
83     cJSON_Delete(json);
84 }
85 
ReadSectionInfo(std::ifstream & file,uint32_t endOffset,std::vector<uint32_t> & sections)86 bool RawHeapTranslate::ReadSectionInfo(std::ifstream &file, uint32_t endOffset, std::vector<uint32_t> &sections)
87 {
88     auto result = CheckAndGetHead(file, endOffset - sizeof(uint64_t), sizeof(uint32_t));
89     if (!result.has_value()) {
90         LOG_ERROR("RawHeapTranslate::ReadSectionInfo: sections header error!");
91         return false;
92     }
93 
94     auto [secSize, unitSize] = result.value();
95     uint32_t sectionSize = secSize * unitSize;
96     std::vector<char> sectionBytes(sectionSize);
97     if (!ReadFileAtOffset(file, endOffset - sectionSize - sizeof(uint64_t), sectionSize, sectionBytes.data())) {
98         return false;
99     }
100 
101     sections.resize(secSize);
102     ByteToU32Array(sectionBytes.data(), sections.data(), secSize);
103     LOG_INFO("RawHeapTranslate::ReadSectionInfo: sectionSize=" + std::to_string(secSize));
104     return true;
105 }
106 
ReadVersion(std::ifstream & file,uint32_t offset,uint32_t size)107 bool RawHeapTranslate::ReadVersion(std::ifstream &file, uint32_t offset, uint32_t size)
108 {
109     std::vector<char> version(size);
110     if (!ReadFileAtOffset(file, offset, size, version.data())) {
111         return false;
112     }
113     LOG_INFO("Rawheap version is " + std::string(version.data()));
114     return true;
115 }
116 
ReadObjTableBySection(std::ifstream & file,const std::vector<uint32_t> & sections)117 bool RawHeapTranslate::ReadObjTableBySection(std::ifstream &file, const std::vector<uint32_t> &sections)
118 {
119     LOG_INFO("RawHeapTranslate::Translate: start to read objects");
120     // 4: index of obj table section start from 4
121     // 2: step is 2
122     for (size_t secIndex = 4; secIndex < sections.size(); secIndex += 2) {
123         uint32_t offset = sections[secIndex];
124         uint32_t size = sections[secIndex + 1];
125         if (!ReadObjTable(file, offset, size)) {
126             return false;
127         }
128     }
129     LOG_INFO("RawHeapTranslate::Translate: read objects finish!");
130     return true;
131 }
132 
ReadObjTable(std::ifstream & file,uint32_t offset,uint32_t size)133 bool RawHeapTranslate::ReadObjTable(std::ifstream &file, uint32_t offset, uint32_t size)
134 {
135     auto result = CheckAndGetHead(file, offset, sizeof(AddrTableItem));
136     if (!result.has_value()) {
137         LOG_ERROR("RawHeapTranslate::ReadObjTable: obj table header error!");
138         return false;
139     }
140 
141     auto [objNum, unitSize] = result.value();
142     uint32_t baseOffset = sizeof(uint64_t) + offset;
143     std::vector<AddrTableItem> objTable;
144     if (!ByteToAddrTableItem(file, baseOffset, objNum, objTable)) {
145         return false;
146     }
147 
148     uint32_t tableSize = objNum * unitSize;
149     uint32_t curOffset = baseOffset + tableSize;
150     uint32_t objMemSize = size - tableSize - sizeof(uint64_t);
151     char *objMem = new char[objMemSize];
152     if (!ReadFileAtOffset(file, curOffset, objMemSize, objMem)) {
153         delete[] objMem;
154         return false;
155     }
156     memBuf_.emplace_back(objMem);
157 
158     for (uint32_t i = 0; i < objNum; i++) {
159         uint32_t nextOffset = i + 1 < objNum ? objTable[i + 1].offset : size - sizeof(uint64_t);
160         auto actSize = nextOffset - objTable[i].offset;
161         if (actSize != objTable[i].objSize && actSize != sizeof(uint64_t)) {
162             LOG_ERROR("RawHeapTranslate::ReadObjTable: expected objSize=" + std::to_string(objTable[i].objSize));
163             continue;
164         }
165         uint32_t objMemOffset = objTable[i].offset - tableSize;
166         if (objMemOffset > objMemSize) {
167             LOG_ERROR("RawHeapTranslate::ReadObjTable: obj out of memory buf!");
168             return false;
169         }
170         CreateNode(objTable[i], objMem + objMemOffset);
171     }
172 
173     LOG_INFO("RawHeapTranslate::ReadObjTable: read object, cnt=" + std::to_string(objNum));
174     return true;
175 }
176 
ReadStringTable(std::ifstream & file,uint32_t offset,uint32_t size)177 bool RawHeapTranslate::ReadStringTable(std::ifstream &file, uint32_t offset, uint32_t size)
178 {
179     if (size == 0) {
180         LOG_ERROR("RawHeapTranslate::ReadStringTable: string section size is 0");
181         return false;
182     }
183     char *strSection = new char[size];
184     if (!ReadFileAtOffset(file, offset, size, strSection)) {
185         delete[] strSection;
186         return false;
187     }
188 
189     uint32_t strNum = ByteToU32(strSection);
190     char *curStrSection = strSection + sizeof(uint32_t) * 2;
191     uint32_t strIndex = 0;
192     while (strIndex++ < strNum) {
193         uint32_t strSize = ByteToU32(curStrSection);
194         uint32_t objCnt = ByteToU32(curStrSection + sizeof(uint32_t));
195         char *objAddr = curStrSection + sizeof(uint32_t) * 2;
196         uint32_t strOffset = sizeof(uint32_t) * 2 + sizeof(uint64_t) * objCnt;
197         char *str = curStrSection + strOffset;
198         StringId strId = strTable_->InsertStrAndGetStringId(std::string(str));
199         SetNodeStringId(objAddr, objCnt, strId);
200         curStrSection += strOffset + strSize + 1;
201     }
202 
203     delete[] strSection;
204     LOG_INFO("RawHeapTranslate::ReadStringTable: read string table, cnt=" + std::to_string(strNum));
205     return true;
206 }
207 
ReadRootTable(std::ifstream & file,uint32_t offset,uint32_t size)208 bool RawHeapTranslate::ReadRootTable(std::ifstream &file, uint32_t offset, uint32_t size)
209 {
210     auto result = CheckAndGetHead(file, offset, sizeof(uint64_t));
211     if (!result.has_value()) {
212         LOG_ERROR("RawHeapTranslate::ReadObjTable: obj table header error!");
213         return false;
214     }
215 
216     auto [rootNum, unitSize] = result.value();
217     std::vector<char> roots(rootNum * unitSize);
218     if (!ReadFileAtOffset(file, offset + sizeof(uint64_t), rootNum * unitSize, roots.data())) {
219         return false;
220     }
221 
222     auto syntheticRoot = std::make_shared<Node>(Node(0));
223     syntheticRoot->nodeId = 1;  // 1: means root node
224     syntheticRoot->type = 9;  // 9: means SYNTHETIC node type
225     syntheticRoot->strId = strTable_->InsertStrAndGetStringId("SyntheticRoot");
226     nodes_.insert(nodes_.begin(), syntheticRoot);
227     StringId edgeStrId = strTable_->InsertStrAndGetStringId("-subroot-");
228     EdgeType type = EdgeType::SHORTCUT;
229 
230     char *addr = roots.data();
231     std::vector<std::shared_ptr<Edge>> rootEdges;
232     for (uint32_t i = 0; i < rootNum; i++) {
233         uint64_t rootAddr = ByteToU64(addr);
234         addr += sizeof(uint64_t);
235         auto rootNode = nodesMap_.find(rootAddr);
236         if (rootNode == nodesMap_.end()) {
237             continue;
238         }
239         auto edge = std::make_shared<Edge>(Edge(type, syntheticRoot, rootNode->second, edgeStrId));
240         rootEdges.emplace_back(edge);
241         syntheticRoot->edgeCount++;
242     }
243 
244     edges_.insert(edges_.begin(), rootEdges.begin(), rootEdges.end());
245     LOG_INFO("RawHeapTranslate::ReadRootTable: find root obj " + std::to_string(rootNum));
246     return true;
247 }
248 
ReadFileAtOffset(std::ifstream & file,uint32_t offset,uint32_t size,char * buf)249 bool RawHeapTranslate::ReadFileAtOffset(std::ifstream &file, uint32_t offset, uint32_t size, char *buf)
250 {
251     if (buf == nullptr) {
252         LOG_ERROR("RawHeapTranslate::ReadFileAtOffset: file buf is nullptr!");
253         return false;
254     }
255     if (!file.is_open()) {
256         LOG_ERROR("RawHeapTranslate::ReadFileAtOffset: file not open!");
257         return false;
258     }
259     file.clear();
260     if (!file.seekg(offset)) {
261         LOG_ERROR("RawHeapTranslate::ReadFileAtOffset: file set offset failed, offset=" + std::to_string(offset));
262         return false;
263     }
264     if (file.read(buf, size).fail()) {
265         LOG_ERROR("RawHeapTranslate::ReadFileAtOffset: file read failed, offset=" + std::to_string(offset));
266         return false;
267     }
268     return true;
269 }
270 
CreateNode(AddrTableItem & item,char * data)271 void RawHeapTranslate::CreateNode(AddrTableItem &item, char *data)
272 {
273     static uint32_t nodeIndex = 1;
274     auto node = std::make_shared<Node>(Node(nodeIndex++));
275     node->nodeId = item.id;
276     node->size = item.objSize;
277     node->data = data;
278     nodes_.emplace_back(node);
279     nodesMap_.emplace(item.addr, node);
280 }
281 
FillNodesAndBuildEdges()282 void RawHeapTranslate::FillNodesAndBuildEdges()
283 {
284     LOG_INFO("RawHeapTranslate::FillNodesAndBuildEdges: start to build edges!");
285     int missNodes = 0;
286     StringId hclassStrId = strTable_->InsertStrAndGetStringId("hclass");
287     for (size_t i = 1; i < nodes_.size(); i++) {
288         auto node = nodes_[i];
289         auto result = FindNodeFromAddr(ByteToU64(node->data), nullptr);
290         if (!result.has_value()) {
291             missNodes++;
292             continue;
293         }
294         auto hclass = result.value();
295         FillNodes(node, hclass->data);
296         if (hclass->nodeId == node->nodeId) {
297             continue;
298         }
299         CreateEdge(node, hclass, EdgeType::DEFAULT, hclassStrId);
300         if (meta_->IsString(hclass->data)) {
301             continue;
302         }
303         BuildEdges(node, hclass->data);
304     }
305     LOG_INFO("RawHeapTranslate::FillNodesAndBuildEdges: build edges finish!");
306     if (missNodes > 0) {
307         LOG_ERROR("RawHeapTranslate::FillNodesAndBuildEdges: " + std::to_string(missNodes) + " nodes missed hclass!");
308     }
309 }
310 
FillNodes(const std::shared_ptr<Node> & node,char * hclass)311 void RawHeapTranslate::FillNodes(const std::shared_ptr<Node> &node, char *hclass)
312 {
313     node->nativeSize = meta_->GetNativateSize(node->data, hclass);
314     node->type = meta_->GetNodeTypeFromHClass(hclass);
315     if (node->strId < 3 && !meta_->IsString(hclass)) {  // 3: custom strId start from 3
316         std::string name = meta_->GetTypeNameFromHClass(hclass);
317         std::transform(name.begin(), name.end(), name.begin(), ::tolower);
318         node->strId = strTable_->InsertStrAndGetStringId(name);
319     }
320 }
321 
BuildEdges(const std::shared_ptr<Node> & from,char * hclass)322 void RawHeapTranslate::BuildEdges(const std::shared_ptr<Node> &from, char *hclass)
323 {
324     if (meta_->IsGlobalEnv(hclass)) {
325         BuildGlobalEnvEdges(from);
326         return;
327     }
328 
329     std::string typeName = meta_->GetTypeNameFromHClass(hclass);
330     auto visitor = [&from, this] (std::shared_ptr<MetaData> &metadata, int offset) {
331         if (!metadata->IsArray()) {
332             BuildFieldsEdges(from, metadata, offset);
333             return;
334         }
335         BuildArrayEdges(from, metadata, offset);
336     };
337     uint32_t baseOffset = 0;
338     meta_->VisitObjectBody(typeName, visitor, baseOffset);
339     BuildJSObjectInlEdges(from, hclass, baseOffset);
340 }
341 
BuildFieldsEdges(const std::shared_ptr<Node> & from,const std::shared_ptr<MetaData> & metadata,int offset)342 void RawHeapTranslate::BuildFieldsEdges(
343     const std::shared_ptr<Node> &from, const std::shared_ptr<MetaData> &metadata, int offset)
344 {
345     for (const auto &field : metadata->fields) {
346         if (field->size != sizeof(uint64_t) || offset + sizeof(uint64_t) > from->size) {
347             continue;
348         }
349         uint64_t addr = ByteToU64(from->data + offset + field->offset);
350         EdgeType type = EdgeType::DEFAULT;
351         auto result = FindNodeFromAddr(addr, &type);
352         if (!result.has_value()) {
353             continue;
354         }
355         StringId strId = strTable_->InsertStrAndGetStringId(field->name);
356         CreateEdge(from, result.value(), type, strId);
357     }
358 }
359 
BuildGlobalEnvEdges(const std::shared_ptr<Node> & from)360 void RawHeapTranslate::BuildGlobalEnvEdges(const std::shared_ptr<Node> &from)
361 {
362     uint32_t index = sizeof(uint64_t);
363     while ((index + sizeof(uint64_t)) < from->size) {
364         uint64_t addr = ByteToU64(from->data + index);
365         index += sizeof(uint64_t);
366         auto result = FindNodeFromAddr(addr, nullptr);
367         if (!result.has_value()) {
368             continue;
369         }
370         CreateEdge(from, result.value(), EdgeType::DEFAULT, result.value()->strId);
371     }
372 }
373 
BuildArrayEdges(const std::shared_ptr<Node> & from,const std::shared_ptr<MetaData> & metadata,int offset)374 void RawHeapTranslate::BuildArrayEdges(
375     const std::shared_ptr<Node> &from, const std::shared_ptr<MetaData> &metadata, int offset)
376 {
377     auto lengthField = FindFieldInMetaData(metadata, "Length");
378     auto dataField = FindFieldInMetaData(metadata, "Data");
379     if (!lengthField || !dataField) {
380         LOG_ERROR("RawHeapTranslate::BuildArrayEdges: field length or data of array not found!");
381         return;
382     }
383 
384     uint32_t len = ByteToU32(from->data + offset + lengthField->offset);
385     uint32_t step = dataField->size;
386     if (step != sizeof(uint64_t) || len <= 0 || len * step + offset > from->size) {
387         return;
388     }
389 
390     uint32_t index = offset + dataField->offset;
391     uint32_t itemIndex = 0;
392     uint32_t itemCnt = 0;
393     while (itemCnt++ < len && index < from->size) {
394         uint64_t addr = ByteToU64(from->data + index);
395         index += step;
396         auto result = FindNodeFromAddr(addr, nullptr);
397         if (!result.has_value()) {
398             continue;
399         }
400         CreateEdge(from, result.value(), EdgeType::ELEMENT, itemIndex++);
401     }
402 }
403 
BuildDictionaryEdges(const std::shared_ptr<Node> & from,const std::shared_ptr<MetaData> & metadata,int offset)404 void RawHeapTranslate::BuildDictionaryEdges(
405     const std::shared_ptr<Node> &from, const std::shared_ptr<MetaData> &metadata, int offset)
406 {
407     auto lengthField = FindFieldInMetaData(metadata, "Length");
408     auto dataField = FindFieldInMetaData(metadata, "Data");
409     auto layout = meta_->GetObjectLayout("Dictionary");
410     if (!lengthField || !dataField || !layout) {
411         LOG_ERROR("RawHeapTranslate::BuildDictionaryEdges: field length or data or layout of dictionary not found!");
412         return;
413     }
414 
415     uint32_t len = ByteToU32(from->data + offset + lengthField->offset);
416     uint32_t step = dataField->size;
417     if (step != sizeof(uint64_t) || len <= 0 || len * step + offset > from->size) {
418         return;
419     }
420 
421     uint32_t eleIndex = 0;
422     uint32_t index = offset + dataField->offset + layout->headerSize * step;
423     while (index < from->size) {
424         std::vector<uint64_t> item(layout->entrySize);
425         ByteToU64Array(from->data + index, item.data(), layout->entrySize);
426         index += layout->entrySize * step;
427 
428         auto value = FindNodeFromAddr(item[layout->valueIndex], nullptr);
429         if (!value.has_value()) {
430             continue;
431         }
432         CreateEdge(from, value.value(), EdgeType::ELEMENT, eleIndex++);
433     }
434 }
435 
BuildJSObjectInlEdges(const std::shared_ptr<Node> & from,char * hclass,uint32_t offset)436 void RawHeapTranslate::BuildJSObjectInlEdges(const std::shared_ptr<Node> &from, char *hclass, uint32_t offset)
437 {
438     if (!meta_->IsJSObject(hclass)) {
439         return;
440     }
441 
442     StringId strId = strTable_->InsertStrAndGetStringId("InlineProperty");
443     uint32_t propOffset = offset;
444     while (propOffset + sizeof(uint64_t) <= from->size) {
445         uint64_t addr = ByteToU64(from->data + propOffset);
446         propOffset += sizeof(uint64_t);
447         auto result = FindNodeFromAddr(addr, nullptr);
448         if (!result.has_value()) {
449             continue;
450         }
451         CreateEdge(from, result.value(), EdgeType::DEFAULT, strId);
452     }
453 }
454 
CreateEdge(const std::shared_ptr<Node> & from,const std::shared_ptr<Node> & to,EdgeType type,uint32_t index)455 void RawHeapTranslate::CreateEdge(
456     const std::shared_ptr<Node> &from, const std::shared_ptr<Node> &to, EdgeType type, uint32_t index)
457 {
458     auto edge = std::make_shared<Edge>(Edge(type, from, to, index));
459     edges_.emplace_back(edge);
460     from->edgeCount++;
461 }
462 
SetNodeStringId(char * addr,uint32_t size,StringId strId)463 void RawHeapTranslate::SetNodeStringId(char *addr, uint32_t size, StringId strId)
464 {
465     char *objAddr = addr;
466     for (uint32_t i = 0; i < size; i++) {
467         auto node = nodesMap_.find(ByteToU64(objAddr));
468         if (node != nodesMap_.end()) {
469             node->second->strId = strId;
470         }
471         objAddr += sizeof(uint64_t);
472     }
473 }
474 
ByteToAddrTableItem(std::ifstream & file,uint32_t offset,uint32_t objNum,std::vector<AddrTableItem> & table)475 bool RawHeapTranslate::ByteToAddrTableItem(
476     std::ifstream &file, uint32_t offset, uint32_t objNum, std::vector<AddrTableItem> &table)
477 {
478     uint32_t unitSize = sizeof(AddrTableItem);
479     uint32_t tableSize = objNum * unitSize;
480     std::vector<char> tableByte(tableSize);
481     if (!ReadFileAtOffset(file, offset, tableSize, tableByte.data())) {
482         return false;
483     }
484     table.resize(objNum);
485     char *item = tableByte.data();
486     for (uint32_t i = 0; i < objNum; i++) {
487         table[i].addr = ByteToU64(item);
488         item += sizeof(uint64_t);
489 
490         table[i].id = ByteToU64(item);
491         item += sizeof(uint64_t);
492 
493         table[i].objSize = ByteToU32(item);
494         item += sizeof(uint32_t);
495 
496         table[i].offset = ByteToU32(item);
497         item += sizeof(uint32_t);
498     }
499     return true;
500 }
501 
FindNodeFromAddr(uint64_t addr,EdgeType * type)502 std::optional<std::shared_ptr<Node>> RawHeapTranslate::FindNodeFromAddr(uint64_t addr, EdgeType *type)
503 {
504     if (!IsHeapObject(addr)) {
505         return std::nullopt;
506     }
507     CheckAndRemoveWeak(addr, type);
508     auto node = nodesMap_.find(addr);
509     if (node == nodesMap_.end()) {
510         return std::nullopt;
511     }
512     return node->second;
513 }
514 
CheckAndGetHead(std::ifstream & file,uint32_t offset,uint32_t assertNum)515 std::optional<std::pair<uint32_t, uint32_t>> RawHeapTranslate::CheckAndGetHead(
516     std::ifstream &file, uint32_t offset, uint32_t assertNum)
517 {
518     uint32_t headSize = sizeof(uint64_t);
519     std::vector<char> head(headSize);
520     if (!ReadFileAtOffset(file, offset, headSize, head.data())) {
521         return std::nullopt;
522     }
523 
524     uint32_t firstNum = ByteToU32(head.data());
525     uint32_t secondNum = ByteToU32(head.data() + sizeof(uint32_t));
526     if (assertNum != 0 && secondNum != assertNum) {
527         return std::nullopt;
528     }
529 
530     return std::pair<uint32_t, uint32_t>(firstNum, secondNum);
531 }
532 
FindFieldInMetaData(const std::shared_ptr<MetaData> & metadata,const std::string & name)533 std::shared_ptr<Field> RawHeapTranslate::FindFieldInMetaData(
534     const std::shared_ptr<MetaData> &metadata, const std::string &name)
535 {
536     for (const auto &field : metadata->fields) {
537         if (field->name == name) {
538             return field;
539         }
540     }
541     return nullptr;
542 }
543 
CheckAndRemoveWeak(uint64_t & addr,EdgeType * type)544 void RawHeapTranslate::CheckAndRemoveWeak(uint64_t &addr, EdgeType *type)
545 {
546     if ((addr & TAG_WEAK_MASK) == TAG_WEAK) {
547         addr &= (~TAG_WEAK);
548         if (type != nullptr) {
549             *type = EdgeType::WEAK;
550         }
551     }
552 }
553 
IsHeapObject(uint64_t addr)554 bool RawHeapTranslate::IsHeapObject(uint64_t addr)
555 {
556     return ((addr & TAG_HEAPOBJECT_MASK) == 0U);
557 }
558 } // namespace rawheap_translate