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