diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index 92f46420e8..b2f3bbaa6c 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -1348,13 +1348,10 @@ static void DumpArrayClass([[maybe_unused]] JSThread *thread, const TaggedArray { DISALLOW_GARBAGE_COLLECTION; array_size_t len = arr->GetLength(); - for (array_size_t i = 0; i < len; i++) { JSTaggedValue val(arr->Get(i)); - if (!val.IsHole()) { - CString str = ToCString(i); - vec.push_back(std::make_pair(str, val)); - } + CString str = ToCString(i); + vec.push_back(std::make_pair(str, val)); } } @@ -1376,6 +1373,7 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::vectorGetDescription().GetTaggedObject())); - } else { - UNREACHABLE(); + if (key.IsInt()) { + res = std::to_string(key.GetInt()); + } else if (key.IsDouble()) { + res = std::to_string(key.GetDouble()); + } else if (key.IsBoolean()) { + res = key.IsTrue() ? "true" : "false"; + } else if (key.IsHeapObject()) { + if (key.IsWeak()) { + key.RemoveWeakTag(); + } + if (key.IsString()) { + EcmaStringToStd(res, EcmaString::Cast(key.GetTaggedObject())); + } else if (key.IsSymbol()) { + JSSymbol *sym = JSSymbol::Cast(key.GetTaggedObject()); + EcmaStringToStd(res, EcmaString::Cast(sym->GetDescription().GetTaggedObject())); + } } } @@ -1557,7 +1564,7 @@ void NumberDictionary::DumpForSnapshot([[maybe_unused]] JSThread *thread, int size = Size(); for (int hashIndex = 0; hashIndex < size; hashIndex++) { JSTaggedValue key(GetKey(hashIndex)); - if (!key.IsUndefined() && !key.IsHole()) { + if (!key.IsUndefined() && !key.IsHole() && !key.IsNull()) { JSTaggedValue val(GetValue(hashIndex)); CString str = ToCString(static_cast(JSTaggedNumber(key).GetNumber())); vec.push_back(std::make_pair(str, val)); @@ -1572,9 +1579,8 @@ void NameDictionary::DumpForSnapshot([[maybe_unused]] JSThread *thread, int size = Size(); for (int hashIndex = 0; hashIndex < size; hashIndex++) { JSTaggedValue key(GetKey(hashIndex)); - if (!key.IsUndefined() && !key.IsHole()) { + if (!key.IsUndefined() && !key.IsHole() && !key.IsNull()) { JSTaggedValue val(GetValue(hashIndex)); - CString str; KeyToStd(str, key); vec.push_back(std::make_pair(str, val)); @@ -1589,12 +1595,10 @@ void GlobalDictionary::DumpForSnapshot([[maybe_unused]] JSThread *thread, int size = Size(); for (int hashIndex = 0; hashIndex < size; hashIndex++) { JSTaggedValue key(GetKey(hashIndex)); - if (!key.IsUndefined() && !key.IsHole()) { - PropertyBox *box = PropertyBox::Cast(key.GetTaggedObject()); - + if (!key.IsUndefined() && !key.IsHole() && !key.IsNull()) { CString str; KeyToStd(str, key); - JSTaggedValue val = box->GetValue(); + JSTaggedValue val = GetValue(hashIndex); vec.push_back(std::make_pair(str, val)); } } @@ -1607,7 +1611,7 @@ void LinkedHashSet::DumpForSnapshot([[maybe_unused]] JSThread *thread, int capacity = NumberOfElements() + NumberOfDeletedElements(); for (int hashIndex = 0; hashIndex < capacity; hashIndex++) { JSTaggedValue key(GetKey(hashIndex)); - if (!key.IsUndefined() && !key.IsHole()) { + if (!key.IsUndefined() && !key.IsHole() && !key.IsNull()) { CString str; KeyToStd(str, key); vec.push_back(std::make_pair(str, JSTaggedValue::Hole())); @@ -1622,8 +1626,8 @@ void LinkedHashMap::DumpForSnapshot([[maybe_unused]] JSThread *thread, int capacity = NumberOfElements() + NumberOfDeletedElements(); for (int hashIndex = 0; hashIndex < capacity; hashIndex++) { JSTaggedValue key(GetKey(hashIndex)); - if (!key.IsUndefined() && !key.IsHole()) { - JSTaggedValue val(GetValue(hashIndex)); + if (!key.IsUndefined() && !key.IsHole() && !key.IsNull()) { + JSTaggedValue val = GetValue(hashIndex); CString str; KeyToStd(str, key); vec.push_back(std::make_pair(str, val)); diff --git a/ecmascript/hprof/heap_profiler.cpp b/ecmascript/hprof/heap_profiler.cpp index 6a2d640af6..42a3801244 100644 --- a/ecmascript/hprof/heap_profiler.cpp +++ b/ecmascript/hprof/heap_profiler.cpp @@ -37,6 +37,10 @@ bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, con { [[maybe_unused]] bool heapClean = ForceFullGC(thread); ASSERT(heapClean); + auto heap = thread->GetEcmaVM()->GetHeap(); + size_t heapSize = heap->GetNewSpace()->GetHeapObjectSize() + heap->GetOldSpace()->GetHeapObjectSize() + + heap->GetNonMovableSpace()->GetHeapObjectSize(); + LOG(ERROR, RUNTIME) << "HeapProfiler DumpSnapshot heap size " << heapSize; HeapSnapShot *snapShot = MakeHeapSnapShot(thread, SampleType::ONE_SHOT); ASSERT(snapShot != nullptr); std::pair realPath = FilePathValid(filePath); @@ -148,7 +152,6 @@ bool HeapProfiler::ForceFullGC(JSThread *thread) if (vm->IsInitialized()) { const_cast(vm->GetHeap())->CollectGarbage(TriggerGCType::SEMI_GC); const_cast(vm->GetHeap())->CollectGarbage(TriggerGCType::OLD_GC); - const_cast(vm->GetHeap())->CollectGarbage(TriggerGCType::NON_MOVE_GC); return true; } return false; @@ -156,6 +159,7 @@ bool HeapProfiler::ForceFullGC(JSThread *thread) HeapSnapShot *HeapProfiler::MakeHeapSnapShot(JSThread *thread, SampleType sampleType) { + LOG(ERROR, RUNTIME) << "HeapProfiler::MakeHeapSnapShot"; DISALLOW_GARBAGE_COLLECTION; switch (sampleType) { case SampleType::ONE_SHOT: { diff --git a/ecmascript/hprof/heap_profiler_interface.cpp b/ecmascript/hprof/heap_profiler_interface.cpp index 93ae61bbe7..0292c07942 100644 --- a/ecmascript/hprof/heap_profiler_interface.cpp +++ b/ecmascript/hprof/heap_profiler_interface.cpp @@ -20,6 +20,7 @@ namespace panda::ecmascript { void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) { + LOG(ERROR, RUNTIME) << "HeapProfilerInterface::DumpHeapSnapshot"; const Heap *heap = thread->GetEcmaVM()->GetHeap(); auto *hprof = const_cast(heap->GetRegionFactory())->New(heap); if (UNLIKELY(hprof == nullptr)) { diff --git a/ecmascript/hprof/heap_snapshot.cpp b/ecmascript/hprof/heap_snapshot.cpp index 32512f9f6b..04006470cf 100644 --- a/ecmascript/hprof/heap_snapshot.cpp +++ b/ecmascript/hprof/heap_snapshot.cpp @@ -22,6 +22,7 @@ #include "ecmascript/global_env.h" #include "ecmascript/hprof/heap_root_visitor.h" #include "ecmascript/ic/property_box.h" +#include "ecmascript/js_array.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_hclass-inl.h" #include "ecmascript/js_object-inl.h" @@ -144,10 +145,17 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) CString *name = GetString("UnKnownType"); auto *hCls = entry->GetClass(); if (hCls->IsTaggedArray()) { + CString arrayName; TaggedArray *array = TaggedArray::Cast(entry); - CString arrayName("Array["); - arrayName.append(ToCString(array->GetLength())); - arrayName.append("]"); + if (hCls->IsDictionary()) { + arrayName = "TaggedDict["; + arrayName.append(ToCString(array->GetLength())); + arrayName.append("]"); + } else { + arrayName = "TaggedArray["; + arrayName.append(ToCString(array->GetLength())); + arrayName.append("]"); + } name = GetString(arrayName); // String type was handled singly, see#GenerateStringNode } else if (hCls->IsHClass()) { name = GetString("HiddenClass"); @@ -161,7 +169,11 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) } else if (hCls->IsJSSymbol()) { name = GetString("JSSymbol"); } else if (hCls->IsJSArray()) { - name = GetString("JSArray"); + JSArray *jsArray = JSArray::Cast(entry); + CString arrayName("JSArray["); + arrayName.append(ToCString(jsArray->GetLength().GetInt())); + arrayName.append("]"); + name = GetString(arrayName); } else if (hCls->IsTypedArray()) { name = GetString("TypedArray"); } else if (hCls->IsJSTypedArray()) { @@ -352,7 +364,7 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) NodeType HeapSnapShot::GenerateNodeType(TaggedObject *entry) { - NodeType nodeType; + NodeType nodeType = NodeType::INVALID; auto *hCls = entry->GetClass(); if (hCls->IsTaggedArray()) { nodeType = NodeType::JS_ARRAY; @@ -381,8 +393,14 @@ Node *HeapSnapShot::GenerateNode(JSThread *thread, JSTaggedValue entry, int sequ sequenceId = sequenceId_ + SEQ_STEP; } if (entry.IsHeapObject()) { + if (entry.IsWeak()) { + entry.RemoveWeakTag(); + } if (entry.IsString()) { - return GenerateStringNode(entry, sequenceId); + node = GenerateStringNode(entry, sequenceId); + if (node == nullptr) { + LOG(ERROR, RUNTIME) << "string node nullptr"; + } } TaggedObject *obj = entry.GetTaggedObject(); auto *baseClass = obj->GetClass(); @@ -404,44 +422,36 @@ Node *HeapSnapShot::GenerateNode(JSThread *thread, JSTaggedValue entry, int sequ } } } else { - auto *obj = reinterpret_cast(entry.GetRawData()); CString primitiveName; - JSTaggedValue primitiveObj(obj); - if (primitiveObj.IsInt()) { - primitiveName.append("Int:"); - } else if (primitiveObj.IsDouble()) { + // A primitive value with tag will be regarded as a pointer + auto *obj = reinterpret_cast(entry.GetRawData()); + if (entry.IsInt()) { + primitiveName.append("Int:" + ToCString(entry.GetInt())); + } else if (entry.IsDouble()) { primitiveName.append("Double:"); - } else if (primitiveObj.IsSpecial()) { - if (primitiveObj.IsHole()) { - primitiveName.append("Hole"); - } else if (primitiveObj.IsNull()) { - primitiveName.append("Null"); - } else if (primitiveObj.IsTrue()) { - primitiveName.append("Boolean:true"); - } else if (primitiveObj.IsFalse()) { - primitiveName.append("Boolean:false"); - } else if (primitiveObj.IsException()) { - primitiveName.append("Exception"); - } else if (primitiveObj.IsUndefined()) { - primitiveName.append("Undefined"); - } + } else if (entry.IsHole()) { + primitiveName.append("Hole"); + } else if (entry.IsNull()) { + primitiveName.append("Null"); + } else if (entry.IsTrue()) { + primitiveName.append("Boolean:true"); + } else if (entry.IsFalse()) { + primitiveName.append("Boolean:false"); + } else if (entry.IsException()) { + primitiveName.append("Exception"); + } else if (entry.IsUndefined()) { + primitiveName.append("Undefined"); } else { primitiveName.append("Illegal_Primitive"); } node = Node::NewNode(heap_, sequenceId, nodeCount_, GetString(primitiveName), NodeType::JS_PRIMITIVE_REF, 0, obj); - Node *existNode = entryMap_.FindOrInsertNode(node); // Fast Index - if (existNode == node) { - if (sequenceId == sequenceId_ + SEQ_STEP) { - sequenceId_ = sequenceId; // Odd Digit - } - InsertNodeUnique(node); - } else { - const_cast(heap_->GetRegionFactory())->Delete(node); - node = nullptr; - existNode->SetLive(true); + entryMap_.InsertEntry(node); // Fast Index + if (sequenceId == sequenceId_ + SEQ_STEP) { + sequenceId_ = sequenceId; // Odd Digit } + InsertNodeUnique(node); } return node; } @@ -482,11 +492,16 @@ void HeapSnapShot::FillEdges(JSThread *thread) auto *objFrom = reinterpret_cast((*iter)->GetAddress()); std::vector> nameResources; JSTaggedValue(objFrom).DumpForSnapshot(thread, nameResources); + JSTaggedValue objValue(objFrom); for (auto const &it : nameResources) { - auto *to = reinterpret_cast(it.second.GetRawData()); - Node *entryTo = entryMap_.FindEntry(Node::NewAddress(to)); + JSTaggedValue toValue = it.second; + Node *entryTo = nullptr; + if (toValue.IsHeapObject()) { + auto *to = reinterpret_cast(toValue.GetHeapObject()); + entryTo = entryMap_.FindEntry(Node::NewAddress(to)); + } if (entryTo == nullptr) { - entryTo = GenerateNode(thread, it.second); + entryTo = GenerateNode(thread, toValue); } if (entryTo != nullptr) { Edge *edge = Edge::NewEdge(heap_, edgeCount_, EdgeType::DEFAULT, *iter, entryTo, GetString(it.first)); @@ -565,8 +580,8 @@ Edge *HeapSnapShot::InsertEdgeUnique(Edge *edge) void HeapSnapShot::AddSyntheticRoot(JSThread *thread) { - Node *syntheticRoot = Node::NewNode(heap_, 1, nodeCount_, GetString("SyntheticRoot"), NodeType::SYNTHETIC, 0, - nullptr); + Node *syntheticRoot = Node::NewNode(heap_, 1, nodeCount_, GetString("SyntheticRoot"), + NodeType::SYNTHETIC, 0, nullptr); InsertNodeAt(0, syntheticRoot); int edgeOffset = 0; @@ -632,7 +647,7 @@ CString EntryVisitor::ConvertKey(JSTaggedValue key) keyString = EcmaString::Cast(symbol->GetDescription().GetTaggedObject()); } // convert, expensive but safe - int length; + int length = 0; if (keyString->IsUtf8()) { length = keyString->GetUtf8Length(); std::vector buffer(length); @@ -687,7 +702,7 @@ void HeapEntryMap::InsertEntry(Node *node) FrontType NodeTypeConverter::Convert(NodeType type) { - FrontType fType; + FrontType fType = FrontType::DEFAULT; if (type == NodeType::PROPERTY_BOX) { fType = FrontType::HIDDEN; } else if (type == NodeType::JS_ARRAY || type == NodeType::JS_TYPED_ARRAY) { diff --git a/ecmascript/hprof/heap_snapshot.h b/ecmascript/hprof/heap_snapshot.h index be10d01f51..f2ad5fb7d1 100644 --- a/ecmascript/hprof/heap_snapshot.h +++ b/ecmascript/hprof/heap_snapshot.h @@ -224,9 +224,9 @@ public: { return nodeEntryCount_; } + void InsertEntry(Node *node); private: - void InsertEntry(Node *node); size_t nodeEntryCount_{0}; CUnorderedMap nodesMap_{}; }; diff --git a/ecmascript/hprof/heap_snapshot_json_serializer.cpp b/ecmascript/hprof/heap_snapshot_json_serializer.cpp index 1946fdb7dd..5cbed3f0f5 100644 --- a/ecmascript/hprof/heap_snapshot_json_serializer.cpp +++ b/ecmascript/hprof/heap_snapshot_json_serializer.cpp @@ -22,6 +22,7 @@ namespace panda::ecmascript { bool HeapSnapShotJSONSerializer::Serialize(HeapSnapShot *snapShot, const CString &fileName) { // Serialize Node/Edge/String-Table + LOG(ERROR, RUNTIME) << "HeapSnapShotJSONSerializer::Serialize begin"; snapShot_ = snapShot; ASSERT(snapShot_->GetNodes() != nullptr && snapShot_->GetEdges() != nullptr && snapShot_->GetEcmaStringTable() != nullptr); @@ -38,6 +39,7 @@ bool HeapSnapShotJSONSerializer::Serialize(HeapSnapShot *snapShot, const CString SerializerSnapShotClosure(); // 9. WriteJSON(fileName); // 10. + LOG(ERROR, RUNTIME) << "HeapSnapShotJSONSerializer::Serialize exit"; return true; } @@ -191,6 +193,7 @@ void HeapSnapShotJSONSerializer::SerializerSnapShotClosure() void HeapSnapShotJSONSerializer::WriteJSON(const CString &fileName) { std::string fName(fileName); + LOG(ERROR, RUNTIME) << "HeapSnapShotJSONSerializer::WriteJSON" << fName; outputStream_.open(fName, std::ios::out); if (!outputStream_.good()) { LOG_ECMA(ERROR) << "open file failed"; diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 127658b16b..d0e6be3516 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -359,7 +359,7 @@ public: class JSObject : public ECMAObject { public: - static constexpr int MIN_ELEMENTS_LENGTH = 16; + static constexpr int MIN_ELEMENTS_LENGTH = 3; static constexpr int MIN_PROPERTIES_LENGTH = JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS; static constexpr int PROPERTIES_GROW_SIZE = 4; static constexpr int FAST_ELEMENTS_FACTOR = 3;