mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-08 16:44:06 +00:00

This is a temporary solution to avoid running out of file descriptors (which defaults to 256). Need to benchmark to understand the speed benefit. If the benefit is small, the simple solution is to avoid memory mapping files. If the benefit is significant, more thought is necessary. llvm-svn: 48991
575 lines
19 KiB
C++
575 lines
19 KiB
C++
//===--- SourceManager.cpp - Track and cache source files -----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the SourceManager interface.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
#include "clang/Basic/FileManager.h"
|
|
#include "llvm/Config/config.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/System/Path.h"
|
|
#include "llvm/Bitcode/Serialize.h"
|
|
#include "llvm/Bitcode/Deserialize.h"
|
|
#include "llvm/Support/Streams.h"
|
|
#include <algorithm>
|
|
#include <fcntl.h>
|
|
using namespace clang;
|
|
using namespace SrcMgr;
|
|
using llvm::MemoryBuffer;
|
|
|
|
ContentCache::~ContentCache() {
|
|
delete Buffer;
|
|
delete [] SourceLineCache;
|
|
}
|
|
|
|
// FIXME: REMOVE THESE
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
|
#include <sys/uio.h>
|
|
#include <sys/fcntl.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
#include <cerrno>
|
|
|
|
static const MemoryBuffer *ReadFileFast(const FileEntry *FileEnt) {
|
|
#if 0
|
|
// FIXME: Reintroduce this and zap this function once the common llvm stuff
|
|
// is fast for the small case.
|
|
return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()),
|
|
FileEnt->getSize());
|
|
#endif
|
|
|
|
// If the file is larger than some threshold, use 'read', otherwise use mmap.
|
|
if (FileEnt->getSize() >= 4096*12)
|
|
return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()),
|
|
0, FileEnt->getSize());
|
|
|
|
MemoryBuffer *SB = MemoryBuffer::getNewUninitMemBuffer(FileEnt->getSize(),
|
|
FileEnt->getName());
|
|
char *BufPtr = const_cast<char*>(SB->getBufferStart());
|
|
|
|
#if defined(LLVM_ON_WIN32)
|
|
int FD = ::open(FileEnt->getName(), O_RDONLY|O_BINARY);
|
|
#else
|
|
int FD = ::open(FileEnt->getName(), O_RDONLY);
|
|
#endif
|
|
if (FD == -1) {
|
|
delete SB;
|
|
return 0;
|
|
}
|
|
|
|
unsigned BytesLeft = FileEnt->getSize();
|
|
while (BytesLeft) {
|
|
ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
|
|
if (NumRead != -1) {
|
|
BytesLeft -= NumRead;
|
|
BufPtr += NumRead;
|
|
} else if (errno == EINTR) {
|
|
// try again
|
|
} else {
|
|
// error reading.
|
|
close(FD);
|
|
delete SB;
|
|
return 0;
|
|
}
|
|
}
|
|
close(FD);
|
|
|
|
return SB;
|
|
}
|
|
|
|
|
|
/// getFileInfo - Create or return a cached FileInfo for the specified file.
|
|
///
|
|
const ContentCache* SourceManager::getContentCache(const FileEntry *FileEnt) {
|
|
|
|
assert(FileEnt && "Didn't specify a file entry to use?");
|
|
// Do we already have information about this file?
|
|
std::set<ContentCache>::iterator I =
|
|
FileInfos.lower_bound(ContentCache(FileEnt));
|
|
|
|
if (I != FileInfos.end() && I->Entry == FileEnt)
|
|
return &*I;
|
|
|
|
// Nope, get information.
|
|
const MemoryBuffer *File = ReadFileFast(FileEnt);
|
|
if (File == 0)
|
|
return 0;
|
|
|
|
ContentCache& Entry = const_cast<ContentCache&>(*FileInfos.insert(I,FileEnt));
|
|
|
|
Entry.Buffer = File;
|
|
Entry.SourceLineCache = 0;
|
|
Entry.NumLines = 0;
|
|
return &Entry;
|
|
}
|
|
|
|
|
|
/// createMemBufferContentCache - Create a new ContentCache for the specified
|
|
/// memory buffer. This does no caching.
|
|
const ContentCache*
|
|
SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
|
|
// Add a new ContentCache to the MemBufferInfos list and return it. We
|
|
// must default construct the object first that the instance actually
|
|
// stored within MemBufferInfos actually owns the Buffer, and not any
|
|
// temporary we would use in the call to "push_back".
|
|
MemBufferInfos.push_back(ContentCache());
|
|
ContentCache& Entry = const_cast<ContentCache&>(MemBufferInfos.back());
|
|
Entry.Buffer = Buffer;
|
|
return &Entry;
|
|
}
|
|
|
|
|
|
/// createFileID - Create a new fileID for the specified ContentCache and
|
|
/// include position. This works regardless of whether the ContentCache
|
|
/// corresponds to a file or some other input source.
|
|
unsigned SourceManager::createFileID(const ContentCache *File,
|
|
SourceLocation IncludePos) {
|
|
// If FileEnt is really large (e.g. it's a large .i file), we may not be able
|
|
// to fit an arbitrary position in the file in the FilePos field. To handle
|
|
// this, we create one FileID for each chunk of the file that fits in a
|
|
// FilePos field.
|
|
unsigned FileSize = File->Buffer->getBufferSize();
|
|
if (FileSize+1 < (1 << SourceLocation::FilePosBits)) {
|
|
FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File));
|
|
assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) &&
|
|
"Ran out of file ID's!");
|
|
return FileIDs.size();
|
|
}
|
|
|
|
// Create one FileID for each chunk of the file.
|
|
unsigned Result = FileIDs.size()+1;
|
|
|
|
unsigned ChunkNo = 0;
|
|
while (1) {
|
|
FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File));
|
|
|
|
if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break;
|
|
FileSize -= (1 << SourceLocation::FilePosBits);
|
|
}
|
|
|
|
assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) &&
|
|
"Ran out of file ID's!");
|
|
return Result;
|
|
}
|
|
|
|
/// getInstantiationLoc - Return a new SourceLocation that encodes the fact
|
|
/// that a token from physloc PhysLoc should actually be referenced from
|
|
/// InstantiationLoc.
|
|
SourceLocation SourceManager::getInstantiationLoc(SourceLocation PhysLoc,
|
|
SourceLocation InstantLoc) {
|
|
// The specified source location may be a mapped location, due to a macro
|
|
// instantiation or #line directive. Strip off this information to find out
|
|
// where the characters are actually located.
|
|
PhysLoc = getPhysicalLoc(PhysLoc);
|
|
|
|
// Resolve InstantLoc down to a real logical location.
|
|
InstantLoc = getLogicalLoc(InstantLoc);
|
|
|
|
|
|
// If the last macro id is close to the currently requested location, try to
|
|
// reuse it. This implements a small cache.
|
|
for (int i = MacroIDs.size()-1, e = MacroIDs.size()-6; i >= 0 && i != e; --i){
|
|
MacroIDInfo &LastOne = MacroIDs[i];
|
|
|
|
// The instanitation point and source physloc have to exactly match to reuse
|
|
// (for now). We could allow "nearby" instantiations in the future.
|
|
if (LastOne.getVirtualLoc() != InstantLoc ||
|
|
LastOne.getPhysicalLoc().getFileID() != PhysLoc.getFileID())
|
|
continue;
|
|
|
|
// Check to see if the physloc of the token came from near enough to reuse.
|
|
int PhysDelta = PhysLoc.getRawFilePos() -
|
|
LastOne.getPhysicalLoc().getRawFilePos();
|
|
if (SourceLocation::isValidMacroPhysOffs(PhysDelta))
|
|
return SourceLocation::getMacroLoc(i, PhysDelta);
|
|
}
|
|
|
|
|
|
MacroIDs.push_back(MacroIDInfo::get(InstantLoc, PhysLoc));
|
|
return SourceLocation::getMacroLoc(MacroIDs.size()-1, 0);
|
|
}
|
|
|
|
/// getBufferData - Return a pointer to the start and end of the character
|
|
/// data for the specified FileID.
|
|
std::pair<const char*, const char*>
|
|
SourceManager::getBufferData(unsigned FileID) const {
|
|
const llvm::MemoryBuffer *Buf = getBuffer(FileID);
|
|
return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd());
|
|
}
|
|
|
|
|
|
/// getCharacterData - Return a pointer to the start of the specified location
|
|
/// in the appropriate MemoryBuffer.
|
|
const char *SourceManager::getCharacterData(SourceLocation SL) const {
|
|
// Note that this is a hot function in the getSpelling() path, which is
|
|
// heavily used by -E mode.
|
|
SL = getPhysicalLoc(SL);
|
|
|
|
return getContentCache(SL.getFileID())->Buffer->getBufferStart() +
|
|
getFullFilePos(SL);
|
|
}
|
|
|
|
|
|
/// getColumnNumber - Return the column # for the specified file position.
|
|
/// this is significantly cheaper to compute than the line number. This returns
|
|
/// zero if the column number isn't known.
|
|
unsigned SourceManager::getColumnNumber(SourceLocation Loc) const {
|
|
unsigned FileID = Loc.getFileID();
|
|
if (FileID == 0) return 0;
|
|
|
|
unsigned FilePos = getFullFilePos(Loc);
|
|
const MemoryBuffer *Buffer = getBuffer(FileID);
|
|
const char *Buf = Buffer->getBufferStart();
|
|
|
|
unsigned LineStart = FilePos;
|
|
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
|
|
--LineStart;
|
|
return FilePos-LineStart+1;
|
|
}
|
|
|
|
/// getSourceName - This method returns the name of the file or buffer that
|
|
/// the SourceLocation specifies. This can be modified with #line directives,
|
|
/// etc.
|
|
const char *SourceManager::getSourceName(SourceLocation Loc) const {
|
|
unsigned FileID = Loc.getFileID();
|
|
if (FileID == 0) return "";
|
|
return getContentCache(FileID)->Buffer->getBufferIdentifier();
|
|
}
|
|
|
|
static void ComputeLineNumbers(ContentCache* FI) DISABLE_INLINE;
|
|
static void ComputeLineNumbers(ContentCache* FI) {
|
|
const MemoryBuffer *Buffer = FI->Buffer;
|
|
|
|
// Find the file offsets of all of the *physical* source lines. This does
|
|
// not look at trigraphs, escaped newlines, or anything else tricky.
|
|
std::vector<unsigned> LineOffsets;
|
|
|
|
// Line #1 starts at char 0.
|
|
LineOffsets.push_back(0);
|
|
|
|
const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart();
|
|
const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd();
|
|
unsigned Offs = 0;
|
|
while (1) {
|
|
// Skip over the contents of the line.
|
|
// TODO: Vectorize this? This is very performance sensitive for programs
|
|
// with lots of diagnostics and in -E mode.
|
|
const unsigned char *NextBuf = (const unsigned char *)Buf;
|
|
while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
|
|
++NextBuf;
|
|
Offs += NextBuf-Buf;
|
|
Buf = NextBuf;
|
|
|
|
if (Buf[0] == '\n' || Buf[0] == '\r') {
|
|
// If this is \n\r or \r\n, skip both characters.
|
|
if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1])
|
|
++Offs, ++Buf;
|
|
++Offs, ++Buf;
|
|
LineOffsets.push_back(Offs);
|
|
} else {
|
|
// Otherwise, this is a null. If end of file, exit.
|
|
if (Buf == End) break;
|
|
// Otherwise, skip the null.
|
|
++Offs, ++Buf;
|
|
}
|
|
}
|
|
|
|
// Copy the offsets into the FileInfo structure.
|
|
FI->NumLines = LineOffsets.size();
|
|
FI->SourceLineCache = new unsigned[LineOffsets.size()];
|
|
std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache);
|
|
}
|
|
|
|
/// getLineNumber - Given a SourceLocation, return the physical line number
|
|
/// for the position indicated. This requires building and caching a table of
|
|
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
|
|
/// about to emit a diagnostic.
|
|
unsigned SourceManager::getLineNumber(SourceLocation Loc) {
|
|
unsigned FileID = Loc.getFileID();
|
|
if (FileID == 0) return 0;
|
|
|
|
ContentCache* Content;
|
|
|
|
if (LastLineNoFileIDQuery == FileID)
|
|
Content = LastLineNoContentCache;
|
|
else
|
|
Content = const_cast<ContentCache*>(getContentCache(FileID));
|
|
|
|
// If this is the first use of line information for this buffer, compute the
|
|
/// SourceLineCache for it on demand.
|
|
if (Content->SourceLineCache == 0)
|
|
ComputeLineNumbers(Content);
|
|
|
|
// Okay, we know we have a line number table. Do a binary search to find the
|
|
// line number that this character position lands on.
|
|
unsigned *SourceLineCache = Content->SourceLineCache;
|
|
unsigned *SourceLineCacheStart = SourceLineCache;
|
|
unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines;
|
|
|
|
unsigned QueriedFilePos = getFullFilePos(Loc)+1;
|
|
|
|
// If the previous query was to the same file, we know both the file pos from
|
|
// that query and the line number returned. This allows us to narrow the
|
|
// search space from the entire file to something near the match.
|
|
if (LastLineNoFileIDQuery == FileID) {
|
|
if (QueriedFilePos >= LastLineNoFilePos) {
|
|
SourceLineCache = SourceLineCache+LastLineNoResult-1;
|
|
|
|
// The query is likely to be nearby the previous one. Here we check to
|
|
// see if it is within 5, 10 or 20 lines. It can be far away in cases
|
|
// where big comment blocks and vertical whitespace eat up lines but
|
|
// contribute no tokens.
|
|
if (SourceLineCache+5 < SourceLineCacheEnd) {
|
|
if (SourceLineCache[5] > QueriedFilePos)
|
|
SourceLineCacheEnd = SourceLineCache+5;
|
|
else if (SourceLineCache+10 < SourceLineCacheEnd) {
|
|
if (SourceLineCache[10] > QueriedFilePos)
|
|
SourceLineCacheEnd = SourceLineCache+10;
|
|
else if (SourceLineCache+20 < SourceLineCacheEnd) {
|
|
if (SourceLineCache[20] > QueriedFilePos)
|
|
SourceLineCacheEnd = SourceLineCache+20;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1;
|
|
}
|
|
}
|
|
|
|
// If the spread is large, do a "radix" test as our initial guess, based on
|
|
// the assumption that lines average to approximately the same length.
|
|
// NOTE: This is currently disabled, as it does not appear to be profitable in
|
|
// initial measurements.
|
|
if (0 && SourceLineCacheEnd-SourceLineCache > 20) {
|
|
unsigned FileLen = Content->SourceLineCache[Content->NumLines-1];
|
|
|
|
// Take a stab at guessing where it is.
|
|
unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen;
|
|
|
|
// Check for -10 and +10 lines.
|
|
unsigned LowerBound = std::max(int(ApproxPos-10), 0);
|
|
unsigned UpperBound = std::min(ApproxPos+10, FileLen);
|
|
|
|
// If the computed lower bound is less than the query location, move it in.
|
|
if (SourceLineCache < SourceLineCacheStart+LowerBound &&
|
|
SourceLineCacheStart[LowerBound] < QueriedFilePos)
|
|
SourceLineCache = SourceLineCacheStart+LowerBound;
|
|
|
|
// If the computed upper bound is greater than the query location, move it.
|
|
if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound &&
|
|
SourceLineCacheStart[UpperBound] >= QueriedFilePos)
|
|
SourceLineCacheEnd = SourceLineCacheStart+UpperBound;
|
|
}
|
|
|
|
unsigned *Pos
|
|
= std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos);
|
|
unsigned LineNo = Pos-SourceLineCacheStart;
|
|
|
|
LastLineNoFileIDQuery = FileID;
|
|
LastLineNoContentCache = Content;
|
|
LastLineNoFilePos = QueriedFilePos;
|
|
LastLineNoResult = LineNo;
|
|
return LineNo;
|
|
}
|
|
|
|
/// PrintStats - Print statistics to stderr.
|
|
///
|
|
void SourceManager::PrintStats() const {
|
|
llvm::cerr << "\n*** Source Manager Stats:\n";
|
|
llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size()
|
|
<< " mem buffers mapped, " << FileIDs.size()
|
|
<< " file ID's allocated.\n";
|
|
llvm::cerr << " " << FileIDs.size() << " normal buffer FileID's, "
|
|
<< MacroIDs.size() << " macro expansion FileID's.\n";
|
|
|
|
unsigned NumLineNumsComputed = 0;
|
|
unsigned NumFileBytesMapped = 0;
|
|
for (std::set<ContentCache>::const_iterator I =
|
|
FileInfos.begin(), E = FileInfos.end(); I != E; ++I) {
|
|
NumLineNumsComputed += I->SourceLineCache != 0;
|
|
NumFileBytesMapped += I->Buffer->getBufferSize();
|
|
}
|
|
|
|
llvm::cerr << NumFileBytesMapped << " bytes of files mapped, "
|
|
<< NumLineNumsComputed << " files with line #'s computed.\n";
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Serialization.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void ContentCache::Emit(llvm::Serializer& S) const {
|
|
S.FlushRecord();
|
|
S.EmitPtr(this);
|
|
|
|
if (Entry) {
|
|
llvm::sys::Path Fname(Buffer->getBufferIdentifier());
|
|
|
|
if (Fname.isAbsolute())
|
|
S.EmitCStr(Fname.c_str());
|
|
else {
|
|
// Create an absolute path.
|
|
// FIXME: This will potentially contain ".." and "." in the path.
|
|
llvm::sys::Path path = llvm::sys::Path::GetCurrentDirectory();
|
|
path.appendComponent(Fname.c_str());
|
|
S.EmitCStr(path.c_str());
|
|
}
|
|
}
|
|
else {
|
|
const char* p = Buffer->getBufferStart();
|
|
const char* e = Buffer->getBufferEnd();
|
|
|
|
S.EmitInt(e-p);
|
|
|
|
for ( ; p != e; ++p)
|
|
S.EmitInt(*p);
|
|
}
|
|
|
|
S.FlushRecord();
|
|
}
|
|
|
|
void ContentCache::ReadToSourceManager(llvm::Deserializer& D,
|
|
SourceManager& SMgr,
|
|
FileManager* FMgr,
|
|
std::vector<char>& Buf) {
|
|
if (FMgr) {
|
|
llvm::SerializedPtrID PtrID = D.ReadPtrID();
|
|
D.ReadCStr(Buf,false);
|
|
|
|
// Create/fetch the FileEntry.
|
|
const char* start = &Buf[0];
|
|
const FileEntry* E = FMgr->getFile(start,start+Buf.size());
|
|
|
|
// FIXME: Ideally we want a lazy materialization of the ContentCache
|
|
// anyway, because we don't want to read in source files unless this
|
|
// is absolutely needed.
|
|
if (!E)
|
|
D.RegisterPtr(PtrID,NULL);
|
|
else
|
|
// Get the ContextCache object and register it with the deserializer.
|
|
D.RegisterPtr(PtrID,SMgr.getContentCache(E));
|
|
}
|
|
else {
|
|
// Register the ContextCache object with the deserializer.
|
|
SMgr.MemBufferInfos.push_back(ContentCache());
|
|
ContentCache& Entry = const_cast<ContentCache&>(SMgr.MemBufferInfos.back());
|
|
D.RegisterPtr(&Entry);
|
|
|
|
// Create the buffer.
|
|
unsigned Size = D.ReadInt();
|
|
Entry.Buffer = MemoryBuffer::getNewUninitMemBuffer(Size);
|
|
|
|
// Read the contents of the buffer.
|
|
char* p = const_cast<char*>(Entry.Buffer->getBufferStart());
|
|
for (unsigned i = 0; i < Size ; ++i)
|
|
p[i] = D.ReadInt();
|
|
}
|
|
}
|
|
|
|
void FileIDInfo::Emit(llvm::Serializer& S) const {
|
|
S.Emit(IncludeLoc);
|
|
S.EmitInt(ChunkNo);
|
|
S.EmitPtr(Content);
|
|
}
|
|
|
|
FileIDInfo FileIDInfo::ReadVal(llvm::Deserializer& D) {
|
|
FileIDInfo I;
|
|
I.IncludeLoc = SourceLocation::ReadVal(D);
|
|
I.ChunkNo = D.ReadInt();
|
|
D.ReadPtr(I.Content,false);
|
|
return I;
|
|
}
|
|
|
|
void MacroIDInfo::Emit(llvm::Serializer& S) const {
|
|
S.Emit(VirtualLoc);
|
|
S.Emit(PhysicalLoc);
|
|
}
|
|
|
|
MacroIDInfo MacroIDInfo::ReadVal(llvm::Deserializer& D) {
|
|
MacroIDInfo I;
|
|
I.VirtualLoc = SourceLocation::ReadVal(D);
|
|
I.PhysicalLoc = SourceLocation::ReadVal(D);
|
|
return I;
|
|
}
|
|
|
|
void SourceManager::Emit(llvm::Serializer& S) const {
|
|
S.EnterBlock();
|
|
S.EmitPtr(this);
|
|
S.EmitInt(MainFileID);
|
|
|
|
// Emit: FileInfos. Just emit the file name.
|
|
S.EnterBlock();
|
|
|
|
std::for_each(FileInfos.begin(),FileInfos.end(),
|
|
S.MakeEmitter<ContentCache>());
|
|
|
|
S.ExitBlock();
|
|
|
|
// Emit: MemBufferInfos
|
|
S.EnterBlock();
|
|
|
|
std::for_each(MemBufferInfos.begin(), MemBufferInfos.end(),
|
|
S.MakeEmitter<ContentCache>());
|
|
|
|
S.ExitBlock();
|
|
|
|
// Emit: FileIDs
|
|
S.EmitInt(FileIDs.size());
|
|
std::for_each(FileIDs.begin(), FileIDs.end(), S.MakeEmitter<FileIDInfo>());
|
|
|
|
// Emit: MacroIDs
|
|
S.EmitInt(MacroIDs.size());
|
|
std::for_each(MacroIDs.begin(), MacroIDs.end(), S.MakeEmitter<MacroIDInfo>());
|
|
|
|
S.ExitBlock();
|
|
}
|
|
|
|
SourceManager*
|
|
SourceManager::CreateAndRegister(llvm::Deserializer& D, FileManager& FMgr){
|
|
SourceManager *M = new SourceManager();
|
|
D.RegisterPtr(M);
|
|
|
|
// Read: the FileID of the main source file of the translation unit.
|
|
M->MainFileID = D.ReadInt();
|
|
|
|
std::vector<char> Buf;
|
|
|
|
{ // Read: FileInfos.
|
|
llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation();
|
|
while (!D.FinishedBlock(BLoc))
|
|
ContentCache::ReadToSourceManager(D,*M,&FMgr,Buf);
|
|
}
|
|
|
|
{ // Read: MemBufferInfos.
|
|
llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation();
|
|
while (!D.FinishedBlock(BLoc))
|
|
ContentCache::ReadToSourceManager(D,*M,NULL,Buf);
|
|
}
|
|
|
|
// Read: FileIDs.
|
|
unsigned Size = D.ReadInt();
|
|
M->FileIDs.reserve(Size);
|
|
for (; Size > 0 ; --Size)
|
|
M->FileIDs.push_back(FileIDInfo::ReadVal(D));
|
|
|
|
// Read: MacroIDs.
|
|
Size = D.ReadInt();
|
|
M->MacroIDs.reserve(Size);
|
|
for (; Size > 0 ; --Size)
|
|
M->MacroIDs.push_back(MacroIDInfo::ReadVal(D));
|
|
|
|
return M;
|
|
}
|