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/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 84833c0..08ee4ef 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -19,6 +19,7 @@
class CXXRecordDecl;
class DeclGroupRef;
class HandleTagDeclDefinition;
+ class ASTMutationListener;
class ASTDeserializationListener; // layering violation because void* is ugly
class SemaConsumer; // layering violation required for safe SemaConsumer
class TagDecl;
@@ -86,10 +87,13 @@
/// it was actually used.
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
+ /// \brief If the consumer is interested in entities getting modified after
+ /// their initial creation, it should return a pointer to
+ /// a GetASTMutationListener here.
+ virtual ASTMutationListener *GetASTMutationListener() { return 0; }
+
/// \brief If the consumer is interested in entities being deserialized from
/// AST files, it should return a pointer to a ASTDeserializationListener here
- ///
- /// The return type is void* because ASTDS lives in Frontend.
virtual ASTDeserializationListener *GetASTDeserializationListener() { return 0; }
/// PrintStats - If desired, print any statistics.
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 0a960ab..33f522f 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -45,6 +45,7 @@
class Diagnostic;
class Expr;
class ExternalASTSource;
+ class ASTMutationListener;
class IdentifierTable;
class SelectorTable;
class SourceManager;
@@ -297,6 +298,7 @@
Builtin::Context &BuiltinInfo;
DeclarationNameTable DeclarationNames;
llvm::OwningPtr<ExternalASTSource> ExternalSource;
+ ASTMutationListener *Listener;
clang::PrintingPolicy PrintingPolicy;
// Typedefs which may be provided defining the structure of Objective-C
@@ -412,6 +414,19 @@
/// with this AST context, if any.
ExternalASTSource *getExternalSource() const { return ExternalSource.get(); }
+ /// \brief Attach an AST mutation listener to the AST context.
+ ///
+ /// The AST mutation listener provides the ability to track modifications to
+ /// the abstract syntax tree entities committed after they were initially
+ /// created.
+ void setASTMutationListener(ASTMutationListener *Listener) {
+ this->Listener = Listener;
+ }
+
+ /// \brief Retrieve a pointer to the AST mutation listener associated
+ /// with this AST context, if any.
+ ASTMutationListener *getASTMutationListener() const { return Listener; }
+
void PrintStats() const;
const std::vector<Type*>& getTypes() const { return Types; }
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
new file mode 100644
index 0000000..ea09b0c
--- /dev/null
+++ b/include/clang/AST/ASTMutationListener.h
@@ -0,0 +1,30 @@
+//===--- ASTMutationListener.h - AST Mutation Interface --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ASTMutationListener interface.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
+#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H
+
+namespace clang {
+ class CXXRecordDecl;
+ class CXXMethodDecl;
+
+/// \brief An abstract interface that should be implemented by listeners
+/// that want to be notified when an AST entity gets modified after its
+/// initial creation.
+class ASTMutationListener {
+public:
+ virtual ~ASTMutationListener();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 8310017..073efa6 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -43,6 +43,7 @@
class CompoundStmt;
class StoredDeclsMap;
class DependentDiagnostic;
+class ASTMutationListener;
}
namespace llvm {
@@ -625,6 +626,8 @@
private:
const Attr *getAttrsImpl() const;
+protected:
+ ASTMutationListener *getASTMutationListener() const;
};
/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index da27cde..7370db1 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -141,7 +141,10 @@
/// \brief The block containing the definitions of all of the
/// types and decls used within the AST file.
- DECLTYPES_BLOCK_ID
+ DECLTYPES_BLOCK_ID,
+
+ /// \brief The block containing DECL_UPDATES records.
+ DECL_UPDATES_BLOCK_ID
};
/// \brief Record types that occur within the AST block itself.
@@ -326,7 +329,15 @@
/// \brief Record code for template specializations introduced after
/// serializations of the original template decl.
- ADDITIONAL_TEMPLATE_SPECIALIZATIONS = 35
+ ADDITIONAL_TEMPLATE_SPECIALIZATIONS = 35,
+
+ /// \brief Record for offsets of DECL_UPDATES records for declarations
+ /// that were modified after being deserialized and need updates.
+ DECL_UPDATE_OFFSETS = 36,
+
+ /// \brief Record of updates for a declaration that was modified after
+ /// being deserialized.
+ DECL_UPDATES = 37
};
/// \brief Record types used within a source manager block.
diff --git a/include/clang/Serialization/ASTDeserializationListener.h b/include/clang/Serialization/ASTDeserializationListener.h
index 00860cd..f8cdebe 100644
--- a/include/clang/Serialization/ASTDeserializationListener.h
+++ b/include/clang/Serialization/ASTDeserializationListener.h
@@ -29,8 +29,9 @@
virtual ~ASTDeserializationListener();
public:
- /// \brief Tell the listener about the reader.
- virtual void SetReader(ASTReader *Reader) { }
+
+ /// \brief The ASTReader was initialized.
+ virtual void ReaderInitialized(ASTReader *Reader) { }
/// \brief An identifier was deserialized from the AST file.
virtual void IdentifierRead(serialization::IdentID ID,
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index b5766b1..324e093 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -401,6 +401,14 @@
/// = I + 1 has already been loaded.
std::vector<Decl *> DeclsLoaded;
+ typedef std::pair<PerFileData *, uint64_t> FileOffset;
+ typedef llvm::SmallVector<FileOffset, 2> FileOffsetsTy;
+ typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy>
+ DeclUpdateOffsetsMap;
+ /// \brief Declarations that have modifications residing in a later file
+ /// in the chain.
+ DeclUpdateOffsetsMap DeclUpdateOffsets;
+
typedef llvm::DenseMap<serialization::DeclID,
std::pair<PerFileData *, uint64_t> >
DeclReplacementMap;
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index b2eccf3..f1a66fc 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Sema/SemaConsumer.h"
@@ -55,9 +56,11 @@
/// representation of a given abstract syntax tree and its supporting
/// data structures. This bitstream can be de-serialized via an
/// instance of the ASTReader class.
-class ASTWriter : public ASTDeserializationListener {
+class ASTWriter : public ASTDeserializationListener,
+ public ASTMutationListener {
public:
typedef llvm::SmallVector<uint64_t, 64> RecordData;
+ typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
friend class ASTDeclWriter;
private:
@@ -187,6 +190,12 @@
/// to the corresponding offsets within the preprocessor block.
std::vector<uint32_t> MacroDefinitionOffsets;
+ typedef llvm::SmallVector<uint64_t, 2> UpdateRecord;
+ typedef llvm::DenseMap<const Decl *, UpdateRecord> DeclUpdateMap;
+ /// \brief Mapping from declarations that came from a chained PCH to the
+ /// record containing modifications to them.
+ DeclUpdateMap DeclUpdates;
+
typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap;
/// \brief Map of first declarations from a chained PCH that point to the
/// most recent declarations in another PCH.
@@ -280,6 +289,7 @@
void WriteReferencedSelectorsPool(Sema &SemaRef);
void WriteIdentifierTable(Preprocessor &PP);
void WriteAttributes(const AttrVec &Attrs, RecordData &Record);
+ void WriteDeclChangeSetBlocks();
void WriteDeclUpdateBlock();
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteAdditionalTemplateSpecializations();
@@ -389,7 +399,7 @@
RecordData &Record);
/// \brief Emit a reference to a declaration.
- void AddDeclRef(const Decl *D, RecordData &Record);
+ void AddDeclRef(const Decl *D, RecordDataImpl &Record);
/// \brief Force a declaration to be emitted and get its ID.
serialization::DeclID GetDeclRef(const Decl *D);
@@ -489,7 +499,7 @@
bool hasChain() const { return Chain; }
// ASTDeserializationListener implementation
- void SetReader(ASTReader *Reader);
+ void ReaderInitialized(ASTReader *Reader);
void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II);
void TypeRead(serialization::TypeIdx Idx, QualType T);
void DeclRead(serialization::DeclID ID, const Decl *D);
@@ -508,6 +518,7 @@
std::vector<unsigned char> Buffer;
llvm::BitstreamWriter Stream;
ASTWriter Writer;
+ bool Chaining;
protected:
ASTWriter &getWriter() { return Writer; }
@@ -518,6 +529,7 @@
const char *isysroot, llvm::raw_ostream *Out);
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
+ virtual ASTMutationListener *GetASTMutationListener();
virtual ASTDeserializationListener *GetASTDeserializationListener();
};
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c7b014e..313c2ea 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
@@ -5200,6 +5201,8 @@
void ExternalASTSource::PrintStats() { }
+ASTMutationListener::~ASTMutationListener() { }
+
//===----------------------------------------------------------------------===//
// Builtin Type Computation
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index d60a067..483352f 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -210,6 +210,10 @@
return getTranslationUnitDecl()->getASTContext();
}
+ASTMutationListener *Decl::getASTMutationListener() const {
+ return getASTContext().getASTMutationListener();
+}
+
bool Decl::isUsed(bool CheckUsedAttr) const {
if (Used)
return true;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 8e1de4d..f371514 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 9718891..26ae4b1 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -167,6 +167,8 @@
llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
+ CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
+
/// Use PCH?
if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
assert(hasPCHSupport() && "This action does not have PCH support!");
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;
}