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