Modules: Use hash of PCM content for SIGNATURE
Change ASTFileSignature from a random 32-bit number to the hash of the
PCM content.
- Move definition ASTFileSignature to Basic/Module.h so Module and
ASTSourceDescriptor can use it.
- Change the signature from uint64_t to std::array<uint32_t,5>.
- Stop using (saving/reading) the size and modification time of PCM
files when there is a valid SIGNATURE.
- Add UNHASHED_CONTROL_BLOCK, and use it to store the SIGNATURE record
and other records that shouldn't affect the hash. Because implicit
modules reuses the same file for multiple levels of -Werror, this
includes DIAGNOSTIC_OPTIONS and DIAG_PRAGMA_MAPPINGS.
This helps to solve a PCH + implicit Modules dependency issue: PCH files
are handled by the external build system, whereas implicit modules are
handled by internal compiler build system. This prevents invalidating a
PCH when the compiler overwrites a PCM file with the same content
(modulo the diagnostic differences).
Design and original patch by Manman Ren!
llvm-svn: 297655
This commit is contained in:
@@ -376,6 +376,15 @@ namespace {
|
||||
/// \brief The set of modules on which this module depends. Each entry is
|
||||
/// a module ID.
|
||||
SmallVector<unsigned, 4> Dependencies;
|
||||
ASTFileSignature Signature;
|
||||
};
|
||||
|
||||
struct ImportedModuleFileInfo {
|
||||
off_t StoredSize;
|
||||
time_t StoredModTime;
|
||||
ASTFileSignature StoredSignature;
|
||||
ImportedModuleFileInfo(off_t Size, time_t ModTime, ASTFileSignature Sig)
|
||||
: StoredSize(Size), StoredModTime(ModTime), StoredSignature(Sig) {}
|
||||
};
|
||||
|
||||
/// \brief Builder that generates the global module index file.
|
||||
@@ -383,12 +392,20 @@ namespace {
|
||||
FileManager &FileMgr;
|
||||
const PCHContainerReader &PCHContainerRdr;
|
||||
|
||||
/// \brief Mapping from files to module file information.
|
||||
/// Mapping from files to module file information.
|
||||
typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
|
||||
|
||||
/// \brief Information about each of the known module files.
|
||||
/// Information about each of the known module files.
|
||||
ModuleFilesMap ModuleFiles;
|
||||
|
||||
/// \brief Mapping from the imported module file to the imported
|
||||
/// information.
|
||||
typedef std::multimap<const FileEntry *, ImportedModuleFileInfo>
|
||||
ImportedModuleFilesMap;
|
||||
|
||||
/// \brief Information about each importing of a module file.
|
||||
ImportedModuleFilesMap ImportedModuleFiles;
|
||||
|
||||
/// \brief Mapping from identifiers to the list of module file IDs that
|
||||
/// consider this identifier to be interesting.
|
||||
typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
|
||||
@@ -424,7 +441,8 @@ namespace {
|
||||
bool loadModuleFile(const FileEntry *File);
|
||||
|
||||
/// \brief Write the index to the given bitstream.
|
||||
void writeIndex(llvm::BitstreamWriter &Stream);
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool writeIndex(llvm::BitstreamWriter &Stream);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -515,7 +533,7 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
|
||||
unsigned ID = getModuleFileInfo(File).ID;
|
||||
|
||||
// Search for the blocks and records we care about.
|
||||
enum { Other, ControlBlock, ASTBlock } State = Other;
|
||||
enum { Other, ControlBlock, ASTBlock, DiagnosticOptionsBlock } State = Other;
|
||||
bool Done = false;
|
||||
while (!Done) {
|
||||
llvm::BitstreamEntry Entry = InStream.advance();
|
||||
@@ -553,6 +571,15 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Entry.ID == UNHASHED_CONTROL_BLOCK_ID) {
|
||||
if (InStream.EnterSubBlock(UNHASHED_CONTROL_BLOCK_ID))
|
||||
return true;
|
||||
|
||||
// Found the Diagnostic Options block.
|
||||
State = DiagnosticOptionsBlock;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InStream.SkipBlock())
|
||||
return true;
|
||||
|
||||
@@ -587,7 +614,10 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
|
||||
|
||||
// Skip the stored signature.
|
||||
// FIXME: we could read the signature out of the import and validate it.
|
||||
Idx++;
|
||||
ASTFileSignature StoredSignature = {
|
||||
{{(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
|
||||
(uint32_t)Record[Idx++], (uint32_t)Record[Idx++],
|
||||
(uint32_t)Record[Idx++]}}};
|
||||
|
||||
// Retrieve the imported file name.
|
||||
unsigned Length = Record[Idx++];
|
||||
@@ -599,11 +629,16 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
|
||||
const FileEntry *DependsOnFile
|
||||
= FileMgr.getFile(ImportedFile, /*openFile=*/false,
|
||||
/*cacheFailure=*/false);
|
||||
if (!DependsOnFile ||
|
||||
(StoredSize != DependsOnFile->getSize()) ||
|
||||
(StoredModTime != DependsOnFile->getModificationTime()))
|
||||
|
||||
if (!DependsOnFile)
|
||||
return true;
|
||||
|
||||
// Save the information in ImportedModuleFileInfo so we can verify after
|
||||
// loading all pcms.
|
||||
ImportedModuleFiles.insert(std::make_pair(
|
||||
DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
|
||||
StoredSignature)));
|
||||
|
||||
// Record the dependency.
|
||||
unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
|
||||
getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
|
||||
@@ -632,6 +667,12 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get Signature.
|
||||
if (State == DiagnosticOptionsBlock && Code == SIGNATURE)
|
||||
getModuleFileInfo(File).Signature = {
|
||||
{{(uint32_t)Record[0], (uint32_t)Record[1], (uint32_t)Record[2],
|
||||
(uint32_t)Record[3], (uint32_t)Record[4]}}};
|
||||
|
||||
// We don't care about this record.
|
||||
}
|
||||
|
||||
@@ -680,7 +721,20 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
|
||||
bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
|
||||
for (auto MapEntry : ImportedModuleFiles) {
|
||||
auto *File = MapEntry.first;
|
||||
ImportedModuleFileInfo &Info = MapEntry.second;
|
||||
if (getModuleFileInfo(File).Signature) {
|
||||
if (getModuleFileInfo(File).Signature != Info.StoredSignature)
|
||||
// Verify Signature.
|
||||
return true;
|
||||
} else if (Info.StoredSize != File->getSize() ||
|
||||
Info.StoredModTime != File->getModificationTime())
|
||||
// Verify Size and ModTime.
|
||||
return true;
|
||||
}
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
// Emit the file header.
|
||||
@@ -756,6 +810,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
|
||||
}
|
||||
|
||||
Stream.ExitBlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
GlobalModuleIndex::ErrorCode
|
||||
@@ -816,7 +871,8 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
|
||||
SmallVector<char, 16> OutputBuffer;
|
||||
{
|
||||
llvm::BitstreamWriter OutputStream(OutputBuffer);
|
||||
Builder.writeIndex(OutputStream);
|
||||
if (Builder.writeIndex(OutputStream))
|
||||
return EC_IOError;
|
||||
}
|
||||
|
||||
// Write the global index file to a temporary file.
|
||||
|
||||
Reference in New Issue
Block a user