summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2025-07-01 19:52:14 -0400
committerRusty Wagner <rusty.wagner@gmail.com>2025-07-03 12:43:48 -0400
commitb4918a512bef271d7f6e27980ea875208c7f2954 (patch)
tree9708e48bbaa6d9dc0352c50c0b1aac0279283e59
parentb26a85dda211a0f1f00eecc37441e1725c5ef898 (diff)
Reduce number of refreshes and memory usage of cross references widget.
* Generates IL for cross references only when visible instead of all at once. * Releases memory for IL after the cross references retrieves the tokens. * Much faster algorithm for updating IL when functions change. * Don't refresh cross references at all if the widget isn't visible. Retreiving the new set of cross references is deferred until the widget becomes visible again. * Don't redo the query for the list of cross references when anything in the entire UI changes, even the window layout. Only recompute the list when an event for a new cross reference selection comes in.
-rw-r--r--function.cpp3
-rw-r--r--ui/xreflist.h51
2 files changed, 44 insertions, 10 deletions
diff --git a/function.cpp b/function.cpp
index 367dbe80..19d3fbc7 100644
--- a/function.cpp
+++ b/function.cpp
@@ -3566,6 +3566,9 @@ AdvancedFunctionAnalysisDataRequestor& AdvancedFunctionAnalysisDataRequestor::op
void AdvancedFunctionAnalysisDataRequestor::SetFunction(Function* func)
{
+ if (m_func.GetPtr() == func)
+ return;
+
if (m_func)
m_func->ReleaseAdvancedAnalysisData();
diff --git a/ui/xreflist.h b/ui/xreflist.h
index ee6c7bf1..867ebef0 100644
--- a/ui/xreflist.h
+++ b/ui/xreflist.h
@@ -76,6 +76,8 @@ class XrefItem
XrefQueryKind m_queryKind;
XrefDirection m_direction;
mutable std::vector<BinaryNinja::InstructionTextToken> m_cachedTokens;
+ mutable uint64_t m_cachedTokenVersion = 0;
+ mutable std::optional<BinaryNinja::AdvancedFunctionAnalysisDataRequestor> m_advancedAnalysisRequest;
mutable XrefHeader* m_parentItem;
mutable int m_size;
@@ -107,9 +109,13 @@ class XrefItem
int size() const { return m_size; }
void setSize(int size) const { m_size = size; }
void setParent(XrefHeader* parent) const;
- void setCachedTokens(const std::vector<BinaryNinja::InstructionTextToken>& cachedTokens) const { m_cachedTokens = cachedTokens; }
+ void setCachedTokens(const std::vector<BinaryNinja::InstructionTextToken>& cachedTokens, uint64_t version) const;
std::vector<BinaryNinja::InstructionTextToken> cachedTokens() const { return m_cachedTokens; }
+ uint64_t cachedTokenVersion() const { return m_cachedTokenVersion; }
bool hasCachedTokens() const { return m_cachedTokens.size() > 0; }
+ bool cachedTokensValidForVersion(uint64_t version) const { return m_cachedTokenVersion == version; }
+ void requestAdvancedAnalysis() const;
+ void clearAdvancedAnalysisRequest() const { m_advancedAnalysisRequest.reset(); }
virtual XrefItem* parent() const { return (XrefItem*)m_parentItem; }
virtual XrefItem* child(int) const { return nullptr; }
virtual int childCount() const { return 0; }
@@ -311,7 +317,23 @@ class XrefRoot : public XrefHeader
/*!
- \ingroup xreflist
+ \ingroup xreflist
+*/
+struct CrossReferenceFunctionList
+{
+ std::unordered_map<uint64_t, uint64_t> functionVersions;
+ uint64_t nextVersion = 1;
+ bool hasUpdates = true;
+
+ void updateForRefs(const std::vector<XrefItem>& refs);
+ void updateFunction(BinaryNinja::Function* func);
+ std::optional<uint64_t> getFunctionVersion(BinaryNinja::Function* func) const;
+ bool checkForUpdates();
+};
+
+/*!
+
+ \ingroup xreflist
*/
class BINARYNINJAUIAPI CrossReferenceTreeModel : public QAbstractItemModel
{
@@ -322,10 +344,10 @@ class BINARYNINJAUIAPI CrossReferenceTreeModel : public QAbstractItemModel
BinaryViewRef m_data;
ViewFrame* m_view;
std::vector<XrefItem> m_refs;
+ CrossReferenceFunctionList m_funcs;
size_t m_maxUIItems;
std::optional<BinaryNinja::FunctionViewType> m_graphType;
SelectionInfoForXref m_curRef;
- QTimer* m_updateTimer;
public:
CrossReferenceTreeModel(QWidget* parent, BinaryViewRef data, ViewFrame* view);
@@ -348,9 +370,9 @@ class BINARYNINJAUIAPI CrossReferenceTreeModel : public QAbstractItemModel
virtual void updateMaxUIItems(size_t value) { m_maxUIItems = value; }
size_t getMaxUIItems() const { return m_maxUIItems; }
void setGraphType(const BinaryNinja::FunctionViewType& type);
- void requestAdvancedAnalysis();
+ void notifyRefresh();
- Q_SIGNALS:
+Q_SIGNALS:
void needRepaint();
public Q_SLOTS:
@@ -370,10 +392,10 @@ class BINARYNINJAUIAPI CrossReferenceTableModel : public QAbstractTableModel
BinaryViewRef m_data;
ViewFrame* m_view;
std::vector<XrefItem> m_refs;
+ CrossReferenceFunctionList m_funcs;
size_t m_maxUIItems;
std::optional<BinaryNinja::FunctionViewType> m_graphType;
SelectionInfoForXref m_curRef;
- QTimer* m_updateTimer;
public:
enum ColumnHeaders
@@ -413,8 +435,9 @@ class BINARYNINJAUIAPI CrossReferenceTableModel : public QAbstractTableModel
virtual void updateMaxUIItems(size_t value) { m_maxUIItems = value; }
size_t getMaxUIItems() const { return m_maxUIItems; }
void setGraphType(const BinaryNinja::FunctionViewType& type);
- void requestAdvancedAnalysis();
- Q_SIGNALS:
+ void notifyRefresh();
+
+Q_SIGNALS:
void needRepaint();
public Q_SLOTS:
@@ -551,8 +574,9 @@ public:
virtual void updateMaxUIItems(size_t count) override;
void setGraphType(const BinaryNinja::FunctionViewType& type) { m_tree->setGraphType(type); }
virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override;
+ void notifyRefresh();
- Q_SIGNALS:
+Q_SIGNALS:
void newSelection();
void modelUpdated();
void functionUpdated(FunctionRef func);
@@ -595,8 +619,9 @@ class BINARYNINJAUIAPI CrossReferenceTable : public QTableView, public CrossRefe
virtual void updateMaxUIItems(size_t count) override;
void setGraphType(const BinaryNinja::FunctionViewType& type) { m_table->setGraphType(type); }
virtual void OnAnalysisFunctionUpdated(BinaryNinja::BinaryView* view, BinaryNinja::Function* func) override;
+ void notifyRefresh();
- public Q_SLOTS:
+public Q_SLOTS:
void doRepaint();
void updateTextFilter(const QString& filterText);
@@ -640,6 +665,7 @@ class BINARYNINJAUIAPI CrossReferenceWidget : public SidebarWidget, public UICon
bool m_curRefTargetValid = false;
SelectionInfoForXref m_curRef;
SelectionInfoForXref m_newRef;
+ std::optional<SelectionInfoForXref> m_pendingSelection;
bool m_navigating = false;
bool m_navToNextOrPrevStarted = false;
bool m_pinned;
@@ -648,6 +674,8 @@ class BINARYNINJAUIAPI CrossReferenceWidget : public SidebarWidget, public UICon
QWidget* m_header = nullptr;
+ QTimer* m_updateTimer = nullptr;
+
virtual void contextMenuEvent(QContextMenuEvent* event) override;
virtual void wheelEvent(QWheelEvent* e) override;
@@ -686,6 +714,9 @@ class BINARYNINJAUIAPI CrossReferenceWidget : public SidebarWidget, public UICon
virtual QWidget* headerWidget() override { return m_header; }
virtual void setPrimaryOrientation(Qt::Orientation orientation) override;
+ void notifyRefresh() override;
+ void notifyQuiesce(bool quiesce) override;
+
private Q_SLOTS:
void hoverTimerEvent();
void newPinnedPane();