From c910aa5a42fb789225bb58c990d077d39da9b4ce Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 31 Aug 2016 17:21:53 -0400 Subject: Cache lines on API side to avoid UI hangs with large basic blocks --- binaryninjaapi.h | 11 ++++++++--- functiongraph.cpp | 30 +++++++++++++++++++++++++++--- functiongraphblock.cpp | 20 ++++++++++++++++---- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 6902c1a3..fed1bbd9 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1694,6 +1694,10 @@ namespace BinaryNinja class FunctionGraphBlock: public CoreRefCountObject { + std::vector m_cachedLines; + std::vector m_cachedEdges; + bool m_cachedLinesValid, m_cachedEdgesValid; + public: FunctionGraphBlock(BNFunctionGraphBlock* block); @@ -1705,14 +1709,15 @@ namespace BinaryNinja int GetWidth() const; int GetHeight() const; - std::vector GetLines() const; - std::vector GetOutgoingEdges() const; + const std::vector& GetLines(); + const std::vector& GetOutgoingEdges(); }; class FunctionGraph: public RefCountObject { BNFunctionGraph* m_graph; std::function m_completeFunc; + std::map> m_cachedBlocks; static void CompleteCallback(void* ctxt); @@ -1735,7 +1740,7 @@ namespace BinaryNinja void OnComplete(const std::function& func); void Abort(); - std::vector> GetBlocks() const; + std::vector> GetBlocks(); int GetWidth() const; int GetHeight() const; diff --git a/functiongraph.cpp b/functiongraph.cpp index 93f60f63..30e2e165 100644 --- a/functiongraph.cpp +++ b/functiongraph.cpp @@ -104,14 +104,26 @@ void FunctionGraph::Abort() } -vector> FunctionGraph::GetBlocks() const +vector> FunctionGraph::GetBlocks() { size_t count; BNFunctionGraphBlock** blocks = BNGetFunctionGraphBlocks(m_graph, &count); vector> result; for (size_t i = 0; i < count; i++) - result.push_back(new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i]))); + { + auto block = m_cachedBlocks.find(blocks[i]); + if (block == m_cachedBlocks.end()) + { + FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i])); + m_cachedBlocks[blocks[i]] = newBlock; + result.push_back(newBlock); + } + else + { + result.push_back(block->second); + } + } BNFreeFunctionGraphBlockList(blocks, count); return result; @@ -137,7 +149,19 @@ vector> FunctionGraph::GetBlocksInRegion(int left, int t vector> result; for (size_t i = 0; i < count; i++) - result.push_back(new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i]))); + { + auto block = m_cachedBlocks.find(blocks[i]); + if (block == m_cachedBlocks.end()) + { + FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i])); + m_cachedBlocks[blocks[i]] = newBlock; + result.push_back(newBlock); + } + else + { + result.push_back(block->second); + } + } BNFreeFunctionGraphBlockList(blocks, count); return result; diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp index af330497..436339f6 100644 --- a/functiongraphblock.cpp +++ b/functiongraphblock.cpp @@ -27,6 +27,8 @@ using namespace std; FunctionGraphBlock::FunctionGraphBlock(BNFunctionGraphBlock* block) { m_object = block; + m_cachedLinesValid = false; + m_cachedEdgesValid = false; } @@ -72,8 +74,11 @@ int FunctionGraphBlock::GetHeight() const } -vector FunctionGraphBlock::GetLines() const +const vector& FunctionGraphBlock::GetLines() { + if (m_cachedLinesValid) + return m_cachedLines; + size_t count; BNDisassemblyTextLine* lines = BNGetFunctionGraphBlockLines(m_object, &count); @@ -96,12 +101,17 @@ vector FunctionGraphBlock::GetLines() const } BNFreeDisassemblyTextLines(lines, count); - return result; + m_cachedLines = result; + m_cachedLinesValid = true; + return m_cachedLines; } -vector FunctionGraphBlock::GetOutgoingEdges() const +const vector& FunctionGraphBlock::GetOutgoingEdges() { + if (m_cachedEdgesValid) + return m_cachedEdges; + size_t count; BNFunctionGraphEdge* edges = BNGetFunctionGraphBlockOutgoingEdges(m_object, &count); @@ -117,5 +127,7 @@ vector FunctionGraphBlock::GetOutgoingEdges() const } BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count); - return result; + m_cachedEdges = result; + m_cachedEdgesValid = true; + return m_cachedEdges; } -- cgit v1.3.1