зеркало из https://github.com/microsoft/clang-1.git
Implement caching of stat() calls for precompiled headers, which is
essentially the same thing we do with pretokenized headers. stat() caching improves performance of the Cocoa-prefixed "Hello, World" by 45%. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70223 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
8e03444e92
Коммит
4fed3f47f6
|
@ -81,7 +81,31 @@ public:
|
||||||
virtual ~StatSysCallCache() {}
|
virtual ~StatSysCallCache() {}
|
||||||
virtual int stat(const char *path, struct stat *buf) = 0;
|
virtual int stat(const char *path, struct stat *buf) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief A stat listener that can be used by FileManager to keep
|
||||||
|
/// track of the results of stat() calls that occur throughout the
|
||||||
|
/// execution of the front end.
|
||||||
|
class MemorizeStatCalls : public StatSysCallCache {
|
||||||
|
public:
|
||||||
|
/// \brief The result of a stat() call.
|
||||||
|
///
|
||||||
|
/// The first member is the result of calling stat(). If stat()
|
||||||
|
/// found something, the second member is a copy of the stat
|
||||||
|
/// structure.
|
||||||
|
typedef std::pair<int, struct stat> StatResult;
|
||||||
|
|
||||||
|
/// \brief The set of stat() calls that have been
|
||||||
|
llvm::StringMap<StatResult, llvm::BumpPtrAllocator> StatCalls;
|
||||||
|
|
||||||
|
typedef llvm::StringMap<StatResult, llvm::BumpPtrAllocator>::const_iterator
|
||||||
|
iterator;
|
||||||
|
|
||||||
|
iterator begin() const { return StatCalls.begin(); }
|
||||||
|
iterator end() const { return StatCalls.end(); }
|
||||||
|
|
||||||
|
virtual int stat(const char *path, struct stat *buf);
|
||||||
|
};
|
||||||
|
|
||||||
/// FileManager - Implements support for file system lookup, file system
|
/// FileManager - Implements support for file system lookup, file system
|
||||||
/// caching, and directory search management. This also handles more advanced
|
/// caching, and directory search management. This also handles more advanced
|
||||||
/// properties, such as uniquing files based on "inode", so that a file with two
|
/// properties, such as uniquing files based on "inode", so that a file with two
|
||||||
|
|
|
@ -185,7 +185,10 @@ namespace clang {
|
||||||
/// This set contains the source location entry for the
|
/// This set contains the source location entry for the
|
||||||
/// predefines buffer and for any file entries that need to be
|
/// predefines buffer and for any file entries that need to be
|
||||||
/// preloaded.
|
/// preloaded.
|
||||||
SOURCE_LOCATION_PRELOADS = 16
|
SOURCE_LOCATION_PRELOADS = 16,
|
||||||
|
|
||||||
|
/// \brief Record code for the stat() cache.
|
||||||
|
STAT_CACHE = 17
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Record types used within a source manager block.
|
/// \brief Record types used within a source manager block.
|
||||||
|
|
|
@ -226,6 +226,10 @@ private:
|
||||||
/// been de-serialized.
|
/// been de-serialized.
|
||||||
std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs;
|
std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs;
|
||||||
|
|
||||||
|
/// \brief The number of stat() calls that hit/missed the stat
|
||||||
|
/// cache.
|
||||||
|
unsigned NumStatHits, NumStatMisses;
|
||||||
|
|
||||||
/// \brief The number of source location entries de-serialized from
|
/// \brief The number of source location entries de-serialized from
|
||||||
/// the PCH file.
|
/// the PCH file.
|
||||||
unsigned NumSLocEntriesRead;
|
unsigned NumSLocEntriesRead;
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace clang {
|
||||||
|
|
||||||
class ASTContext;
|
class ASTContext;
|
||||||
class LabelStmt;
|
class LabelStmt;
|
||||||
|
class MemorizeStatCalls;
|
||||||
class Preprocessor;
|
class Preprocessor;
|
||||||
class Sema;
|
class Sema;
|
||||||
class SourceManager;
|
class SourceManager;
|
||||||
|
@ -161,6 +162,7 @@ private:
|
||||||
void WriteBlockInfoBlock();
|
void WriteBlockInfoBlock();
|
||||||
void WriteTargetTriple(const TargetInfo &Target);
|
void WriteTargetTriple(const TargetInfo &Target);
|
||||||
void WriteLanguageOptions(const LangOptions &LangOpts);
|
void WriteLanguageOptions(const LangOptions &LangOpts);
|
||||||
|
void WriteStatCache(MemorizeStatCalls &StatCalls);
|
||||||
void WriteSourceManagerBlock(SourceManager &SourceMgr,
|
void WriteSourceManagerBlock(SourceManager &SourceMgr,
|
||||||
const Preprocessor &PP);
|
const Preprocessor &PP);
|
||||||
void WritePreprocessor(const Preprocessor &PP);
|
void WritePreprocessor(const Preprocessor &PP);
|
||||||
|
@ -183,7 +185,7 @@ public:
|
||||||
PCHWriter(llvm::BitstreamWriter &Stream);
|
PCHWriter(llvm::BitstreamWriter &Stream);
|
||||||
|
|
||||||
/// \brief Write a precompiled header for the given semantic analysis.
|
/// \brief Write a precompiled header for the given semantic analysis.
|
||||||
void WritePCH(Sema &SemaRef);
|
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls);
|
||||||
|
|
||||||
/// \brief Emit a source location.
|
/// \brief Emit a source location.
|
||||||
void AddSourceLocation(SourceLocation Loc, RecordData &Record);
|
void AddSourceLocation(SourceLocation Loc, RecordData &Record);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "clang/Basic/FileManager.h"
|
#include "clang/Basic/FileManager.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
#include "llvm/System/Path.h"
|
||||||
#include "llvm/Support/Streams.h"
|
#include "llvm/Support/Streams.h"
|
||||||
#include "llvm/Config/config.h"
|
#include "llvm/Config/config.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -282,3 +283,20 @@ void FileManager::PrintStats() const {
|
||||||
|
|
||||||
//llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
|
//llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MemorizeStatCalls::stat(const char *path, struct stat *buf) {
|
||||||
|
int result = ::stat(path, buf);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
// Cache failed 'stat' results.
|
||||||
|
struct stat empty;
|
||||||
|
StatCalls[path] = StatResult(result, empty);
|
||||||
|
}
|
||||||
|
else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) {
|
||||||
|
// Cache file 'stat' results and directories with absolutely
|
||||||
|
// paths.
|
||||||
|
StatCalls[path] = StatResult(result, *buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <sys/stat.h>
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -43,7 +44,8 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext &Context)
|
||||||
IdentifierOffsets(0),
|
IdentifierOffsets(0),
|
||||||
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
||||||
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
|
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
|
||||||
TotalNumSelectors(0), NumSLocEntriesRead(0), NumStatementsRead(0),
|
TotalNumSelectors(0), NumStatHits(0), NumStatMisses(0),
|
||||||
|
NumSLocEntriesRead(0), NumStatementsRead(0),
|
||||||
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
|
NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
|
||||||
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
|
NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
|
||||||
|
|
||||||
|
@ -377,6 +379,10 @@ bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Source Manager Deserialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// \brief Read the line table in the source manager block.
|
/// \brief Read the line table in the source manager block.
|
||||||
/// \returns true if ther was an error.
|
/// \returns true if ther was an error.
|
||||||
static bool ParseLineTable(SourceManager &SourceMgr,
|
static bool ParseLineTable(SourceManager &SourceMgr,
|
||||||
|
@ -420,6 +426,115 @@ static bool ParseLineTable(SourceManager &SourceMgr,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class VISIBILITY_HIDDEN PCHStatData {
|
||||||
|
public:
|
||||||
|
const bool hasStat;
|
||||||
|
const ino_t ino;
|
||||||
|
const dev_t dev;
|
||||||
|
const mode_t mode;
|
||||||
|
const time_t mtime;
|
||||||
|
const off_t size;
|
||||||
|
|
||||||
|
PCHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
|
||||||
|
: hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
|
||||||
|
|
||||||
|
PCHStatData()
|
||||||
|
: hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VISIBILITY_HIDDEN PCHStatLookupTrait {
|
||||||
|
public:
|
||||||
|
typedef const char *external_key_type;
|
||||||
|
typedef const char *internal_key_type;
|
||||||
|
|
||||||
|
typedef PCHStatData data_type;
|
||||||
|
|
||||||
|
static unsigned ComputeHash(const char *path) {
|
||||||
|
return BernsteinHash(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static internal_key_type GetInternalKey(const char *path) { return path; }
|
||||||
|
|
||||||
|
static bool EqualKey(internal_key_type a, internal_key_type b) {
|
||||||
|
return strcmp(a, b) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<unsigned, unsigned>
|
||||||
|
ReadKeyDataLength(const unsigned char*& d) {
|
||||||
|
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
|
||||||
|
unsigned DataLen = (unsigned) *d++;
|
||||||
|
return std::make_pair(KeyLen + 1, DataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static internal_key_type ReadKey(const unsigned char *d, unsigned) {
|
||||||
|
return (const char *)d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static data_type ReadData(const internal_key_type, const unsigned char *d,
|
||||||
|
unsigned /*DataLen*/) {
|
||||||
|
using namespace clang::io;
|
||||||
|
|
||||||
|
if (*d++ == 1)
|
||||||
|
return data_type();
|
||||||
|
|
||||||
|
ino_t ino = (ino_t) ReadUnalignedLE32(d);
|
||||||
|
dev_t dev = (dev_t) ReadUnalignedLE32(d);
|
||||||
|
mode_t mode = (mode_t) ReadUnalignedLE16(d);
|
||||||
|
time_t mtime = (time_t) ReadUnalignedLE64(d);
|
||||||
|
off_t size = (off_t) ReadUnalignedLE64(d);
|
||||||
|
return data_type(ino, dev, mode, mtime, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief stat() cache for precompiled headers.
|
||||||
|
///
|
||||||
|
/// This cache is very similar to the stat cache used by pretokenized
|
||||||
|
/// headers.
|
||||||
|
class VISIBILITY_HIDDEN PCHStatCache : public StatSysCallCache {
|
||||||
|
typedef OnDiskChainedHashTable<PCHStatLookupTrait> CacheTy;
|
||||||
|
CacheTy *Cache;
|
||||||
|
|
||||||
|
unsigned &NumStatHits, &NumStatMisses;
|
||||||
|
public:
|
||||||
|
PCHStatCache(const unsigned char *Buckets,
|
||||||
|
const unsigned char *Base,
|
||||||
|
unsigned &NumStatHits,
|
||||||
|
unsigned &NumStatMisses)
|
||||||
|
: Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) {
|
||||||
|
Cache = CacheTy::Create(Buckets, Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PCHStatCache() { delete Cache; }
|
||||||
|
|
||||||
|
int stat(const char *path, struct stat *buf) {
|
||||||
|
// Do the lookup for the file's data in the PCH file.
|
||||||
|
CacheTy::iterator I = Cache->find(path);
|
||||||
|
|
||||||
|
// If we don't get a hit in the PCH file just forward to 'stat'.
|
||||||
|
if (I == Cache->end()) {
|
||||||
|
++NumStatMisses;
|
||||||
|
return ::stat(path, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
++NumStatHits;
|
||||||
|
PCHStatData Data = *I;
|
||||||
|
|
||||||
|
if (!Data.hasStat)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
buf->st_ino = Data.ino;
|
||||||
|
buf->st_dev = Data.dev;
|
||||||
|
buf->st_mtime = Data.mtime;
|
||||||
|
buf->st_mode = Data.mode;
|
||||||
|
buf->st_size = Data.size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
/// \brief Read the source manager block
|
/// \brief Read the source manager block
|
||||||
PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
|
PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() {
|
||||||
using namespace SrcMgr;
|
using namespace SrcMgr;
|
||||||
|
@ -916,6 +1031,13 @@ PCHReader::ReadPCHBlock() {
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case pch::STAT_CACHE:
|
||||||
|
PP.getFileManager().setStatCache(
|
||||||
|
new PCHStatCache((const unsigned char *)BlobStart + Record[0],
|
||||||
|
(const unsigned char *)BlobStart,
|
||||||
|
NumStatHits, NumStatMisses));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Error("Premature end of bitstream");
|
Error("Premature end of bitstream");
|
||||||
|
@ -1505,6 +1627,8 @@ void PCHReader::PrintStats() {
|
||||||
SelectorsLoaded.end(),
|
SelectorsLoaded.end(),
|
||||||
Selector());
|
Selector());
|
||||||
|
|
||||||
|
std::fprintf(stderr, " %u stat cache hits\n", NumStatHits);
|
||||||
|
std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses);
|
||||||
if (TotalNumSLocEntries)
|
if (TotalNumSLocEntries)
|
||||||
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
|
std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n",
|
||||||
NumSLocEntriesRead, TotalNumSLocEntries,
|
NumSLocEntriesRead, TotalNumSLocEntries,
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace {
|
||||||
pch::TypeCode Code;
|
pch::TypeCode Code;
|
||||||
|
|
||||||
PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
|
PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record)
|
||||||
: Writer(Writer), Record(Record) { }
|
: Writer(Writer), Record(Record), Code(pch::TYPE_EXT_QUAL) { }
|
||||||
|
|
||||||
void VisitArrayType(const ArrayType *T);
|
void VisitArrayType(const ArrayType *T);
|
||||||
void VisitFunctionType(const FunctionType *T);
|
void VisitFunctionType(const FunctionType *T);
|
||||||
|
@ -354,6 +354,7 @@ void PCHWriter::WriteBlockInfoBlock() {
|
||||||
RECORD(PP_COUNTER_VALUE);
|
RECORD(PP_COUNTER_VALUE);
|
||||||
RECORD(SOURCE_LOCATION_OFFSETS);
|
RECORD(SOURCE_LOCATION_OFFSETS);
|
||||||
RECORD(SOURCE_LOCATION_PRELOADS);
|
RECORD(SOURCE_LOCATION_PRELOADS);
|
||||||
|
RECORD(STAT_CACHE);
|
||||||
|
|
||||||
// SourceManager Block.
|
// SourceManager Block.
|
||||||
BLOCK(SOURCE_MANAGER_BLOCK);
|
BLOCK(SOURCE_MANAGER_BLOCK);
|
||||||
|
@ -513,6 +514,101 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
|
||||||
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
|
Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// stat cache Serialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Trait used for the on-disk hash table of stat cache results.
|
||||||
|
class VISIBILITY_HIDDEN PCHStatCacheTrait {
|
||||||
|
public:
|
||||||
|
typedef const char * key_type;
|
||||||
|
typedef key_type key_type_ref;
|
||||||
|
|
||||||
|
typedef std::pair<int, struct stat> data_type;
|
||||||
|
typedef const data_type& data_type_ref;
|
||||||
|
|
||||||
|
static unsigned ComputeHash(const char *path) {
|
||||||
|
return BernsteinHash(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<unsigned,unsigned>
|
||||||
|
EmitKeyDataLength(llvm::raw_ostream& Out, const char *path,
|
||||||
|
data_type_ref Data) {
|
||||||
|
unsigned StrLen = strlen(path);
|
||||||
|
clang::io::Emit16(Out, StrLen);
|
||||||
|
unsigned DataLen = 1; // result value
|
||||||
|
if (Data.first == 0)
|
||||||
|
DataLen += 4 + 4 + 2 + 8 + 8;
|
||||||
|
clang::io::Emit8(Out, DataLen);
|
||||||
|
return std::make_pair(StrLen + 1, DataLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) {
|
||||||
|
Out.write(path, KeyLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitData(llvm::raw_ostream& Out, key_type_ref,
|
||||||
|
data_type_ref Data, unsigned DataLen) {
|
||||||
|
using namespace clang::io;
|
||||||
|
uint64_t Start = Out.tell(); (void)Start;
|
||||||
|
|
||||||
|
// Result of stat()
|
||||||
|
Emit8(Out, Data.first? 1 : 0);
|
||||||
|
|
||||||
|
if (Data.first == 0) {
|
||||||
|
Emit32(Out, (uint32_t) Data.second.st_ino);
|
||||||
|
Emit32(Out, (uint32_t) Data.second.st_dev);
|
||||||
|
Emit16(Out, (uint16_t) Data.second.st_mode);
|
||||||
|
Emit64(Out, (uint64_t) Data.second.st_mtime);
|
||||||
|
Emit64(Out, (uint64_t) Data.second.st_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Out.tell() - Start == DataLen && "Wrong data length");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
/// \brief Write the stat() system call cache to the PCH file.
|
||||||
|
void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) {
|
||||||
|
// Build the on-disk hash table containing information about every
|
||||||
|
// stat() call.
|
||||||
|
OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator;
|
||||||
|
unsigned NumStatEntries = 0;
|
||||||
|
for (MemorizeStatCalls::iterator Stat = StatCalls.begin(),
|
||||||
|
StatEnd = StatCalls.end();
|
||||||
|
Stat != StatEnd; ++Stat, ++NumStatEntries)
|
||||||
|
Generator.insert(Stat->first(), Stat->second);
|
||||||
|
|
||||||
|
// Create the on-disk hash table in a buffer.
|
||||||
|
llvm::SmallVector<char, 4096> StatCacheData;
|
||||||
|
uint32_t BucketOffset;
|
||||||
|
{
|
||||||
|
llvm::raw_svector_ostream Out(StatCacheData);
|
||||||
|
// Make sure that no bucket is at offset 0
|
||||||
|
clang::io::Emit32(Out, 0);
|
||||||
|
BucketOffset = Generator.Emit(Out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a blob abbreviation
|
||||||
|
using namespace llvm;
|
||||||
|
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
|
||||||
|
Abbrev->Add(BitCodeAbbrevOp(pch::STAT_CACHE));
|
||||||
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
||||||
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
|
||||||
|
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
|
||||||
|
unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev);
|
||||||
|
|
||||||
|
// Write the stat cache
|
||||||
|
RecordData Record;
|
||||||
|
Record.push_back(pch::STAT_CACHE);
|
||||||
|
Record.push_back(BucketOffset);
|
||||||
|
Record.push_back(NumStatEntries);
|
||||||
|
Stream.EmitRecordWithBlob(StatCacheAbbrev, Record,
|
||||||
|
&StatCacheData.front(),
|
||||||
|
StatCacheData.size());
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Source Manager Serialization
|
// Source Manager Serialization
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -747,6 +843,10 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
|
||||||
Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs);
|
Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Preprocessor Serialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// \brief Writes the block containing the serialized form of the
|
/// \brief Writes the block containing the serialized form of the
|
||||||
/// preprocessor.
|
/// preprocessor.
|
||||||
///
|
///
|
||||||
|
@ -830,6 +930,9 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
|
||||||
Stream.ExitBlock();
|
Stream.ExitBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Type Serialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// \brief Write the representation of a type to the PCH stream.
|
/// \brief Write the representation of a type to the PCH stream.
|
||||||
void PCHWriter::WriteType(const Type *T) {
|
void PCHWriter::WriteType(const Type *T) {
|
||||||
|
@ -891,6 +994,10 @@ void PCHWriter::WriteTypesBlock(ASTContext &Context) {
|
||||||
Stream.ExitBlock();
|
Stream.ExitBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Declaration Serialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// \brief Write the block containing all of the declaration IDs
|
/// \brief Write the block containing all of the declaration IDs
|
||||||
/// lexically declared within the given DeclContext.
|
/// lexically declared within the given DeclContext.
|
||||||
///
|
///
|
||||||
|
@ -961,6 +1068,10 @@ uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
|
||||||
return Offset;
|
return Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Global Method Pool and Selector Serialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Trait used for the on-disk hash table used in the method pool.
|
// Trait used for the on-disk hash table used in the method pool.
|
||||||
class VISIBILITY_HIDDEN PCHMethodPoolTrait {
|
class VISIBILITY_HIDDEN PCHMethodPoolTrait {
|
||||||
|
@ -1162,6 +1273,10 @@ void PCHWriter::WriteMethodPool(Sema &SemaRef) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Identifier Table Serialization
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
|
class VISIBILITY_HIDDEN PCHIdentifierTableTrait {
|
||||||
PCHWriter &Writer;
|
PCHWriter &Writer;
|
||||||
|
@ -1339,6 +1454,10 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
|
||||||
IdentifierOffsets.size() * sizeof(uint32_t));
|
IdentifierOffsets.size() * sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// General Serialization Routines
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
/// \brief Write a record containing the given attributes.
|
/// \brief Write a record containing the given attributes.
|
||||||
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
|
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
|
||||||
RecordData Record;
|
RecordData Record;
|
||||||
|
@ -1487,7 +1606,7 @@ PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
|
||||||
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
|
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
|
||||||
NumVisibleDeclContexts(0) { }
|
NumVisibleDeclContexts(0) { }
|
||||||
|
|
||||||
void PCHWriter::WritePCH(Sema &SemaRef) {
|
void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls) {
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
ASTContext &Context = SemaRef.Context;
|
ASTContext &Context = SemaRef.Context;
|
||||||
|
@ -1540,6 +1659,8 @@ void PCHWriter::WritePCH(Sema &SemaRef) {
|
||||||
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
|
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
|
||||||
WriteTargetTriple(Context.Target);
|
WriteTargetTriple(Context.Target);
|
||||||
WriteLanguageOptions(Context.getLangOptions());
|
WriteLanguageOptions(Context.getLangOptions());
|
||||||
|
if (StatCalls)
|
||||||
|
WriteStatCache(*StatCalls);
|
||||||
WriteSourceManagerBlock(Context.getSourceManager(), PP);
|
WriteSourceManagerBlock(Context.getSourceManager(), PP);
|
||||||
WritePreprocessor(PP);
|
WritePreprocessor(PP);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/AST/ASTConsumer.h"
|
#include "clang/AST/ASTConsumer.h"
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
|
#include "clang/Basic/FileManager.h"
|
||||||
#include "llvm/Bitcode/BitstreamWriter.h"
|
#include "llvm/Bitcode/BitstreamWriter.h"
|
||||||
#include "llvm/System/Path.h"
|
#include "llvm/System/Path.h"
|
||||||
#include "llvm/Support/Compiler.h"
|
#include "llvm/Support/Compiler.h"
|
||||||
|
@ -33,16 +34,24 @@ namespace {
|
||||||
const Preprocessor &PP;
|
const Preprocessor &PP;
|
||||||
std::string OutFile;
|
std::string OutFile;
|
||||||
Sema *SemaPtr;
|
Sema *SemaPtr;
|
||||||
|
MemorizeStatCalls *StatCalls; // owned by the FileManager
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PCHGenerator(const Preprocessor &PP, const std::string &OutFile)
|
explicit PCHGenerator(const Preprocessor &PP, const std::string &OutFile);
|
||||||
: PP(PP), OutFile(OutFile), SemaPtr(0) { }
|
|
||||||
|
|
||||||
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
|
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
|
||||||
virtual void HandleTranslationUnit(ASTContext &Ctx);
|
virtual void HandleTranslationUnit(ASTContext &Ctx);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PCHGenerator::PCHGenerator(const Preprocessor &PP, const std::string &OutFile)
|
||||||
|
: PP(PP), OutFile(OutFile), SemaPtr(0), StatCalls(0) {
|
||||||
|
|
||||||
|
// Install a stat() listener to keep track of all of the stat()
|
||||||
|
// calls.
|
||||||
|
StatCalls = new MemorizeStatCalls;
|
||||||
|
PP.getFileManager().setStatCache(StatCalls);
|
||||||
|
}
|
||||||
|
|
||||||
void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
|
void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
|
||||||
if (PP.getDiagnostics().hasErrorOccurred())
|
if (PP.getDiagnostics().hasErrorOccurred())
|
||||||
return;
|
return;
|
||||||
|
@ -54,7 +63,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
|
||||||
|
|
||||||
// Emit the PCH file
|
// Emit the PCH file
|
||||||
assert(SemaPtr && "No Sema?");
|
assert(SemaPtr && "No Sema?");
|
||||||
Writer.WritePCH(*SemaPtr);
|
Writer.WritePCH(*SemaPtr, StatCalls);
|
||||||
|
|
||||||
// Open up the PCH file.
|
// Open up the PCH file.
|
||||||
std::string ErrMsg;
|
std::string ErrMsg;
|
||||||
|
|
|
@ -1919,7 +1919,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
// Create a file manager object to provide access to and cache the filesystem.
|
// Create a file manager object to provide access to and cache the filesystem.
|
||||||
FileManager FileMgr;
|
FileManager FileMgr;
|
||||||
|
|
||||||
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
|
||||||
const std::string &InFile = InputFilenames[i];
|
const std::string &InFile = InputFilenames[i];
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче