Put the mechanism in place to track modifications in an AST entity that were committed after
its initial creation/deserialization and store the changes in a chained PCH.
The idea is that the AST entities call methods on the ASTMutationListener to give notifications
of changes; the PCHWriter implements the ASTMutationListener interface and stores the incremental changes
of the updated entity. WIP
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117235 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 162fa26..38e786b 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -454,8 +454,6 @@
void
ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) {
DeserializationListener = Listener;
- if (DeserializationListener)
- DeserializationListener->SetReader(this);
}
@@ -1716,6 +1714,13 @@
}
break;
+ case DECL_UPDATES_BLOCK_ID:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ break;
+
case PREPROCESSOR_BLOCK_ID:
F.MacroCursor = Stream;
if (PP)
@@ -2043,6 +2048,17 @@
F.LocalNumMacroDefinitions = Record[1];
break;
+ case DECL_UPDATE_OFFSETS: {
+ if (Record.size() % 2 != 0) {
+ Error("invalid DECL_UPDATE_OFFSETS block in AST file");
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 2)
+ DeclUpdateOffsets[static_cast<DeclID>(Record[I])]
+ .push_back(std::make_pair(&F, Record[I+1]));
+ break;
+ }
+
case DECL_REPLACEMENTS: {
if (Record.size() % 2 != 0) {
Error("invalid DECL_REPLACEMENTS block in AST file");
@@ -2164,6 +2180,9 @@
if (Context)
InitializeContext(*Context);
+ if (DeserializationListener)
+ DeserializationListener->ReaderInitialized(this);
+
return Success;
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 750e723..acc4dc1 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "ASTCommon.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -71,6 +72,8 @@
void Visit(Decl *D);
+ void UpdateDecl(Decl *D, const RecordData &Record);
+
void VisitDecl(Decl *D);
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
void VisitNamedDecl(NamedDecl *ND);
@@ -1537,6 +1540,28 @@
}
assert(Idx == Record.size());
+ // The declaration may have been modified by files later in the chain.
+ // If this is the case, read the record containing the updates from each file
+ // and pass it to ASTDeclReader to make the modifications.
+ DeclUpdateOffsetsMap::iterator UpdI = DeclUpdateOffsets.find(ID);
+ if (UpdI != DeclUpdateOffsets.end()) {
+ FileOffsetsTy &UpdateOffsets = UpdI->second;
+ for (FileOffsetsTy::iterator
+ I = UpdateOffsets.begin(), E = UpdateOffsets.end(); I != E; ++I) {
+ PerFileData *F = I->first;
+ uint64_t Offset = I->second;
+ llvm::BitstreamCursor &Cursor = F->DeclsCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = Cursor.ReadCode();
+ unsigned RecCode = Cursor.ReadRecord(Code, Record);
+ (void)RecCode;
+ assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
+ Reader.UpdateDecl(D, Record);
+ }
+ }
+
// If we have deserialized a declaration that has a definition the
// AST consumer might need to know about, queue it.
// We don't pass it to the consumer immediately because we may be in recursive
@@ -1546,3 +1571,7 @@
return D;
}
+
+void ASTDeclReader::UpdateDecl(Decl *D, const RecordData &Record) {
+ // No update is tracked yet.
+}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 4d0ec99..e258fcc 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -2474,17 +2474,6 @@
const char *isysroot) {
using namespace llvm;
- FirstDeclID += Chain->getTotalNumDecls();
- FirstTypeID += Chain->getTotalNumTypes();
- FirstIdentID += Chain->getTotalNumIdentifiers();
- FirstSelectorID += Chain->getTotalNumSelectors();
- FirstMacroID += Chain->getTotalNumMacroDefinitions();
- NextDeclID = FirstDeclID;
- NextTypeID = FirstTypeID;
- NextIdentID = FirstIdentID;
- NextSelectorID = FirstSelectorID;
- NextMacroID = FirstMacroID;
-
ASTContext &Context = SemaRef.Context;
Preprocessor &PP = SemaRef.PP;
@@ -2707,6 +2696,8 @@
if (!AdditionalTemplateSpecializations.empty())
WriteAdditionalTemplateSpecializations();
+ WriteDeclChangeSetBlocks();
+
Record.clear();
Record.push_back(NumStatements);
Record.push_back(NumMacros);
@@ -2717,6 +2708,27 @@
Stream.ExitBlock();
}
+void ASTWriter::WriteDeclChangeSetBlocks() {
+ if (DeclUpdates.empty())
+ return;
+
+ RecordData OffsetsRecord;
+ Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, 3);
+ for (DeclUpdateMap::iterator
+ I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
+ const Decl *D = I->first;
+ UpdateRecord &URec = I->second;
+
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ Stream.EmitRecord(DECL_UPDATES, URec);
+
+ OffsetsRecord.push_back(GetDeclRef(D));
+ OffsetsRecord.push_back(Offset);
+ }
+ Stream.ExitBlock();
+ Stream.EmitRecord(DECL_UPDATE_OFFSETS, OffsetsRecord);
+}
+
void ASTWriter::WriteDeclUpdateBlock() {
if (ReplacedDecls.empty())
return;
@@ -2891,7 +2903,7 @@
return I->second;
}
-void ASTWriter::AddDeclRef(const Decl *D, RecordData &Record) {
+void ASTWriter::AddDeclRef(const Decl *D, RecordDataImpl &Record) {
Record.push_back(GetDeclRef(D));
}
@@ -3190,8 +3202,9 @@
}
}
-void ASTWriter::SetReader(ASTReader *Reader) {
+void ASTWriter::ReaderInitialized(ASTReader *Reader) {
assert(Reader && "Cannot remove chain");
+ assert(!Chain && "Cannot replace chain");
assert(FirstDeclID == NextDeclID &&
FirstTypeID == NextTypeID &&
FirstIdentID == NextIdentID &&
@@ -3199,6 +3212,17 @@
FirstMacroID == NextMacroID &&
"Setting chain after writing has started.");
Chain = Reader;
+
+ FirstDeclID += Chain->getTotalNumDecls();
+ FirstTypeID += Chain->getTotalNumTypes();
+ FirstIdentID += Chain->getTotalNumIdentifiers();
+ FirstSelectorID += Chain->getTotalNumSelectors();
+ FirstMacroID += Chain->getTotalNumMacroDefinitions();
+ NextDeclID = FirstDeclID;
+ NextTypeID = FirstTypeID;
+ NextIdentID = FirstIdentID;
+ NextSelectorID = FirstSelectorID;
+ NextMacroID = FirstMacroID;
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 5329b6c..0d8ec73 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -30,7 +30,7 @@
const char *isysroot,
llvm::raw_ostream *OS)
: PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0),
- StatCalls(0), Stream(Buffer), Writer(Stream) {
+ StatCalls(0), Stream(Buffer), Writer(Stream), Chaining(Chaining) {
// Install a stat() listener to keep track of all of the stat()
// calls.
@@ -59,6 +59,12 @@
Buffer.clear();
}
+ASTMutationListener *PCHGenerator::GetASTMutationListener() {
+ if (Chaining)
+ return &Writer;
+ return 0;
+}
+
ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() {
return &Writer;
}