/// \brief Read the source location entry with index ID.
virtual void ReadSLocEntry(unsigned ID) = 0;
};
+
+
+/// IsBeforeInTranslationUnitCache - This class holds the cache used by
+/// isBeforeInTranslationUnit. The cache structure is complex enough to be
+/// worth breaking out of SourceManager.
+class IsBeforeInTranslationUnitCache {
+ /// L/R QueryFID - These are the FID's of the cached query. If these match up
+ /// with a subsequent query, the result can be reused.
+ FileID LQueryFID, RQueryFID;
+
+ /// CommonFID - This is the file found in common between the two #include
+ /// traces. It is the nearest common ancestor of the #include tree.
+ FileID CommonFID;
+
+ /// L/R CommonOffset - This is the offset of the previous query in CommonFID.
+ /// Usually, this represents the location of the #include for QueryFID, but if
+ /// LQueryFID is a parent of RQueryFID (or vise versa) then these can be a
+ /// random token in the parent.
+ unsigned LCommonOffset, RCommonOffset;
+public:
+
+ /// isCacheValid - Return true if the currently cached values match up with
+ /// the specified LHS/RHS query. If not, we can't use the cache.
+ bool isCacheValid(FileID LHS, FileID RHS) const {
+ return LQueryFID == LHS && RQueryFID == RHS;
+ }
+
+ /// getCachedResult - If the cache is valid, compute the result given the
+ /// specified offsets in the LHS/RHS FID's.
+ bool getCachedResult(unsigned LOffset, unsigned ROffset) const {
+ // If one of the query files is the common file, use the offset. Otherwise,
+ // use the #include loc in the common file.
+ if (LQueryFID != CommonFID) LOffset = LCommonOffset;
+ if (RQueryFID != CommonFID) ROffset = RCommonOffset;
+ return LOffset < ROffset;
+ }
+
+ // Set up a new query.
+ void setQueryFIDs(FileID LHS, FileID RHS) {
+ LQueryFID = LHS;
+ RQueryFID = RHS;
+ }
+
+ void setCommonLoc(FileID commonFID, unsigned lCommonOffset,
+ unsigned rCommonOffset) {
+ CommonFID = commonFID;
+ LCommonOffset = lCommonOffset;
+ RCommonOffset = rCommonOffset;
+ }
+
+};
/// SourceManager - This file handles loading and caching of source files into
/// memory. This object owns the MemoryBuffer objects for all of the loaded
mutable unsigned NumLinearScans, NumBinaryProbes;
// Cache results for the isBeforeInTranslationUnit method.
- mutable FileID LastLFIDForBeforeTUCheck;
- mutable FileID LastRFIDForBeforeTUCheck;
- mutable bool LastResForBeforeTUCheck;
+ mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache;
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&);
if (LOffs.first == ROffs.first)
return LOffs.second < ROffs.second;
-#if 0
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
+ bool Cached = false;
+ bool CachedResult = false;
+ if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first)) {
+ Cached = true;
+ CachedResult = IsBeforeInTUCache.getCachedResult(LOffs.second,ROffs.second);
+ }
- // FIXME: This caching is wrong, but I don't know enough about this code
- // to immediately fix it. There are cases where passing the same input
- // values to this method causes it to return different results.
- if (LastLFIDForBeforeTUCheck == LOffs.first &&
- LastRFIDForBeforeTUCheck == ROffs.first)
- return LastResForBeforeTUCheck;
-
- LastLFIDForBeforeTUCheck = LOffs.first;
- LastRFIDForBeforeTUCheck = ROffs.first;
-#endif
+ // Okay, we missed in the cache, start updating the cache for this query.
+ IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first);
// "Traverse" the include/instantiation stacks of both locations and try to
// find a common "ancestor".
// First we traverse the stack of the right location and check each level
// against the level of the left location, while collecting all levels in a
// "stack map".
-
std::map<FileID, unsigned> ROffsMap;
ROffsMap[ROffs.first] = ROffs.second;
ROffs = getDecomposedLoc(UpperLoc);
- if (LOffs.first == ROffs.first)
- return LastResForBeforeTUCheck = LOffs.second < ROffs.second;
+ // If we found a common file, cache and return our answer!
+ if (LOffs.first == ROffs.first) {
+ IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
+ bool Result = IsBeforeInTUCache.getCachedResult(LOffs.second,
+ ROffs.second);
+ assert(!Cached || CachedResult == Result); // Validate Cache.
+ return Result;
+ }
ROffsMap[ROffs.first] = ROffs.second;
}
// We didn't find a common ancestor. Now traverse the stack of the left
// location, checking against the stack map of the right location.
-
while (1) {
SourceLocation UpperLoc;
const SrcMgr::SLocEntry &Entry = getSLocEntry(LOffs.first);
LOffs = getDecomposedLoc(UpperLoc);
std::map<FileID, unsigned>::iterator I = ROffsMap.find(LOffs.first);
- if (I != ROffsMap.end())
- return LastResForBeforeTUCheck = LOffs.second < I->second;
+ if (I != ROffsMap.end()) {
+ IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, I->second);
+
+ bool Result = IsBeforeInTUCache.getCachedResult(LOffs.second, I->second);
+ assert(!Cached || CachedResult == Result); // Validate Cache.
+ return Result;
+ }
}
// There is no common ancestor, most probably because one location is in the
// If exactly one location is a memory buffer, assume it preceeds the other.
bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry;
bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry;
- if (LIsMB != RIsMB)
- return LastResForBeforeTUCheck = LIsMB;
+ if (LIsMB != RIsMB) {
+ IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching.
+ assert(!Cached);
+ return LIsMB;
+ }
// Otherwise, just assume FileIDs were created in order.
- return LastResForBeforeTUCheck = (LOffs.first < ROffs.first);
+ IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching.
+ assert(!Cached);
+ return LOffs.first < ROffs.first;
}
/// PrintStats - Print statistics to stderr.