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:
Duncan P. N. Exon Smith
2017-03-13 18:45:08 +00:00
parent 75a7e6589f
commit 60fa28882e
22 changed files with 436 additions and 160 deletions

View File

@@ -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.