#include <ThreadWeaver/ThreadWeaver>
#include <QDebug>
+#include <QMessageBox>
+#include <QString>
#include "analyze/accumulatedtracedata.h"
return rowData;
}
-ObjectNode buildObjectGraph(ParserData& data, size_t &nodeIndex) {
+ObjectNode buildObjectGraph(ParserData& data, size_t &nodeIndex, bool &success) {
ObjectNode node;
+ if (nodeIndex >= data.objectTreeNodes.size()) {
+ success = false;
+ return node;
+ }
ObjectTreeNode &dataNode = data.objectTreeNodes[nodeIndex];
node.m_classIndex = dataNode.classIndex;
node.m_objectPtr = dataNode.objectPtr;
node.m_objectSize = 0;
nodeIndex++;
for (size_t i = 0; i < dataNode.numChildren; ++i) {
- if (node.gcNum != data.objectTreeNodes[nodeIndex].gcNum)
+ if (node.gcNum != data.objectTreeNodes[nodeIndex].gcNum) {
+ success = false;
break;
- node.m_children.push_back(buildObjectGraph(data, nodeIndex));
+ }
+ node.m_children.push_back(buildObjectGraph(data, nodeIndex, success));
}
return node;
}
size_t nodeIndex = 0;
std::vector<ObjectNode> nodes;
while (nodeIndex < data.objectTreeNodes.size()) {
- nodes.push_back(buildObjectGraph(data, nodeIndex));
+ bool success = true;
+ ObjectNode node = buildObjectGraph(data, nodeIndex, success);
+ if (success)
+ nodes.push_back(node);
+ else {
+ QMessageBox::warning(nullptr, QString::fromStdString("Bad data"),
+ QString::fromStdString("Heap snapshot for GC #%1 is incomplete").arg(node.gcNum));
+ }
}
for (auto& node: nodes) {
m_graph.clear();
}
+ /* m_graph is in fact a flat collection of ObjectNodes. The graph structure
+ is provided by ObjectNode::children which point to ObjectNode instances
+ living inside m_graph. All instances of ObjectNode are residing
+ in m_graph, regardless of their position in the actual graph.
+ NULL key is somewhat special - the ObjectNode corresponding to it is a fake
+ ObjectNode whose children are GC roots. */
static std::unordered_map<void*, ObjectNode> m_graph;
};