From: Argyrios Kyrtzidis Date: Sun, 24 Oct 2010 17:26:36 +0000 (+0000) Subject: Put the mechanism in place to track modifications in an AST entity that were committe... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7b90340c9c7d07aef4e301e72b5e8a30d5f4f0c8;p=clang 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 84833c099f..08ee4ef40d 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/include/clang/AST/ASTConsumer.h @@ -19,6 +19,7 @@ namespace clang { 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 @@ public: /// 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 0a960ab34c..33f522f91b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -45,6 +45,7 @@ namespace clang { class Diagnostic; class Expr; class ExternalASTSource; + class ASTMutationListener; class IdentifierTable; class SelectorTable; class SourceManager; @@ -297,6 +298,7 @@ public: Builtin::Context &BuiltinInfo; DeclarationNameTable DeclarationNames; llvm::OwningPtr ExternalSource; + ASTMutationListener *Listener; clang::PrintingPolicy PrintingPolicy; // Typedefs which may be provided defining the structure of Objective-C @@ -412,6 +414,19 @@ public: /// 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& getTypes() const { return Types; } diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h new file mode 100644 index 0000000000..ea09b0c202 --- /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 83100178d5..073efa6902 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -43,6 +43,7 @@ class DeclarationName; class CompoundStmt; class StoredDeclsMap; class DependentDiagnostic; +class ASTMutationListener; } namespace llvm { @@ -625,6 +626,8 @@ public: 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 da27cde29f..7370db1fc4 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -141,7 +141,10 @@ namespace clang { /// \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 @@ namespace clang { /// \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 00860cd39b..f8cdebe5a9 100644 --- a/include/clang/Serialization/ASTDeserializationListener.h +++ b/include/clang/Serialization/ASTDeserializationListener.h @@ -29,8 +29,9 @@ protected: 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 b5766b14eb..324e093e73 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -401,6 +401,14 @@ private: /// = I + 1 has already been loaded. std::vector DeclsLoaded; + typedef std::pair FileOffset; + typedef llvm::SmallVector FileOffsetsTy; + typedef llvm::DenseMap + DeclUpdateOffsetsMap; + /// \brief Declarations that have modifications residing in a later file + /// in the chain. + DeclUpdateOffsetsMap DeclUpdateOffsets; + typedef llvm::DenseMap > DeclReplacementMap; diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index b2eccf393e..f1a66fcbc7 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 @@ class TargetInfo; /// 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 RecordData; + typedef llvm::SmallVectorImpl RecordDataImpl; friend class ASTDeclWriter; private: @@ -187,6 +190,12 @@ private: /// to the corresponding offsets within the preprocessor block. std::vector MacroDefinitionOffsets; + typedef llvm::SmallVector UpdateRecord; + typedef llvm::DenseMap DeclUpdateMap; + /// \brief Mapping from declarations that came from a chained PCH to the + /// record containing modifications to them. + DeclUpdateMap DeclUpdates; + typedef llvm::DenseMap FirstLatestDeclMap; /// \brief Map of first declarations from a chained PCH that point to the /// most recent declarations in another PCH. @@ -280,6 +289,7 @@ private: 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 @@ public: 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 @@ public: 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 @@ class PCHGenerator : public SemaConsumer { std::vector Buffer; llvm::BitstreamWriter Stream; ASTWriter Writer; + bool Chaining; protected: ASTWriter &getWriter() { return Writer; } @@ -518,6 +529,7 @@ public: 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 c7b014efb5..313c2ea96b 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 @@ ExternalASTSource::~ExternalASTSource() { } void ExternalASTSource::PrintStats() { } +ASTMutationListener::~ASTMutationListener() { } + //===----------------------------------------------------------------------===// // Builtin Type Computation diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index d60a06749d..483352f2d6 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -210,6 +210,10 @@ ASTContext &Decl::getASTContext() const { 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 8e1de4d027..f37151439f 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 97188919f9..26ae4b1f7f 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -167,6 +167,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, llvm::OwningPtr 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 162fa26e2d..38e786bff1 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -454,8 +454,6 @@ void PCHValidator::ReadCounter(unsigned Value) { void ASTReader::setDeserializationListener(ASTDeserializationListener *Listener) { DeserializationListener = Listener; - if (DeserializationListener) - DeserializationListener->SetReader(this); } @@ -1716,6 +1714,13 @@ ASTReader::ReadASTBlock(PerFileData &F) { } 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 @@ ASTReader::ReadASTBlock(PerFileData &F) { 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(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 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, if (Context) InitializeContext(*Context); + if (DeserializationListener) + DeserializationListener->ReaderInitialized(this); + return Success; } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 750e7236ef..acc4dc144d 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 @@ namespace clang { 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 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { } 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 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { 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 4d0ec99074..e258fcc2a2 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2474,17 +2474,6 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, 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 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, if (!AdditionalTemplateSpecializations.empty()) WriteAdditionalTemplateSpecializations(); + WriteDeclChangeSetBlocks(); + Record.clear(); Record.push_back(NumStatements); Record.push_back(NumMacros); @@ -2717,6 +2708,27 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, 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 @@ TypeIdx ASTWriter::getTypeIdx(QualType T) const { 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::AddCXXBaseOrMemberInitializers( } } -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 @@ void ASTWriter::SetReader(ASTReader *Reader) { 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 5329b6cbd4..0d8ec736b6 100644 --- a/lib/Serialization/GeneratePCH.cpp +++ b/lib/Serialization/GeneratePCH.cpp @@ -30,7 +30,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, 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 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { Buffer.clear(); } +ASTMutationListener *PCHGenerator::GetASTMutationListener() { + if (Chaining) + return &Writer; + return 0; +} + ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { return &Writer; }