bugfix for snapshot and change the elements number in jsobject

Signed-off-by: xiongluo <xiongluo@huawei.com>
This commit is contained in:
xiongluo 2021-09-16 11:06:46 +08:00
parent 991c3ea9f9
commit 2fc660ebca
7 changed files with 95 additions and 68 deletions

View File

@ -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::vector<std::pai
DumpDynClass(thread, obj, vec);
break;
case JSType::TAGGED_ARRAY:
case JSType::TAGGED_DICTIONARY:
DumpArrayClass(thread, TaggedArray::Cast(obj), vec);
break;
case JSType::STRING:
@ -1529,15 +1527,24 @@ static inline void EcmaStringToStd(CString &res, EcmaString *str)
res.append(string);
}
static inline void KeyToStd(CString &res, JSTaggedValue key)
static void KeyToStd(CString &res, JSTaggedValue key)
{
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()));
} 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<uint32_t>(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));

View File

@ -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<bool, CString> realPath = FilePathValid(filePath);
@ -148,7 +152,6 @@ bool HeapProfiler::ForceFullGC(JSThread *thread)
if (vm->IsInitialized()) {
const_cast<Heap *>(vm->GetHeap())->CollectGarbage(TriggerGCType::SEMI_GC);
const_cast<Heap *>(vm->GetHeap())->CollectGarbage(TriggerGCType::OLD_GC);
const_cast<Heap *>(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: {

View File

@ -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<RegionFactory *>(heap->GetRegionFactory())->New<HeapProfiler>(heap);
if (UNLIKELY(hprof == nullptr)) {

View File

@ -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<TaggedObject *>(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<TaggedObject *>(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<RegionFactory *>(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<TaggedObject *>((*iter)->GetAddress());
std::vector<std::pair<CString, JSTaggedValue>> nameResources;
JSTaggedValue(objFrom).DumpForSnapshot(thread, nameResources);
JSTaggedValue objValue(objFrom);
for (auto const &it : nameResources) {
auto *to = reinterpret_cast<TaggedObject *>(it.second.GetRawData());
Node *entryTo = entryMap_.FindEntry(Node::NewAddress(to));
JSTaggedValue toValue = it.second;
Node *entryTo = nullptr;
if (toValue.IsHeapObject()) {
auto *to = reinterpret_cast<TaggedObject *>(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<uint8_t> 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) {

View File

@ -224,9 +224,9 @@ public:
{
return nodeEntryCount_;
}
void InsertEntry(Node *node);
private:
void InsertEntry(Node *node);
size_t nodeEntryCount_{0};
CUnorderedMap<Address, Node *> nodesMap_{};
};

View File

@ -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";

View File

@ -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;