• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/heap_snapshot.h"
17 
18 #include <functional>
19 
20 #include "ecmascript/dfx/hprof/heap_root_visitor.h"
21 #include "ecmascript/ecma_string-inl.h"
22 #include "ecmascript/global_dictionary.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/ic/property_box.h"
25 #include "ecmascript/js_array.h"
26 #include "ecmascript/js_handle.h"
27 #include "ecmascript/js_hclass-inl.h"
28 #include "ecmascript/js_object-inl.h"
29 #include "ecmascript/js_symbol.h"
30 #include "ecmascript/js_tagged_value-inl.h"
31 #include "ecmascript/js_thread.h"
32 #include "ecmascript/jspandafile/program_object.h"
33 #include "ecmascript/mem/assert_scope.h"
34 #include "ecmascript/property_attributes.h"
35 #include "ecmascript/tagged_array.h"
36 #include "ecmascript/tagged_dictionary.h"
37 #include "ecmascript/jspandafile/js_pandafile_manager.h"
38 
39 namespace panda::ecmascript {
GetString(const CString & as)40 CString *HeapSnapshot::GetString(const CString &as)
41 {
42     return stringTable_.GetString(as);
43 }
44 
GetArrayString(TaggedArray * array,const CString & as)45 CString *HeapSnapshot::GetArrayString(TaggedArray *array, const CString &as)
46 {
47     CString arrayName = as;
48     arrayName.append(ToCString(array->GetLength()));
49     arrayName.append("]");
50     return GetString(arrayName);  // String type was handled singly, see#GenerateStringNode
51 }
52 
NewNode(Chunk * chunk,size_t id,size_t index,const CString * name,NodeType type,size_t size,TaggedObject * entry,bool isLive)53 Node *Node::NewNode(Chunk *chunk, size_t id, size_t index, const CString *name, NodeType type, size_t size,
54                     TaggedObject *entry, bool isLive)
55 {
56     auto node = chunk->New<Node>(id, index, name, type, size, 0, NewAddress<TaggedObject>(entry), isLive);
57     if (UNLIKELY(node == nullptr)) {
58         LOG_FULL(FATAL) << "internal allocator failed";
59         UNREACHABLE();
60     }
61     return node;
62 }
63 
NewEdge(Chunk * chunk,uint64_t id,EdgeType type,Node * from,Node * to,CString * name)64 Edge *Edge::NewEdge(Chunk *chunk, uint64_t id, EdgeType type, Node *from, Node *to, CString *name)
65 {
66     auto edge = chunk->New<Edge>(id, type, from, to, name);
67     if (UNLIKELY(edge == nullptr)) {
68         LOG_FULL(FATAL) << "internal allocator failed";
69         UNREACHABLE();
70     }
71     return edge;
72 }
73 
~HeapSnapshot()74 HeapSnapshot::~HeapSnapshot()
75 {
76     for (Node *node : nodes_) {
77         chunk_->Delete(node);
78     }
79     for (Edge *edge : edges_) {
80         chunk_->Delete(edge);
81     }
82     nodes_.clear();
83     edges_.clear();
84     traceInfoStack_.clear();
85     stackInfo_.clear();
86     scriptIdMap_.clear();
87     methodToTraceNodeId_.clear();
88     traceNodeIndex_.clear();
89     chunk_ = nullptr;
90 }
91 
BuildUp()92 bool HeapSnapshot::BuildUp()
93 {
94     FillNodes(true);
95     FillEdges();
96     AddSyntheticRoot();
97     return Verify();
98 }
99 
Verify()100 bool HeapSnapshot::Verify()
101 {
102     GetString(CString("HeapVerify:").append(ToCString(totalNodesSize_)));
103     return (edgeCount_ > nodeCount_) && (totalNodesSize_ > 0);
104 }
105 
PrepareSnapshot()106 void HeapSnapshot::PrepareSnapshot()
107 {
108     FillNodes();
109     if (trackAllocations()) {
110         PrepareTraceInfo();
111     }
112 }
113 
UpdateNodes(bool isInFinish)114 void HeapSnapshot::UpdateNodes(bool isInFinish)
115 {
116     for (Node *node : nodes_) {
117         node->SetLive(false);
118     }
119     FillNodes(isInFinish);
120     for (auto iter = nodes_.begin(); iter != nodes_.end();) {
121         if (!(*iter)->IsLive()) {
122             Node *node = entryMap_.FindAndEraseNode((*iter)->GetAddress());
123             ASSERT(*iter == node);
124             if (node != nullptr) {
125                 DecreaseNodeSize(node->GetSelfSize());
126                 chunk_->Delete(node);
127             }
128             iter = nodes_.erase(iter);
129             nodeCount_--;
130         } else {
131             iter++;
132         }
133     }
134 }
135 
FinishSnapshot()136 bool HeapSnapshot::FinishSnapshot()
137 {
138     UpdateNodes(true);
139     FillEdges();
140     AddSyntheticRoot();
141     return Verify();
142 }
143 
RecordSampleTime()144 void HeapSnapshot::RecordSampleTime()
145 {
146     timeStamps_.emplace_back(sequenceId_);
147 }
148 
PushHeapStat(Stream * stream)149 void HeapSnapshot::PushHeapStat(Stream* stream)
150 {
151     CVector<HeapStat> statsBuffer;
152     if (stream == nullptr) {
153         LOG_DEBUGGER(ERROR) << "HeapSnapshot::PushHeapStat::stream is nullptr";
154         return;
155     }
156     int32_t preChunkSize = stream->GetSize();
157     int32_t sequenceId = 0;
158     int64_t timeStampUs = 0;
159     auto iter = nodes_.begin();
160     for (size_t timeIndex = 0; timeIndex < timeStamps_.size(); ++timeIndex) {
161         TimeStamp& timeStamp = timeStamps_[timeIndex];
162         sequenceId = timeStamp.GetLastSequenceId();
163         timeStampUs = timeStamp.GetTimeStamp();
164         int32_t nodesSize = 0;
165         int32_t nodesCount = 0;
166         while (iter != nodes_.end() && (*iter)->GetId() <= static_cast<uint32_t>(sequenceId)) {
167             nodesCount++;
168             nodesSize += (*iter)->GetSelfSize();
169             iter++;
170         }
171         if ((timeStamp.GetCount() != nodesCount) || (timeStamp.GetSize() != nodesSize)) {
172             timeStamp.SetCount(nodesCount);
173             timeStamp.SetSize(nodesSize);
174             statsBuffer.emplace_back(static_cast<int32_t>(timeIndex), nodesCount, nodesSize);
175             if (static_cast<int32_t>(statsBuffer.size()) >= preChunkSize) {
176                 stream->UpdateHeapStats(&statsBuffer.front(), static_cast<int32_t>(statsBuffer.size()));
177                 statsBuffer.clear();
178             }
179         }
180     }
181     if (!statsBuffer.empty()) {
182         stream->UpdateHeapStats(&statsBuffer.front(), static_cast<int32_t>(statsBuffer.size()));
183         statsBuffer.clear();
184     }
185     stream->UpdateLastSeenObjectId(sequenceId, timeStampUs);
186 }
187 
AddNode(TaggedObject * address,size_t size)188 Node *HeapSnapshot::AddNode(TaggedObject *address, size_t size)
189 {
190     return GenerateNode(JSTaggedValue(address), size);
191 }
192 
MoveNode(uintptr_t address,TaggedObject * forwardAddress,size_t size)193 void HeapSnapshot::MoveNode(uintptr_t address, TaggedObject *forwardAddress, size_t size)
194 {
195     if (address == reinterpret_cast<uintptr_t>(forwardAddress)) {
196         return;
197     }
198 
199     Node *node = entryMap_.FindAndEraseNode(address);
200     if (node != nullptr) {
201         ASSERT(node->GetId() <= static_cast<uint64_t>(INT_MAX));
202 
203         entryMap_.FindAndEraseNode(Node::NewAddress(forwardAddress));
204 
205         // Size and name may change during its life for some types(such as string, array and etc).
206         if (forwardAddress->GetClass() != nullptr) {
207             node->SetName(GenerateNodeName(forwardAddress));
208         }
209         auto value = JSTaggedValue(forwardAddress);
210         if (value.IsString()) {
211             node->SetSelfSize(EcmaStringAccessor(forwardAddress).ObjectSize());
212         } else {
213             node->SetSelfSize(size);
214         }
215         node->SetAddress(Node::NewAddress(forwardAddress));
216         if (value.IsHeapObject()) {
217             if (value.IsString()) {
218                 node->SetType(NodeType::PRIM_STRING);
219             } else {
220                 node->SetType(GenerateNodeType(forwardAddress));
221             }
222         } else {
223             node->SetType(NodeType::JS_PRIMITIVE_REF);
224         }
225 
226         entryMap_.InsertEntry(node);
227     } else {
228         GenerateNode(JSTaggedValue(forwardAddress), size, -1);
229     }
230 }
231 
232 // NOLINTNEXTLINE(readability-function-size)
GenerateNodeName(TaggedObject * entry)233 CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
234 {
235     auto *hCls = entry->GetClass();
236     JSType type = hCls->GetObjectType();
237     switch (type) {
238         case JSType::TAGGED_ARRAY:
239             return GetArrayString(TaggedArray::Cast(entry), "TaggedArray[");
240         case JSType::LEXICAL_ENV:
241             return GetArrayString(TaggedArray::Cast(entry), "LexicalEnv[");
242         case JSType::CONSTANT_POOL:
243             return GetArrayString(TaggedArray::Cast(entry), "ConstantPool[");
244         case JSType::TAGGED_DICTIONARY:
245             return GetArrayString(TaggedArray::Cast(entry), "TaggedDict[");
246         case JSType::AOT_LITERAL_INFO:
247             return GetArrayString(TaggedArray::Cast(entry), "AOTLiteralInfo[");
248         case JSType::COW_TAGGED_ARRAY:
249             return GetArrayString(TaggedArray::Cast(entry), "COWArray[");
250         case JSType::HCLASS:
251             return GetString("HiddenClass");
252         case JSType::STRING:
253             return GetString("BaseString");
254         case JSType::JS_OBJECT: {
255             CString objName = CString("JSOBJECT(Ctor=");  // Ctor-name
256             return GetString(objName);
257         }
258         case JSType::FREE_OBJECT_WITH_ONE_FIELD:
259         case JSType::FREE_OBJECT_WITH_NONE_FIELD:
260         case JSType::FREE_OBJECT_WITH_TWO_FIELD:
261             return GetString("FreeObject");
262         case JSType::JS_NATIVE_POINTER:
263             return GetString("JSNativePointer");
264         case JSType::JS_FUNCTION_BASE:
265             return GetString("JSFunctionBase");
266         case JSType::JS_FUNCTION:
267             return GetString("JSFunction");
268         case JSType::JS_ERROR:
269             return GetString("Error");
270         case JSType::JS_EVAL_ERROR:
271             return GetString("Eval Error");
272         case JSType::JS_RANGE_ERROR:
273             return GetString("Range Error");
274         case JSType::JS_TYPE_ERROR:
275             return GetString("Type Error");
276         case JSType::JS_AGGREGATE_ERROR:
277             return GetString("Aggregate Error");
278         case JSType::JS_REFERENCE_ERROR:
279             return GetString("Reference Error");
280         case JSType::JS_URI_ERROR:
281             return GetString("Uri Error");
282         case JSType::JS_SYNTAX_ERROR:
283             return GetString("Syntax Error");
284         case JSType::JS_OOM_ERROR:
285             return GetString("OutOfMemory Error");
286         case JSType::JS_REG_EXP:
287             return GetString("Regexp");
288         case JSType::JS_SET:
289             return GetString("Set");
290         case JSType::JS_MAP:
291             return GetString("Map");
292         case JSType::JS_WEAK_SET:
293             return GetString("WeakSet");
294         case JSType::JS_WEAK_MAP:
295             return GetString("WeakMap");
296         case JSType::JS_DATE:
297             return GetString("Date");
298         case JSType::JS_BOUND_FUNCTION:
299             return GetString("Bound Function");
300         case JSType::JS_ARRAY: {
301             JSArray *jsArray = JSArray::Cast(entry);
302             CString jsArrayName("JSArray[");
303             jsArrayName.append(ToCString(jsArray->GetLength().GetInt()));
304             jsArrayName.append("]");
305             return GetString(jsArrayName);
306         }
307         case JSType::JS_TYPED_ARRAY:
308             return GetString("Typed Array");
309         case JSType::JS_INT8_ARRAY:
310             return GetString("Int8 Array");
311         case JSType::JS_UINT8_ARRAY:
312             return GetString("Uint8 Array");
313         case JSType::JS_UINT8_CLAMPED_ARRAY:
314             return GetString("Uint8 Clamped Array");
315         case JSType::JS_INT16_ARRAY:
316             return GetString("Int16 Array");
317         case JSType::JS_UINT16_ARRAY:
318             return GetString("Uint16 Array");
319         case JSType::JS_INT32_ARRAY:
320             return GetString("Int32 Array");
321         case JSType::JS_UINT32_ARRAY:
322             return GetString("Uint32 Array");
323         case JSType::JS_FLOAT32_ARRAY:
324             return GetString("Float32 Array");
325         case JSType::JS_FLOAT64_ARRAY:
326             return GetString("Float64 Array");
327         case JSType::JS_BIGINT64_ARRAY:
328             return GetString("BigInt64 Array");
329         case JSType::JS_BIGUINT64_ARRAY:
330             return GetString("BigUint64 Array");
331         case JSType::JS_ARGUMENTS:
332             return GetString("Arguments");
333         case JSType::BIGINT:
334             return GetString("BigInt");
335         case JSType::JS_PROXY:
336             return GetString("Proxy");
337         case JSType::JS_PRIMITIVE_REF:
338             return GetString("Primitive");
339         case JSType::JS_DATA_VIEW:
340             return GetString("DataView");
341         case JSType::JS_ITERATOR:
342             return GetString("Iterator");
343         case JSType::JS_FORIN_ITERATOR:
344             return GetString("ForinInterator");
345         case JSType::JS_MAP_ITERATOR:
346             return GetString("MapIterator");
347         case JSType::JS_SET_ITERATOR:
348             return GetString("SetIterator");
349         case JSType::JS_REG_EXP_ITERATOR:
350             return GetString("RegExpIterator");
351         case JSType::JS_ARRAY_ITERATOR:
352             return GetString("ArrayIterator");
353         case JSType::JS_STRING_ITERATOR:
354             return GetString("StringIterator");
355         case JSType::JS_ARRAY_BUFFER:
356             return GetString("ArrayBuffer");
357         case JSType::JS_SHARED_ARRAY_BUFFER:
358             return GetString("SharedArrayBuffer");
359         case JSType::JS_PROXY_REVOC_FUNCTION:
360             return GetString("ProxyRevocFunction");
361         case JSType::PROMISE_REACTIONS:
362             return GetString("PromiseReaction");
363         case JSType::PROMISE_CAPABILITY:
364             return GetString("PromiseCapability");
365         case JSType::ASYNC_GENERATOR_REQUEST:
366             return GetString("AsyncGeneratorRequest");
367         case JSType::PROMISE_ITERATOR_RECORD:
368             return GetString("PromiseIteratorRecord");
369         case JSType::PROMISE_RECORD:
370             return GetString("PromiseRecord");
371         case JSType::RESOLVING_FUNCTIONS_RECORD:
372             return GetString("ResolvingFunctionsRecord");
373         case JSType::JS_PROMISE:
374             return GetString("Promise");
375         case JSType::JS_PROMISE_REACTIONS_FUNCTION:
376             return GetString("PromiseReactionsFunction");
377         case JSType::JS_PROMISE_EXECUTOR_FUNCTION:
378             return GetString("PromiseExecutorFunction");
379         case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION:
380             return GetString("PromiseAllResolveElementFunction");
381         case JSType::JS_PROMISE_ANY_REJECT_ELEMENT_FUNCTION:
382             return GetString("PromiseAnyRejectElementFunction");
383         case JSType::JS_PROMISE_ALL_SETTLED_ELEMENT_FUNCTION:
384             return GetString("PromiseAllSettledElementFunction");
385         case JSType::JS_PROMISE_FINALLY_FUNCTION:
386             return GetString("PromiseFinallyFunction");
387         case JSType::JS_PROMISE_VALUE_THUNK_OR_THROWER_FUNCTION:
388             return GetString("PromiseValueThunkOrThrowerFunction");
389         case JSType::JS_ASYNC_GENERATOR_RESUME_NEXT_RETURN_PROCESSOR_RST_FTN:
390             return GetString("AsyncGeneratorResumeNextReturnProcessorRstFtn");
391         case JSType::JS_GENERATOR_FUNCTION:
392             return GetString("JSGeneratorFunction");
393         case JSType::JS_ASYNC_GENERATOR_FUNCTION:
394             return GetString("JSAsyncGeneratorFunction");
395         case JSType::SYMBOL:
396             return GetString("Symbol");
397         case JSType::JS_ASYNC_FUNCTION:
398             return GetString("AsyncFunction");
399         case JSType::JS_INTL_BOUND_FUNCTION:
400             return GetString("JSIntlBoundFunction");
401         case JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION:
402             return GetString("AsyncAwaitStatusFunction");
403         case JSType::JS_ASYNC_FUNC_OBJECT:
404             return GetString("AsyncFunctionObject");
405         case JSType::JS_REALM:
406             return GetString("Realm");
407         case JSType::JS_GLOBAL_OBJECT:
408             return GetString("GlobalObject");
409         case JSType::JS_INTL:
410             return GetString("JSIntl");
411         case JSType::JS_LOCALE:
412             return GetString("JSLocale");
413         case JSType::JS_DATE_TIME_FORMAT:
414             return GetString("JSDateTimeFormat");
415         case JSType::JS_RELATIVE_TIME_FORMAT:
416             return GetString("JSRelativeTimeFormat");
417         case JSType::JS_NUMBER_FORMAT:
418             return GetString("JSNumberFormat");
419         case JSType::JS_COLLATOR:
420             return GetString("JSCollator");
421         case JSType::JS_PLURAL_RULES:
422             return GetString("JSPluralRules");
423         case JSType::JS_DISPLAYNAMES:
424             return GetString("JSDisplayNames");
425         case JSType::JS_LIST_FORMAT:
426             return GetString("JSListFormat");
427         case JSType::JS_GENERATOR_OBJECT:
428             return GetString("JSGeneratorObject");
429         case JSType::JS_ASYNC_GENERATOR_OBJECT:
430             return GetString("JSAsyncGeneratorObject");
431         case JSType::JS_GENERATOR_CONTEXT:
432             return GetString("JSGeneratorContext");
433         case JSType::ACCESSOR_DATA:
434             return GetString("AccessorData");
435         case JSType::INTERNAL_ACCESSOR:
436             return GetString("InternalAccessor");
437         case JSType::MICRO_JOB_QUEUE:
438             return GetString("MicroJobQueue");
439         case JSType::PENDING_JOB:
440             return GetString("PendingJob");
441         case JSType::COMPLETION_RECORD:
442             return GetString("CompletionRecord");
443         case JSType::JS_API_ARRAY_LIST:
444             return GetString("ArrayList");
445         case JSType::JS_API_ARRAYLIST_ITERATOR:
446             return GetString("ArrayListIterator");
447         case JSType::JS_API_HASH_MAP:
448             return GetString("HashMap");
449         case JSType::JS_API_HASH_SET:
450             return GetString("HashSet");
451         case JSType::JS_API_HASHMAP_ITERATOR:
452             return GetString("HashMapIterator");
453         case JSType::JS_API_HASHSET_ITERATOR:
454             return GetString("HashSetIterator");
455         case JSType::JS_API_LIGHT_WEIGHT_MAP:
456             return GetString("LightWeightMap");
457         case JSType::JS_API_LIGHT_WEIGHT_MAP_ITERATOR:
458             return GetString("LightWeightMapIterator");
459         case JSType::JS_API_LIGHT_WEIGHT_SET:
460             return GetString("LightWeightSet");
461         case JSType::JS_API_LIGHT_WEIGHT_SET_ITERATOR:
462             return GetString("LightWeightSetIterator");
463         case JSType::JS_API_TREE_MAP:
464             return GetString("TreeMap");
465         case JSType::JS_API_TREE_SET:
466             return GetString("TreeSet");
467         case JSType::JS_API_TREEMAP_ITERATOR:
468             return GetString("TreeMapIterator");
469         case JSType::JS_API_TREESET_ITERATOR:
470             return GetString("TreeSetIterator");
471         case JSType::JS_API_VECTOR:
472             return GetString("Vector");
473         case JSType::JS_API_VECTOR_ITERATOR:
474             return GetString("VectorIterator");
475         case JSType::JS_API_QUEUE:
476             return GetString("Queue");
477         case JSType::JS_API_QUEUE_ITERATOR:
478             return GetString("QueueIterator");
479         case JSType::JS_API_DEQUE:
480             return GetString("Deque");
481         case JSType::JS_API_DEQUE_ITERATOR:
482             return GetString("DequeIterator");
483         case JSType::JS_API_STACK:
484             return GetString("Stack");
485         case JSType::JS_API_STACK_ITERATOR:
486             return GetString("StackIterator");
487         case JSType::JS_API_LIST:
488             return GetString("List");
489         case JSType::JS_API_LINKED_LIST:
490             return GetString("LinkedList");
491         case JSType::SOURCE_TEXT_MODULE_RECORD:
492             return GetString("SourceTextModule");
493         case JSType::IMPORTENTRY_RECORD:
494             return GetString("ImportEntry");
495         case JSType::LOCAL_EXPORTENTRY_RECORD:
496             return GetString("LocalExportEntry");
497         case JSType::INDIRECT_EXPORTENTRY_RECORD:
498             return GetString("IndirectExportEntry");
499         case JSType::STAR_EXPORTENTRY_RECORD:
500             return GetString("StarExportEntry");
501         case JSType::RESOLVEDBINDING_RECORD:
502             return GetString("ResolvedBinding");
503         case JSType::RESOLVEDINDEXBINDING_RECORD:
504             return GetString("ResolvedIndexBinding");
505         case JSType::JS_MODULE_NAMESPACE:
506             return GetString("ModuleNamespace");
507         case JSType::JS_API_PLAIN_ARRAY:
508             return GetString("PlainArray");
509         case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
510             return GetString("PlainArrayIterator");
511         case JSType::JS_CJS_EXPORTS:
512             return GetString("CJS Exports");
513         case JSType::JS_CJS_MODULE:
514             return GetString("CJS Module");
515         case JSType::JS_CJS_REQUIRE:
516             return GetString("CJS Require");
517         case JSType::METHOD:
518             return GetString("Method");
519         default:
520             break;
521     }
522     if (IsInVmMode()) {
523         switch (type) {
524             case JSType::PROPERTY_BOX:
525                 return GetString("PropertyBox");
526             case JSType::GLOBAL_ENV:
527                 return GetString("GlobalEnv");
528             case JSType::PROTOTYPE_HANDLER:
529                 return GetString("ProtoTypeHandler");
530             case JSType::TRANSITION_HANDLER:
531                 return GetString("TransitionHandler");
532             case JSType::TRANS_WITH_PROTO_HANDLER:
533                 return GetString("TransWithProtoHandler");
534             case JSType::STORE_TS_HANDLER:
535                 return GetString("StoreTSHandler");
536             case JSType::PROTO_CHANGE_MARKER:
537                 return GetString("ProtoChangeMarker");
538             case JSType::PROTOTYPE_INFO:
539                 return GetString("ProtoChangeDetails");
540             case JSType::TEMPLATE_MAP:
541                 return GetString("TemplateMap");
542             case JSType::PROGRAM:
543                 return GetString("Program");
544             case JSType::MACHINE_CODE_OBJECT:
545                 return GetString("MachineCode");
546             case JSType::CLASS_INFO_EXTRACTOR:
547                 return GetString("ClassInfoExtractor");
548             case JSType::TS_OBJECT_TYPE:
549                 return GetString("TSObjectType");
550             case JSType::TS_INTERFACE_TYPE:
551                 return GetString("TSInterfaceType");
552             case JSType::TS_CLASS_TYPE:
553                 return GetString("TSClassType");
554             case JSType::TS_UNION_TYPE:
555                 return GetString("TSUnionType");
556             case JSType::TS_CLASS_INSTANCE_TYPE:
557                 return GetString("TSClassInstanceType");
558             case JSType::TS_FUNCTION_TYPE:
559                 return GetString("TSFunctionType");
560             case JSType::TS_ARRAY_TYPE:
561                 return GetString("TSArrayType");
562             default:
563                 break;
564         }
565     } else {
566         return GetString("Hidden Object");
567     }
568     return GetString(CString("UnKnownType").append(std::to_string(static_cast<int>(type))));
569 }
570 
GenerateNodeType(TaggedObject * entry)571 NodeType HeapSnapshot::GenerateNodeType(TaggedObject *entry)
572 {
573     NodeType nodeType = NodeType::INVALID;
574     auto *hCls = entry->GetClass();
575     if (hCls->IsTaggedArray()) {
576         nodeType = NodeType::JS_ARRAY;
577     } else if (hCls->IsHClass()) {
578         nodeType = NodeType::HCLASS;
579     } else {
580         nodeType = NodeType(hCls->GetObjectType());
581     }
582     return nodeType;
583 }
584 
FillNodes(bool isInFinish)585 void HeapSnapshot::FillNodes(bool isInFinish)
586 {
587     // Iterate Heap Object
588     auto heap = vm_->GetHeap();
589     if (heap != nullptr) {
590         heap->IterateOverObjects([this, isInFinish](TaggedObject *obj) {
591             GenerateNode(JSTaggedValue(obj), 0, -1, isInFinish);
592         });
593     }
594 }
595 
GenerateNode(JSTaggedValue entry,size_t size,int sequenceId,bool isInFinish)596 Node *HeapSnapshot::GenerateNode(JSTaggedValue entry, size_t size, int sequenceId, bool isInFinish)
597 {
598     Node *node = nullptr;
599     if (sequenceId == -1) {
600         sequenceId = sequenceId_ + SEQ_STEP;
601     }
602     if (entry.IsHeapObject()) {
603         if (entry.IsWeak()) {
604             entry.RemoveWeakTag();
605         }
606         if (entry.IsString()) {
607             if (isPrivate_) {
608                 node = GeneratePrivateStringNode(size, sequenceId);
609             } else {
610                 node = GenerateStringNode(entry, size, sequenceId, isInFinish);
611             }
612             if (node == nullptr) {
613                 LOG_ECMA(DEBUG) << "string node nullptr";
614             }
615             return node;
616         }
617         TaggedObject *obj = entry.GetTaggedObject();
618         auto *baseClass = obj->GetClass();
619         if (baseClass != nullptr) {
620             Address addr = reinterpret_cast<Address>(obj);
621             Node *existNode = entryMap_.FindEntry(addr);  // Fast Index
622             if (existNode == nullptr) {
623                 size_t selfSize = (size != 0) ? size : obj->GetClass()->SizeFromJSHClass(obj);
624                 node = Node::NewNode(chunk_, sequenceId, nodeCount_, GenerateNodeName(obj), GenerateNodeType(obj),
625                     selfSize, obj);
626                 if (sequenceId == sequenceId_ + SEQ_STEP) {
627                     sequenceId_ = sequenceId;  // Odd Digit
628                 }
629                 entryMap_.InsertEntry(node);
630                 InsertNodeUnique(node);
631                 ASSERT(entryMap_.FindEntry(node->GetAddress())->GetAddress() == node->GetAddress());
632             } else {
633                 existNode->SetLive(true);
634                 return existNode;
635             }
636         }
637     } else {
638         CString primitiveName;
639         if (entry.IsInt()) {
640             primitiveName.append("Int:");
641             if (!isPrivate_) {
642                 primitiveName.append(ToCString(entry.GetInt()));
643             }
644         } else if (entry.IsDouble()) {
645             primitiveName.append("Double:");
646             if (!isPrivate_) {
647                 primitiveName.append(FloatToCString(entry.GetDouble()));
648             }
649         } else if (entry.IsHole()) {
650             primitiveName.append("Hole");
651         } else if (entry.IsNull()) {
652             primitiveName.append("Null");
653         } else if (entry.IsTrue()) {
654             primitiveName.append("Boolean:true");
655         } else if (entry.IsFalse()) {
656             primitiveName.append("Boolean:false");
657         } else if (entry.IsException()) {
658             primitiveName.append("Exception");
659         } else if (entry.IsUndefined()) {
660             primitiveName.append("Undefined");
661         } else {
662             primitiveName.append("Illegal_Primitive");
663         }
664 
665         // A primitive value with tag will be regarded as a pointer
666         auto *obj = reinterpret_cast<TaggedObject *>(entry.GetRawData());
667         Node *existNode = entryMap_.FindEntry(reinterpret_cast<Address>(obj));
668         if (existNode != nullptr) {
669             existNode->SetLive(true);
670             return existNode;
671         }
672 
673         node = Node::NewNode(chunk_, sequenceId, nodeCount_, GetString(primitiveName), NodeType::JS_PRIMITIVE_REF, 0,
674                              obj);
675         entryMap_.InsertEntry(node);  // Fast Index
676         if (sequenceId == sequenceId_ + SEQ_STEP) {
677             sequenceId_ = sequenceId;  // Odd Digit
678         }
679         InsertNodeUnique(node);
680     }
681     return node;
682 }
683 
TraceNode(TraceTree * tree,uint32_t nodeIndex)684 TraceNode::TraceNode(TraceTree* tree, uint32_t nodeIndex)
685     : tree_(tree),
686       nodeIndex_(nodeIndex),
687       totalSize_(0),
688       totalCount_(0),
689       id_(tree->GetNextNodeId())
690 {
691 }
692 
~TraceNode()693 TraceNode::~TraceNode()
694 {
695     for (TraceNode* node : children_) {
696         delete node;
697     }
698     children_.clear();
699 }
700 
AddNodeToTree(CVector<uint32_t> traceNodeIndex)701 TraceNode* TraceTree::AddNodeToTree(CVector<uint32_t> traceNodeIndex)
702 {
703     uint32_t len = traceNodeIndex.size();
704     if (len == 0) {
705         return nullptr;
706     }
707 
708     TraceNode* node = GetRoot();
709     for (int i = static_cast<int>(len) - 1; i >= 0; i--) {
710         node = node->FindOrAddChild(traceNodeIndex[i]);
711     }
712     return node;
713 }
714 
FindOrAddChild(uint32_t nodeIndex)715 TraceNode* TraceNode::FindOrAddChild(uint32_t nodeIndex)
716 {
717     TraceNode* child = FindChild(nodeIndex);
718     if (child == nullptr) {
719         child = new TraceNode(tree_, nodeIndex);
720         children_.push_back(child);
721     }
722     return child;
723 }
724 
FindChild(uint32_t nodeIndex)725 TraceNode* TraceNode::FindChild(uint32_t nodeIndex)
726 {
727     for (TraceNode* node : children_) {
728         if (node->GetNodeIndex() == nodeIndex) {
729             return node;
730         }
731     }
732     return nullptr;
733 }
734 
AddTraceNodeId(MethodLiteral * methodLiteral)735 void HeapSnapshot::AddTraceNodeId(MethodLiteral *methodLiteral)
736 {
737     uint32_t traceNodeId = 0;
738     auto result = methodToTraceNodeId_.find(methodLiteral);
739     if (result == methodToTraceNodeId_.end()) {
740         traceNodeId = traceInfoStack_.size() - 1;
741         methodToTraceNodeId_.emplace(methodLiteral, traceNodeId);
742     } else {
743         traceNodeId = result->second;
744     }
745     traceNodeIndex_.emplace_back(traceNodeId);
746 }
747 
AddTraceNode(int sequenceId,int size)748 int HeapSnapshot::AddTraceNode(int sequenceId, int size)
749 {
750     traceNodeIndex_.clear();
751     FrameHandler frameHandler(vm_->GetAssociatedJSThread());
752     for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
753         if (!frameHandler.IsJSFrame()) {
754             continue;
755         }
756         auto method = frameHandler.CheckAndGetMethod();
757         if (method == nullptr || method->IsNativeWithCallField()) {
758             continue;
759         }
760 
761         MethodLiteral *methodLiteral = method->GetMethodLiteral();
762         if (stackInfo_.count(methodLiteral) == 0) {
763             AddMethodInfo(methodLiteral, frameHandler, method->GetJSPandaFile(), sequenceId);
764         }
765         AddTraceNodeId(methodLiteral);
766     }
767 
768     TraceNode* topNode = traceTree_.AddNodeToTree(traceNodeIndex_);
769     if (topNode == nullptr) {
770         return -1;
771     }
772     ASSERT(topNode->GetTotalSize() <= static_cast<uint32_t>(INT_MAX));
773     int totalSize = static_cast<int>(topNode->GetTotalSize());
774     totalSize += size;
775     topNode->SetTotalSize(totalSize);
776     uint32_t totalCount = topNode->GetTotalCount();
777     topNode->SetTotalCount(++totalCount);
778     return topNode->GetId();
779 }
780 
AddMethodInfo(MethodLiteral * methodLiteral,const FrameHandler & frameHandler,const JSPandaFile * jsPandaFile,int sequenceId)781 void HeapSnapshot::AddMethodInfo(MethodLiteral *methodLiteral,
782                                  const FrameHandler &frameHandler,
783                                  const JSPandaFile *jsPandaFile,
784                                  int sequenceId)
785 {
786     struct FunctionInfo codeEntry;
787     codeEntry.functionId = sequenceId;
788     panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
789     const std::string &functionName = methodLiteral->ParseFunctionName(jsPandaFile, methodId);
790     if (functionName.empty()) {
791         codeEntry.functionName = "anonymous";
792     } else {
793         codeEntry.functionName = functionName;
794     }
795     GetString(codeEntry.functionName.c_str());
796 
797     // source file
798     DebugInfoExtractor *debugExtractor =
799         JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
800     const std::string &sourceFile = debugExtractor->GetSourceFile(methodId);
801     if (sourceFile.empty()) {
802         codeEntry.scriptName = "";
803     } else {
804         codeEntry.scriptName = sourceFile;
805         auto iter = scriptIdMap_.find(codeEntry.scriptName);
806         if (iter == scriptIdMap_.end()) {
807             scriptIdMap_.emplace(codeEntry.scriptName, scriptIdMap_.size() + 1);
808             codeEntry.scriptId = static_cast<int>(scriptIdMap_.size());
809         } else {
810             codeEntry.scriptId = iter->second;
811         }
812     }
813     GetString(codeEntry.scriptName.c_str());
814 
815     // line number
816     int32_t lineNumber = 0;
817     int32_t columnNumber = 0;
818     auto callbackLineFunc = [&](int32_t line) -> bool {
819         lineNumber = line + 1;
820         return true;
821     };
822     auto callbackColumnFunc = [&](int32_t column) -> bool {
823         columnNumber = column + 1;
824         return true;
825     };
826     uint32_t offset = frameHandler.GetBytecodeOffset();
827     if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) ||
828         !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) {
829         codeEntry.lineNumber = 0;
830         codeEntry.columnNumber = 0;
831     } else {
832         codeEntry.lineNumber = lineNumber;
833         codeEntry.columnNumber = columnNumber;
834     }
835 
836     traceInfoStack_.emplace_back(codeEntry);
837     stackInfo_.emplace(methodLiteral, codeEntry);
838     return;
839 }
840 
GenerateStringNode(JSTaggedValue entry,size_t size,int sequenceId,bool isInFinish)841 Node *HeapSnapshot::GenerateStringNode(JSTaggedValue entry, size_t size, int sequenceId, bool isInFinish)
842 {
843     static const CString EMPTY_STRING;
844 
845     Node *existNode = entryMap_.FindEntry(reinterpret_cast<Address>(entry.GetTaggedObject()));  // Fast Index
846     if (existNode != nullptr) {
847         if (isInFinish) {
848             existNode->SetName(GetString(EntryVisitor::ConvertKey(entry)));
849         }
850         existNode->SetLive(true);
851         return existNode;
852     }
853     // Allocation Event will generate string node for "".
854     // When we need to serialize and isFinish is true, the nodeName will be given the actual string content.
855     auto originStr = static_cast<EcmaString *>(entry.GetTaggedObject());
856     size_t selfsize = (size != 0) ? size : EcmaStringAccessor(originStr).ObjectSize();
857     const CString *nodeName = &EMPTY_STRING;
858     if (isInFinish) {
859         nodeName = GetString(EntryVisitor::ConvertKey(entry));
860     }
861     Node *node = Node::NewNode(chunk_, sequenceId, nodeCount_, nodeName, NodeType::PRIM_STRING, selfsize,
862                                entry.GetTaggedObject());
863     if (sequenceId == sequenceId_ + SEQ_STEP) {
864         sequenceId_ = sequenceId;  // Odd Digit
865     }
866     entryMap_.InsertEntry(node);
867     InsertNodeUnique(node);
868     return node;
869 }
870 
GeneratePrivateStringNode(size_t size,int sequenceId)871 Node *HeapSnapshot::GeneratePrivateStringNode(size_t size, int sequenceId)
872 {
873     if (privateStringNode_ != nullptr) {
874         return privateStringNode_;
875     }
876     Node *node = nullptr;
877     JSTaggedValue stringValue = vm_->GetJSThread()->GlobalConstants()->GetStringString();
878     auto originStr = static_cast<EcmaString *>(stringValue.GetTaggedObject());
879     size_t selfsize = (size != 0) ? size : EcmaStringAccessor(originStr).ObjectSize();
880     CString strContent;
881     strContent.append(EntryVisitor::ConvertKey(stringValue));
882     node = Node::NewNode(chunk_, sequenceId, nodeCount_, GetString(strContent), NodeType::PRIM_STRING, selfsize,
883                          stringValue.GetTaggedObject());
884     Node *existNode = entryMap_.FindOrInsertNode(node);  // Fast Index
885     if (existNode == node) {
886         if (sequenceId == sequenceId_ + SEQ_STEP) {
887             sequenceId_ = sequenceId;  // Odd Digit
888         }
889         InsertNodeUnique(node);
890     } else {
891         existNode->SetLive(true);
892     }
893     ASSERT(entryMap_.FindEntry(node->GetAddress())->GetAddress() == node->GetAddress());
894     if (existNode != node) {
895         if ((node->GetAddress() == existNode->GetAddress()) && (existNode->GetName()->empty())) {
896             existNode->SetName(GetString(strContent));
897         }
898         const_cast<NativeAreaAllocator *>(vm_->GetNativeAreaAllocator())->Delete(node);
899         return nullptr;
900     }
901     privateStringNode_ = node;
902     return node;
903 }
904 
FillEdges()905 void HeapSnapshot::FillEdges()
906 {
907     size_t length = nodes_.size();
908     auto iter = nodes_.begin();
909     size_t count = 0;
910     while (++count < length) {
911         ASSERT(*iter != nullptr);
912         auto *objFrom = reinterpret_cast<TaggedObject *>((*iter)->GetAddress());
913         std::vector<std::pair<CString, JSTaggedValue>> nameResources;
914         JSTaggedValue(objFrom).DumpForSnapshot(nameResources, isVmMode_);
915         JSTaggedValue objValue(objFrom);
916         for (auto const &it : nameResources) {
917             JSTaggedValue toValue = it.second;
918             Node *entryTo = nullptr;
919             if (toValue.IsWeak()) {
920                 toValue.RemoveWeakTag();
921             }
922             if (toValue.IsHeapObject()) {
923                 auto *to = reinterpret_cast<TaggedObject *>(toValue.GetTaggedObject());
924                 entryTo = entryMap_.FindEntry(Node::NewAddress(to));
925             }
926             if (entryTo == nullptr) {
927                 entryTo = GenerateNode(toValue, 0, -1, true);
928             }
929             if (entryTo != nullptr) {
930                 Edge *edge = Edge::NewEdge(chunk_, edgeCount_, EdgeType::DEFAULT, *iter, entryTo, GetString(it.first));
931                 InsertEdgeUnique(edge);
932                 (*iter)->IncEdgeCount();  // Update Node's edgeCount_ here
933             }
934         }
935         iter++;
936     }
937     // Fill Primitive Edge
938     size_t lengthExtend = nodes_.size();
939     while (++count < lengthExtend) {
940         ASSERT(*iter != nullptr);
941         if ((*iter)->GetType() == NodeType::JS_PRIMITIVE_REF) {
942             JSTaggedValue jsFrom(reinterpret_cast<TaggedObject *>((*iter)->GetAddress()));
943             CString valueName;
944             if (jsFrom.IsInt()) {
945                 valueName.append(ToCString(jsFrom.GetInt()));
946             } else if (jsFrom.IsDouble()) {
947                 valueName.append(FloatToCString(jsFrom.GetDouble()));
948             } else {
949                 valueName.append("NaN");
950             }
951             Edge *edge = Edge::NewEdge(chunk_, edgeCount_, EdgeType::DEFAULT, (*iter), (*iter), GetString(valueName));
952             InsertEdgeUnique(edge);
953             (*iter)->IncEdgeCount();  // Update Node's edgeCount_ here
954         }
955         iter++;
956     }
957 }
958 
BridgeAllReferences()959 void HeapSnapshot::BridgeAllReferences()
960 {
961     // This Function is Unused
962     for (Edge *edge : edges_) {
963         auto *from = reinterpret_cast<TaggedObject *>(edge->GetFrom()->GetAddress());
964         auto *to = reinterpret_cast<TaggedObject *>(edge->GetTo()->GetAddress());
965         if (!JSTaggedValue(from).IsECMAObject()) {
966             continue;  // named it by other way
967         }
968         edge->SetName(GenerateEdgeName(from, to));
969     }
970 }
971 
GenerateEdgeName(TaggedObject * from,TaggedObject * to)972 CString *HeapSnapshot::GenerateEdgeName([[maybe_unused]] TaggedObject *from, [[maybe_unused]] TaggedObject *to)
973 {
974     // This Function is Unused
975     ASSERT(from != nullptr && from != to);
976     return GetString("[]");  // unAnalysed
977 }
978 
InsertNodeUnique(Node * node)979 Node *HeapSnapshot::InsertNodeUnique(Node *node)
980 {
981     AccumulateNodeSize(node->GetSelfSize());
982     nodes_.emplace_back(node);
983     nodeCount_++;
984     return node;
985 }
986 
EraseNodeUnique(Node * node)987 void HeapSnapshot::EraseNodeUnique(Node *node)
988 {
989     auto iter = std::find(nodes_.begin(), nodes_.end(), node);
990     if (iter != nodes_.end()) {
991         DecreaseNodeSize(node->GetSelfSize());
992         chunk_->Delete(node);
993         nodes_.erase(iter);
994         nodeCount_--;
995     }
996 }
997 
InsertEdgeUnique(Edge * edge)998 Edge *HeapSnapshot::InsertEdgeUnique(Edge *edge)
999 {
1000     edges_.emplace_back(edge);
1001     edgeCount_++;
1002     return edge;
1003 }
1004 
AddSyntheticRoot()1005 void HeapSnapshot::AddSyntheticRoot()
1006 {
1007     Node *syntheticRoot = Node::NewNode(chunk_, 1, nodeCount_, GetString("SyntheticRoot"),
1008                                         NodeType::SYNTHETIC, 0, nullptr);
1009     InsertNodeAt(0, syntheticRoot);
1010 
1011     int edgeOffset = 0;
1012 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
1013 #define ROOT_EDGE_BUILDER_CORE(type, slot)                                                            \
1014     do {                                                                                              \
1015         JSTaggedValue value((slot).GetTaggedType());                                                  \
1016         if (value.IsHeapObject()) {                                                                   \
1017             TaggedObject *root = value.GetTaggedObject();                                             \
1018             Node *rootNode = entryMap_.FindEntry(Node::NewAddress(root));                             \
1019             if (rootNode != nullptr) {                                                                \
1020                 Edge *edge = Edge::NewEdge(chunk_,                                                    \
1021                     edgeCount_, EdgeType::SHORTCUT, syntheticRoot, rootNode, GetString("-subroot-")); \
1022                 InsertEdgeAt(edgeOffset, edge);                                                       \
1023                 edgeOffset++;                                                                         \
1024                 syntheticRoot->IncEdgeCount();                                                        \
1025             }                                                                                         \
1026         }                                                                                             \
1027     } while (false)
1028 
1029     RootVisitor rootEdgeBuilder = [this, syntheticRoot, &edgeOffset]([[maybe_unused]] Root type, ObjectSlot slot) {
1030         ROOT_EDGE_BUILDER_CORE(type, slot);
1031     };
1032     RootBaseAndDerivedVisitor rootBaseEdgeBuilder = []
1033         ([[maybe_unused]] Root type, [[maybe_unused]]ObjectSlot base, [[maybe_unused]]ObjectSlot derived,
1034          [[maybe_unused]]uintptr_t baseOldObject) {
1035     };
1036 
1037     RootRangeVisitor rootRangeEdgeBuilder = [this, syntheticRoot, &edgeOffset]([[maybe_unused]] Root type,
1038                                                                                ObjectSlot start, ObjectSlot end) {
1039         for (ObjectSlot slot = start; slot < end; slot++) {
1040             ROOT_EDGE_BUILDER_CORE(type, slot);
1041         }
1042     };
1043 #undef ROOT_EDGE_BUILDER_CORE
1044     rootVisitor_.VisitHeapRoots(vm_->GetJSThread(), rootEdgeBuilder, rootRangeEdgeBuilder, rootBaseEdgeBuilder);
1045 
1046     int reindex = 0;
1047     for (Node *node : nodes_) {
1048         node->SetIndex(reindex);
1049         reindex++;
1050     }
1051 }
1052 
InsertNodeAt(size_t pos,Node * node)1053 Node *HeapSnapshot::InsertNodeAt(size_t pos, Node *node)
1054 {
1055     ASSERT(node != nullptr);
1056     auto iter = nodes_.begin();
1057     std::advance(iter, pos);
1058     nodes_.insert(iter, node);
1059     nodeCount_++;
1060     return node;
1061 }
1062 
InsertEdgeAt(size_t pos,Edge * edge)1063 Edge *HeapSnapshot::InsertEdgeAt(size_t pos, Edge *edge)
1064 {
1065     ASSERT(edge != nullptr);
1066     auto iter = edges_.begin();
1067     std::advance(iter, pos);
1068     edges_.insert(iter, edge);
1069     edgeCount_++;
1070     return edge;
1071 }
1072 
ConvertKey(JSTaggedValue key)1073 CString EntryVisitor::ConvertKey(JSTaggedValue key)
1074 {
1075     ASSERT(key.GetTaggedObject() != nullptr);
1076     EcmaString *keyString = EcmaString::Cast(key.GetTaggedObject());
1077 
1078     if (key.IsSymbol()) {
1079         JSSymbol *symbol = JSSymbol::Cast(key.GetTaggedObject());
1080         keyString = EcmaString::Cast(symbol->GetDescription().GetTaggedObject());
1081     }
1082     // convert, expensive but safe
1083     return EcmaStringAccessor(keyString).ToCString(StringConvertedUsage::PRINT);
1084 }
1085 
FindOrInsertNode(Node * node)1086 Node *HeapEntryMap::FindOrInsertNode(Node *node)
1087 {
1088     ASSERT(node != nullptr);
1089     auto it = nodesMap_.find(node->GetAddress());
1090     if (it != nodesMap_.end()) {
1091         return it->second;
1092     }
1093     InsertEntry(node);
1094     return node;
1095 }
1096 
FindAndEraseNode(Address addr)1097 Node *HeapEntryMap::FindAndEraseNode(Address addr)
1098 {
1099     auto it = nodesMap_.find(addr);
1100     if (it != nodesMap_.end()) {
1101         Node *node = it->second;
1102         nodesMap_.erase(it);
1103         nodeEntryCount_--;
1104         return node;
1105     }
1106     return nullptr;
1107 }
1108 
FindEntry(Address addr)1109 Node *HeapEntryMap::FindEntry(Address addr)
1110 {
1111     auto it = nodesMap_.find(addr);
1112     return it != nodesMap_.end() ? it->second : nullptr;
1113 }
1114 
InsertEntry(Node * node)1115 void HeapEntryMap::InsertEntry(Node *node)
1116 {
1117     nodeEntryCount_++;
1118     nodesMap_.emplace(node->GetAddress(), node);
1119 }
1120 
Convert(NodeType type)1121 FrontType NodeTypeConverter::Convert(NodeType type)
1122 {
1123     FrontType  fType = FrontType::DEFAULT;
1124     if (type == NodeType::PROPERTY_BOX) {
1125         fType = FrontType::HIDDEN;
1126     } else if (type == NodeType::JS_ARRAY || type == NodeType::JS_TYPED_ARRAY) {
1127         fType = FrontType::ARRAY;
1128     } else if (type == NodeType::PRIM_STRING) {  // STRING
1129         fType = FrontType::STRING;
1130     } else if (type == NodeType::JS_OBJECT) {
1131         fType = FrontType::OBJECT;
1132     } else if (type >= NodeType::JS_FUNCTION_FIRST && type <= NodeType::JS_FUNCTION_LAST) {
1133         fType = FrontType::CLOSURE;
1134     } else if (type == NodeType::JS_BOUND_FUNCTION) {
1135         fType = FrontType::CLOSURE;
1136     } else if (type == NodeType::JS_FUNCTION_BASE) {
1137         fType = FrontType::CLOSURE;
1138     } else if (type == NodeType::JS_REG_EXP) {
1139         fType = FrontType::REGEXP;
1140     } else if (type == NodeType::SYMBOL) {
1141         fType = FrontType::SYMBOL;
1142     } else if (type == NodeType::JS_PRIMITIVE_REF) {
1143         fType = FrontType::HEAPNUMBER;
1144     } else if (type == NodeType::SYNTHETIC) {
1145         fType = FrontType::SYNTHETIC;
1146     } else {
1147         fType = FrontType::DEFAULT;
1148         // NATIVE,           /* kNative */
1149         // CONSSTRING,       /* kConsString */
1150         // SLICEDSTRING,     /* kSlicedString */
1151         // SYMBOL,           /* kSymbol */
1152         // BIGINT,           /* kBigInt */
1153     }
1154     return fType;
1155 }
1156 }  // namespace panda::ecmascript
1157