[Source manager] Improve the performance of findBufferContainingLocInternal()

This function was performing a linear scan through the set of known
buffers to find the buffer containing a given source location. This
linear scan can show up in hot loops, and the number of buffers in a
program is increasing due to macros, so this has become a performance
problem.

Replace the linear scan with a logarithmic lookup into a sorted vector
of the buffer IDs, with a one-element most-recently-used cache so that
repeated lookups in the same buffer require constant time.

This mirrors what we already do with source files in a module.
Unfortunately, we cannot reuse that code because there is no link from
buffers to source files. We should look to consolidate this in the
future.

Fixes rdar://116184248.
This commit is contained in:
Doug Gregor
2023-10-04 14:32:41 -07:00
parent 69ec45dfdb
commit f36d2d3978
2 changed files with 130 additions and 9 deletions

View File

@@ -21,6 +21,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/Support/SourceMgr.h"
#include <map>
#include <vector>
namespace swift {
@@ -134,6 +135,28 @@ private:
std::map<const char *, VirtualFile> VirtualFiles;
mutable std::pair<const char *, const VirtualFile*> CachedVFile = {nullptr, nullptr};
/// A cache that improves the speed of location -> buffer lookups.
struct BufferLocCache {
/// The set of memory buffers IDs, sorted by the start of their source range.
std::vector<unsigned> sortedBuffers;
/// The number of buffers that were present when sortedBuffers was formed.
///
/// There can be multiple buffers that refer to the same source range,
/// and we remove duplicates as part of the processing of forming the
/// vector of sorted buffers. This number is the number of original buffers,
/// used to determine when the sorted buffers are out of date.
unsigned numBuffersOriginal = 0;
/// The last buffer we looked in. This acts as a one-element MRU cache for
/// lookups based on source locations.
llvm::Optional<unsigned> lastBufferID;
};
/// The cache that's used to quickly map a source location to a particular
/// buffer ID.
mutable BufferLocCache LocCache;
llvm::Optional<unsigned> findBufferContainingLocInternal(SourceLoc Loc) const;
public: