forked from OSchip/llvm-project
Lazily load the controlling macros for all of the headers known in the
PCH file. In the Cocoa-prefixed "Hello, World" benchmark, this takes us from reading 503 identifiers down to 37 and from 470 macros down to 4. It also results in an 8% performance improvement. llvm-svn: 70094
This commit is contained in:
parent
c06ce0f710
commit
99734e7669
|
@ -234,7 +234,20 @@ public:
|
|||
/// be found.
|
||||
virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0;
|
||||
};
|
||||
|
||||
|
||||
/// \brief An abstract class used to resolve numerical identifier
|
||||
/// references (meaningful only to some external source) into
|
||||
/// IdentifierInfo pointers.
|
||||
class ExternalIdentifierLookup {
|
||||
public:
|
||||
virtual ~ExternalIdentifierLookup();
|
||||
|
||||
/// \brief Return the identifier associated with the given ID number.
|
||||
///
|
||||
/// The ID 0 is associated with the NULL identifier.
|
||||
virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0;
|
||||
};
|
||||
|
||||
/// IdentifierTable - This table implements an efficient mapping from strings to
|
||||
/// IdentifierInfo nodes. It has no other purpose, but this is an
|
||||
/// extremely performance-critical piece of the code, as each occurrance of
|
||||
|
|
|
@ -64,7 +64,10 @@ class SwitchCase;
|
|||
/// The PCH reader provides lazy de-serialization of declarations, as
|
||||
/// required when traversing the AST. Only those AST nodes that are
|
||||
/// actually required will be de-serialized.
|
||||
class PCHReader : public ExternalSemaSource, public IdentifierInfoLookup {
|
||||
class PCHReader
|
||||
: public ExternalSemaSource,
|
||||
public IdentifierInfoLookup,
|
||||
public ExternalIdentifierLookup {
|
||||
public:
|
||||
enum PCHReadResult { Success, Failure, IgnorePCH };
|
||||
|
||||
|
@ -371,6 +374,10 @@ public:
|
|||
return DecodeIdentifierInfo(Record[Idx++]);
|
||||
}
|
||||
|
||||
virtual IdentifierInfo *GetIdentifier(unsigned ID) {
|
||||
return DecodeIdentifierInfo(ID);
|
||||
}
|
||||
|
||||
Selector DecodeSelector(unsigned Idx);
|
||||
|
||||
Selector GetSelector(const RecordData &Record, unsigned &Idx) {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ExternalIdentifierLookup;
|
||||
class FileEntry;
|
||||
class FileManager;
|
||||
class IdentifierInfo;
|
||||
|
@ -42,10 +44,27 @@ struct HeaderFileInfo {
|
|||
/// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard
|
||||
/// that protects the entire contents of the file, this is the identifier
|
||||
/// for the macro that controls whether or not it has any effect.
|
||||
///
|
||||
/// Note: Most clients should use getControllingMacro() to access
|
||||
/// the controlling macro of this header, since
|
||||
/// getControllingMacro() is able to load a controlling macro from
|
||||
/// external storage.
|
||||
const IdentifierInfo *ControllingMacro;
|
||||
|
||||
HeaderFileInfo() : isImport(false), DirInfo(SrcMgr::C_User),
|
||||
NumIncludes(0), ControllingMacro(0) {}
|
||||
|
||||
/// \brief The ID number of the controlling macro.
|
||||
///
|
||||
/// This ID number will be non-zero when there is a controlling
|
||||
/// macro whose IdentifierInfo may not yet have been loaded from
|
||||
/// external storage.
|
||||
unsigned ControllingMacroID;
|
||||
|
||||
HeaderFileInfo()
|
||||
: isImport(false), DirInfo(SrcMgr::C_User),
|
||||
NumIncludes(0), ControllingMacro(0), ControllingMacroID(0) {}
|
||||
|
||||
/// \brief Retrieve the controlling macro for this header file, if
|
||||
/// any.
|
||||
const IdentifierInfo *getControllingMacro(ExternalIdentifierLookup *External);
|
||||
};
|
||||
|
||||
/// HeaderSearch - This class encapsulates the information needed to find the
|
||||
|
@ -84,7 +103,11 @@ class HeaderSearch {
|
|||
/// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing
|
||||
/// headermaps. This vector owns the headermap.
|
||||
std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
|
||||
|
||||
|
||||
/// \brief Entity used to resolve the identifier IDs of controlling
|
||||
/// macros into IdentifierInfo pointers, as needed.
|
||||
ExternalIdentifierLookup *ExternalLookup;
|
||||
|
||||
// Various statistics we track for performance analysis.
|
||||
unsigned NumIncluded;
|
||||
unsigned NumMultiIncludeFileOptzn;
|
||||
|
@ -115,6 +138,10 @@ public:
|
|||
FileInfo.clear();
|
||||
}
|
||||
|
||||
void SetExternalLookup(ExternalIdentifierLookup *EIL) {
|
||||
ExternalLookup = EIL;
|
||||
}
|
||||
|
||||
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
|
||||
/// return null on failure. isAngled indicates whether the file reference is
|
||||
/// a <> reference. If successful, this returns 'UsedDir', the
|
||||
|
|
|
@ -42,6 +42,8 @@ IdentifierInfo::IdentifierInfo() {
|
|||
|
||||
IdentifierInfoLookup::~IdentifierInfoLookup() {}
|
||||
|
||||
ExternalIdentifierLookup::~ExternalIdentifierLookup() {}
|
||||
|
||||
IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
|
||||
IdentifierInfoLookup* externalLookup)
|
||||
: HashTable(8192), // Start with space for 8K identifiers.
|
||||
|
|
|
@ -1717,7 +1717,7 @@ bool PCHReader::ReadPreprocessorBlock() {
|
|||
HFI.isImport = Record[0];
|
||||
HFI.DirInfo = Record[1];
|
||||
HFI.NumIncludes = Record[2];
|
||||
HFI.ControllingMacro = DecodeIdentifierInfo(Record[3]);
|
||||
HFI.ControllingMacroID = Record[3];
|
||||
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
|
||||
break;
|
||||
}
|
||||
|
@ -1854,6 +1854,7 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
|
|||
}
|
||||
IdentifierOffsets = (const uint32_t *)BlobStart;
|
||||
IdentifiersLoaded.resize(Record[0]);
|
||||
PP.getHeaderSearchInfo().SetExternalLookup(this);
|
||||
break;
|
||||
|
||||
case pch::EXTERNAL_DEFINITIONS:
|
||||
|
|
|
@ -20,10 +20,23 @@
|
|||
#include <cstdio>
|
||||
using namespace clang;
|
||||
|
||||
const IdentifierInfo *
|
||||
HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
|
||||
if (ControllingMacro)
|
||||
return ControllingMacro;
|
||||
|
||||
if (!ControllingMacroID || !External)
|
||||
return 0;
|
||||
|
||||
ControllingMacro = External->GetIdentifier(ControllingMacroID);
|
||||
return ControllingMacro;
|
||||
}
|
||||
|
||||
HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) {
|
||||
SystemDirIdx = 0;
|
||||
NoCurDirSearch = false;
|
||||
|
||||
|
||||
ExternalLookup = 0;
|
||||
NumIncluded = 0;
|
||||
NumMultiIncludeFileOptzn = 0;
|
||||
NumFrameworkLookups = NumSubFrameworkLookups = 0;
|
||||
|
@ -417,11 +430,12 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
|
|||
|
||||
// Next, check to see if the file is wrapped with #ifndef guards. If so, and
|
||||
// if the macro that guards it is defined, we know the #include has no effect.
|
||||
if (FileInfo.ControllingMacro &&
|
||||
FileInfo.ControllingMacro->hasMacroDefinition()) {
|
||||
++NumMultiIncludeFileOptzn;
|
||||
return false;
|
||||
}
|
||||
if (const IdentifierInfo *ControllingMacro
|
||||
= FileInfo.getControllingMacro(ExternalLookup))
|
||||
if (ControllingMacro->hasMacroDefinition()) {
|
||||
++NumMultiIncludeFileOptzn;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increment the number of times this file has been included.
|
||||
++FileInfo.NumIncludes;
|
||||
|
|
Loading…
Reference in New Issue