Implement #9756. ImageFunctionsView now builds...

...a source path-based tree of all the image's functions, and
consequently organizes them into a nested hierarchy similar to the
on-disk directory structure in which they were originally found (or at
least, as close as we can get from the DWARF info).
This commit is contained in:
Rene Gollent
2013-05-08 23:26:12 -04:00
parent 879020baf1
commit a69facf051
2 changed files with 305 additions and 118 deletions
@@ -1,6 +1,6 @@
/* /*
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2011, Rene Gollent, [email protected]. * Copyright 2011-2013, Rene Gollent, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -23,6 +23,135 @@
#include "Tracing.h" #include "Tracing.h"
// #pragma mark - SourcePathComponentNode
class ImageFunctionsView::SourcePathComponentNode : public BReferenceable {
public:
SourcePathComponentNode(SourcePathComponentNode* parent,
const BString& componentName, LocatableFile* sourceFile,
FunctionInstance* function)
:
fParent(parent),
fComponentName(componentName),
fSourceFile(sourceFile),
fFunction(function)
{
if (fParent != NULL)
fParent->AcquireReference();
if (fSourceFile != NULL)
fSourceFile->AcquireReference();
if (fFunction != NULL)
fFunction->AcquireReference();
}
virtual ~SourcePathComponentNode()
{
for (int32 i = 0; i < fChildPathComponents.CountItems(); i++)
fChildPathComponents.ItemAt(i)->ReleaseReference();
if (fParent != NULL)
fParent->ReleaseReference();
if (fSourceFile != NULL)
fSourceFile->ReleaseReference();
if (fFunction != NULL)
fFunction->AcquireReference();
}
const BString& ComponentName() const
{
return fComponentName;
}
LocatableFile* SourceFile() const
{
return fSourceFile;
}
FunctionInstance* Function() const
{
return fFunction;
}
int32 CountChildren() const
{
return fChildPathComponents.CountItems();
}
SourcePathComponentNode* ChildAt(int32 index)
{
return fChildPathComponents.ItemAt(index);
}
SourcePathComponentNode* FindChildByName(const BString& name) const
{
return fChildPathComponents.BinarySearchByKey(name,
&CompareByComponentName);
}
int32 FindChildIndexByName(const BString& name) const
{
return fChildPathComponents.BinarySearchIndexByKey(name,
&CompareByComponentName);
}
bool AddChild(SourcePathComponentNode* child)
{
if (!fChildPathComponents.BinaryInsert(child,
&CompareComponents)) {
return false;
}
child->AcquireReference();
return true;
}
bool RemoveChild(SourcePathComponentNode* child)
{
if (!fChildPathComponents.RemoveItem(child))
return false;
child->ReleaseReference();
return true;
}
bool RemoveAllChildren()
{
for (int32 i = 0; i < fChildPathComponents.CountItems(); i++)
RemoveChild(fChildPathComponents.ItemAt(i));
return true;
}
private:
static int CompareByComponentName(const BString* name, const
SourcePathComponentNode* node)
{
return name->Compare(node->ComponentName());
}
static int CompareComponents(const SourcePathComponentNode* a,
const SourcePathComponentNode* b)
{
return a->ComponentName().Compare(b->ComponentName());
}
private:
typedef BObjectList<SourcePathComponentNode> ChildPathComponentList;
private:
SourcePathComponentNode* fParent;
BString fComponentName;
LocatableFile* fSourceFile;
FunctionInstance* fFunction;
ChildPathComponentList fChildPathComponents;
};
// #pragma mark - FunctionsTableModel // #pragma mark - FunctionsTableModel
@@ -31,10 +160,7 @@ public:
FunctionsTableModel() FunctionsTableModel()
: :
fImageDebugInfo(NULL), fImageDebugInfo(NULL),
fFunctions(NULL), fSourcelessNode(NULL)
fFunctionCount(0),
fSourceFileIndices(NULL),
fSourceFileCount(0)
{ {
} }
@@ -46,16 +172,14 @@ public:
void SetImageDebugInfo(ImageDebugInfo* imageDebugInfo) void SetImageDebugInfo(ImageDebugInfo* imageDebugInfo)
{ {
// unset old functions // unset old functions
if (fSourceFileIndices != NULL) { if (fImageDebugInfo != NULL) {
NotifyNodesRemoved(TreeTablePath(), 0, fSourceFileCount); NotifyNodesRemoved(TreeTablePath(), 0,
fChildPathComponents.CountItems());
for (int32 i = 0; i < fChildPathComponents.CountItems(); i++)
fChildPathComponents.ItemAt(i)->ReleaseReference();
delete[] fFunctions; fChildPathComponents.MakeEmpty();
fFunctions = NULL; fSourcelessNode = NULL;
fFunctionCount = 0;
delete[] fSourceFileIndices;
fSourceFileIndices = NULL;
fSourceFileCount = 0;
} }
fImageDebugInfo = imageDebugInfo; fImageDebugInfo = imageDebugInfo;
@@ -95,35 +219,27 @@ public:
// The array might now be too large, but we can live with that. // The array might now be too large, but we can live with that.
} }
// count the different source files SourcePathComponentNode* sourcelessNode = new(std::nothrow)
int32 sourceFileCount = 1; SourcePathComponentNode(NULL, "<no source file>", NULL, NULL);
for (int32 i = 1; i < functionCount; i++) { ObjectDeleter<SourcePathComponentNode> sourceNodeDeleter(
if (_CompareSourceFileNames(functions[i - 1]->SourceFile(), sourcelessNode);
functions[i]->SourceFile()) != 0) {
sourceFileCount++;
for (int32 i = 0; i < functionCount; i++) {
if (!_BuildFunctionSourcePath(functions[i], sourcelessNode))
return;
}
if (sourcelessNode->CountChildren() != 0) {
if (fChildPathComponents.BinaryInsert(sourcelessNode,
&SourcePathComponentNode::CompareComponents)) {
fSourcelessNode = sourcelessNode;
sourceNodeDeleter.Detach();
} }
} }
// allocate and init the indices for the source files NotifyNodesAdded(TreeTablePath(), 0,
fSourceFileIndices = new(std::nothrow) int32[sourceFileCount]; fChildPathComponents.CountItems());
if (fSourceFileIndices == NULL)
return;
fSourceFileCount = sourceFileCount;
fSourceFileIndices[0] = 0;
int32 sourceFileIndex = 1;
for (int32 i = 1; i < functionCount; i++) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFile(),
functions[i]->SourceFile()) != 0) {
fSourceFileIndices[sourceFileIndex++] = i;
}
}
fFunctions = functionsDeleter.Detach();
fFunctionCount = functionCount;
NotifyNodesAdded(TreeTablePath(), 0, fSourceFileCount);
} }
virtual int32 CountColumns() const virtual int32 CountColumns() const
@@ -139,34 +255,17 @@ public:
virtual int32 CountChildren(void* parent) const virtual int32 CountChildren(void* parent) const
{ {
if (parent == this) if (parent == this)
return fSourceFileCount; return fChildPathComponents.CountItems();
if (parent >= fSourceFileIndices return ((SourcePathComponentNode*)parent)->CountChildren();
&& parent < fSourceFileIndices + fSourceFileCount) {
int32 sourceIndex = (int32*)parent - fSourceFileIndices;
return _CountSourceFileFunctions(sourceIndex);
}
return 0;
} }
virtual void* ChildAt(void* parent, int32 index) const virtual void* ChildAt(void* parent, int32 index) const
{ {
if (parent == this) { if (parent == this)
return index >= 0 && index < fSourceFileCount return fChildPathComponents.ItemAt(index);
? fSourceFileIndices + index : NULL;
}
if (parent >= fSourceFileIndices return ((SourcePathComponentNode*)parent)->ChildAt(index);
&& parent < fSourceFileIndices + fSourceFileCount) {
int32 sourceIndex = (int32*)parent - fSourceFileIndices;
int32 count = _CountSourceFileFunctions(sourceIndex);
int32 firstFunctionIndex = fSourceFileIndices[sourceIndex];
return index >= 0 && index < count
? fFunctions[firstFunctionIndex + index] : NULL;
}
return NULL;
} }
virtual bool GetValueAt(void* object, int32 columnIndex, BVariant& value) virtual bool GetValueAt(void* object, int32 columnIndex, BVariant& value)
@@ -177,84 +276,168 @@ public:
if (object == this) if (object == this)
return false; return false;
if (object >= fSourceFileIndices SourcePathComponentNode* node = (SourcePathComponentNode*)object;
&& object < fSourceFileIndices + fSourceFileCount) {
int32 index = *(int32*)object;
if (LocatableFile* file = fFunctions[index]->SourceFile()) {
BString path;
file->GetPath(path);
value.SetTo(path);
} else
value.SetTo("<no source file>", B_VARIANT_DONT_COPY_DATA);
return true; value.SetTo(node->ComponentName(), B_VARIANT_DONT_COPY_DATA);
}
FunctionInstance* function = (FunctionInstance*)object;
value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA);
return true; return true;
} }
bool GetFunctionPath(FunctionInstance* function, TreeTablePath& _path) bool GetFunctionPath(FunctionInstance* function, TreeTablePath& _path)
{ {
int32 index = -1; if (function == NULL)
for (int32 i = 0; i < fFunctionCount; i++) { return false;
if (fFunctions[i] == function) {
index = i; LocatableFile* sourceFile = function->SourceFile();
break; SourcePathComponentNode* node = NULL;
int32 childIndex = -1;
if (sourceFile == NULL) {
node = fSourcelessNode;
_path.AddComponent(fChildPathComponents.IndexOf(node));
} else {
BString sourcePath;
sourceFile->GetPath(sourcePath);
if (sourcePath.IsEmpty())
return false;
BString searchPath;
while (!sourcePath.IsEmpty()) {
if (sourcePath[0] == '/')
sourcePath.Remove(0, 1);
int32 separatorIndex = sourcePath.FindFirst('/');
if (separatorIndex == -1) {
searchPath = sourcePath;
sourcePath.Truncate(0);
} else
sourcePath.MoveInto(searchPath, 0, separatorIndex);
if (node == NULL) {
childIndex = fChildPathComponents.BinarySearchIndexByKey(
searchPath,
&SourcePathComponentNode::CompareByComponentName);
node = fChildPathComponents.ItemAt(childIndex);
} else {
childIndex = node->FindChildIndexByName(searchPath);
node = node->ChildAt(childIndex);
}
if (childIndex < 0)
return false;
_path.AddComponent(childIndex);
} }
} }
if (index < 0) if (node == NULL)
return false; return false;
int32 sourceIndex = fSourceFileCount - 1; childIndex = node->FindChildIndexByName(function->PrettyName());
while (fSourceFileIndices[sourceIndex] > index) if (childIndex < 0)
sourceIndex--; return false;
_path.Clear(); _path.AddComponent(childIndex);
return _path.AddComponent(sourceIndex) return true;
&& _path.AddComponent(index - fSourceFileIndices[sourceIndex]);
} }
bool GetObjectForPath(const TreeTablePath& path, bool GetObjectForPath(const TreeTablePath& path,
LocatableFile*& _sourceFile, FunctionInstance*& _function) LocatableFile*& _sourceFile, FunctionInstance*& _function)
{ {
int32 componentCount = path.CountComponents(); SourcePathComponentNode* node = fChildPathComponents.ItemAt(
if (componentCount == 0 || componentCount > 2) path.ComponentAt(0));
if (node == NULL)
return false; return false;
int32 sourceIndex = path.ComponentAt(0); for (int32 i = 1; i < path.CountComponents(); i++)
if (sourceIndex < 0 || sourceIndex >= fSourceFileCount) node = node->ChildAt(path.ComponentAt(i));
return false;
_sourceFile = fFunctions[fSourceFileIndices[sourceIndex]]->SourceFile(); if (node != NULL) {
_sourceFile = node->SourceFile();
_function = NULL; _function = node->Function();
return true;
if (componentCount == 2) {
int32 index = path.ComponentAt(1);
if (index >= 0 && index < _CountSourceFileFunctions(sourceIndex))
_function = fFunctions[fSourceFileIndices[sourceIndex] + index];
} }
return true; return false;
}
int32 CountSourceFiles() const
{
return fSourceFileCount;
} }
private: private:
int32 _CountSourceFileFunctions(int32 sourceIndex) const bool _BuildFunctionSourcePath(FunctionInstance* function,
SourcePathComponentNode* sourcelessNode)
{ {
if (sourceIndex < 0 || sourceIndex >= fSourceFileCount) LocatableFile* sourceFile = function->SourceFile();
return 0; if (sourceFile == NULL)
return _AddFunctionNode(sourcelessNode, function, NULL);
int32 nextFunctionIndex = sourceIndex + 1 < fSourceFileCount BString sourcePath;
? fSourceFileIndices[sourceIndex + 1] : fFunctionCount; sourceFile->GetPath(sourcePath);
return nextFunctionIndex - fSourceFileIndices[sourceIndex]; if (sourcePath.IsEmpty())
return false;
return _AddNextPathComponent(NULL, sourcePath, function, sourceFile);
}
bool _AddNextPathComponent(SourcePathComponentNode* parent,
BString& childPath, FunctionInstance* function, LocatableFile* file)
{
if (childPath[0] == '/')
childPath.Remove(0, 1);
BString pathComponent;
int32 pathSeparatorIndex = childPath.FindFirst('/');
if (pathSeparatorIndex == -1)
pathComponent = childPath;
else
childPath.MoveInto(pathComponent, 0, pathSeparatorIndex);
SourcePathComponentNode* currentNode = NULL;
if (parent == NULL) {
currentNode = fChildPathComponents.BinarySearchByKey(pathComponent,
SourcePathComponentNode::CompareByComponentName);
} else
currentNode = parent->FindChildByName(pathComponent);
if (currentNode == NULL) {
currentNode = new(std::nothrow) SourcePathComponentNode(parent,
pathComponent, NULL, NULL);
if (currentNode == NULL)
return false;
ObjectDeleter<SourcePathComponentNode> nodeDeleter(currentNode);
if (parent != NULL) {
if (!parent->AddChild(currentNode))
return false;
} else {
if (!fChildPathComponents.BinaryInsert(currentNode,
&SourcePathComponentNode::CompareComponents)) {
return false;
}
}
nodeDeleter.Detach();
}
if (pathSeparatorIndex == -1)
return _AddFunctionNode(currentNode, function, file);
return _AddNextPathComponent(currentNode, childPath, function, file);
}
bool _AddFunctionNode(SourcePathComponentNode* parent,
FunctionInstance* function, LocatableFile* file)
{
SourcePathComponentNode* functionNode = new(std::nothrow)
SourcePathComponentNode(parent, function->PrettyName(), file,
function);
if (functionNode == NULL)
return B_NO_MEMORY;
ObjectDeleter<SourcePathComponentNode> nodeDeleter(functionNode);
if (!parent->AddChild(functionNode))
return false;
nodeDeleter.Detach();
return true;
} }
static int _CompareSourceFileNames(LocatableFile* a, LocatableFile* b) static int _CompareSourceFileNames(LocatableFile* a, LocatableFile* b)
@@ -290,11 +473,12 @@ private:
} }
private: private:
ImageDebugInfo* fImageDebugInfo; typedef BObjectList<SourcePathComponentNode> ChildPathComponentList;
FunctionInstance** fFunctions;
int32 fFunctionCount; private:
int32* fSourceFileIndices; ImageDebugInfo* fImageDebugInfo;
int32 fSourceFileCount; ChildPathComponentList fChildPathComponents;
SourcePathComponentNode* fSourcelessNode;
}; };
@@ -364,7 +548,7 @@ ImageFunctionsView::SetImageDebugInfo(ImageDebugInfo* imageDebugInfo)
// If there's only one source file (i.e. "no source file"), expand the item. // If there's only one source file (i.e. "no source file"), expand the item.
if (fImageDebugInfo != NULL if (fImageDebugInfo != NULL
&& fFunctionsTableModel->CountSourceFiles() == 1) { && fFunctionsTableModel->CountChildren(fFunctionsTableModel) == 1) {
TreeTablePath path; TreeTablePath path;
path.AddComponent(0); path.AddComponent(0);
fFunctionsTable->SetNodeExpanded(path, true, false); fFunctionsTable->SetNodeExpanded(path, true, false);
@@ -388,6 +572,7 @@ ImageFunctionsView::SetFunction(FunctionInstance* function)
fFunctionsTable->SetNodeExpanded(path, true, true); fFunctionsTable->SetNodeExpanded(path, true, true);
fFunctionsTable->SelectNode(path, false); fFunctionsTable->SelectNode(path, false);
fFunctionsTable->ScrollToNode(path); fFunctionsTable->ScrollToNode(path);
fFunctionsTable->ResizeAllColumnsToPreferred();
} else } else
fFunctionsTable->DeselectAllNodes(); fFunctionsTable->DeselectAllNodes();
} }
@@ -1,5 +1,6 @@
/* /*
* Copyright 2009, Ingo Weinhold, [email protected]. * Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2013, Rene Gollent, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef IMAGE_FUNCTIONS_VIEW_H #ifndef IMAGE_FUNCTIONS_VIEW_H
@@ -36,6 +37,7 @@ public:
private: private:
class FunctionsTableModel; class FunctionsTableModel;
class SourcePathComponentNode;
private: private:
// TreeTableListener // TreeTableListener