/// declarations.
TU_UPDATE_LEXICAL = 28,
- /// \brief Record code for the array describing the first/last local
- /// redeclarations of each entity.
- LOCAL_REDECLARATIONS = 29,
+ /// \brief Record code for the array describing the locations (in the
+ /// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by
+ /// the first known ID.
+ LOCAL_REDECLARATIONS_MAP = 29,
/// \brief Record code for declarations that Sema keeps references of.
SEMA_DECL_REFS = 30,
IMPORTED_MODULES = 51,
/// \brief Record code for the set of merged declarations in an AST file.
- MERGED_DECLARATIONS = 52
+ MERGED_DECLARATIONS = 52,
+
+ /// \brief Record code for the array of redeclaration chains.
+ ///
+ /// This array can only be interpreted properly using the local
+ /// redeclarations map.
+ LOCAL_REDECLARATIONS = 53
};
/// \brief Record types used within a source manager block.
/// \brief Describes the redeclarations of a declaration.
struct LocalRedeclarationsInfo {
DeclID FirstID; // The ID of the first declaration
- DeclID FirstLocalID; // The ID of the first local declaration
- DeclID LastLocalID; // The ID of the last local declaration
+ unsigned Offset; // Offset into the array of redeclaration chains.
friend bool operator<(const LocalRedeclarationsInfo &X,
const LocalRedeclarationsInfo &Y) {
/// Objective-C protocols.
std::deque<Decl *> InterestingDecls;
- /// \brief We delay loading of the previous declaration chain to avoid
- /// deeply nested calls when there are many redeclarations.
- std::deque<std::pair<Decl *, serialization::DeclID> > PendingPreviousDecls;
-
+ /// \brief The set of redeclarable declaraations that have been deserialized
+ /// since the last time the declaration chains were linked.
+ llvm::SmallPtrSet<Decl *, 16> RedeclsDeserialized;
+
/// \brief The list of redeclaration chains that still need to be
/// reconstructed.
///
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include <map>
#include <queue>
/// serialized again. In this case, it is registered here, so that the reader
/// knows to read the updated version.
SmallVector<ReplacedDeclInfo, 16> ReplacedDecls;
-
- /// \brief The list of local redeclarations of entities that were
- /// first declared non-locally.
- SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclarations;
-
+
+ /// \brief The set of declarations that may have redeclaration chains that
+ /// need to be serialized.
+ llvm::SetVector<Decl *, llvm::SmallVector<Decl *, 4>,
+ llvm::SmallPtrSet<Decl *, 4> > Redeclarations;
+
/// \brief Statements that we've encountered while serializing a
/// declaration or type.
SmallVector<Stmt *, 16> StmtsToEmit;
void WriteDeclContextVisibleUpdate(const DeclContext *DC);
void WriteFPPragmaOptions(const FPOptions &Opts);
void WriteOpenCLExtensions(Sema &SemaRef);
+ void WriteRedeclarations();
void WriteMergedDecls();
unsigned DeclParmVarAbbrev;
/// \brief Array of file-level DeclIDs sorted by file.
const serialization::DeclID *FileSortedDecls;
- /// \brief Array of redeclaration information within this module file,
- /// sorted by the first declaration ID.
- const serialization::LocalRedeclarationsInfo *RedeclarationsInfo;
+ /// \brief Array of redeclaration chain location information within this
+ /// module file, sorted by the first declaration ID.
+ const serialization::LocalRedeclarationsInfo *RedeclarationsMap;
/// \brief The number of redeclaration info entries in RedeclarationsInfo.
- unsigned LocalNumRedeclarationsInfos;
+ unsigned LocalNumRedeclarationsInMap;
+
+ /// \brief The redeclaration chains for declarations local to this
+ /// module file.
+ SmallVector<uint64_t, 1> RedeclarationChains;
// === Types ===
}
break;
}
-
+
case LOCAL_REDECLARATIONS: {
- if (F.LocalNumRedeclarationsInfos != 0) {
- Error("duplicate LOCAL_REDECLARATIONS record in AST file");
+ F.RedeclarationChains.swap(Record);
+ break;
+ }
+
+ case LOCAL_REDECLARATIONS_MAP: {
+ if (F.LocalNumRedeclarationsInMap != 0) {
+ Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
return Failure;
}
- F.LocalNumRedeclarationsInfos = Record[0];
- F.RedeclarationsInfo = (const LocalRedeclarationsInfo *)BlobStart;
+ F.LocalNumRedeclarationsInMap = Record[0];
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
break;
}
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() ||
- !PendingPreviousDecls.empty() ||
!PendingDeclChains.empty() ||
!PendingChainedObjCCategories.empty()) {
PendingIdentifierInfos.pop_front();
}
- // Ready to load previous declarations of Decls that were delayed.
- while (!PendingPreviousDecls.empty()) {
- loadAndAttachPreviousDecl(PendingPreviousDecls.front().first,
- PendingPreviousDecls.front().second);
- PendingPreviousDecls.pop_front();
- }
-
// Load pending declaration chains.
for (unsigned I = 0; I != PendingDeclChains.size(); ++I) {
loadPendingDeclChain(PendingDeclChains[I]);
template <typename T>
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
- enum RedeclKind { FirstDeclaration = 0, FirstInFile, PointsToPrevious };
- RedeclKind Kind = (RedeclKind)Record[Idx++];
+ DeclID FirstDeclID = ReadDeclID(Record, Idx);
- DeclID FirstDeclID = 0;
- switch (Kind) {
- case FirstDeclaration:
+ // 0 indicates that this declaration was the only declaration of its entity,
+ // and is used for space optimization.
+ if (FirstDeclID == 0)
FirstDeclID = ThisDeclID;
- break;
-
- case FirstInFile:
- case PointsToPrevious: {
- FirstDeclID = ReadDeclID(Record, Idx);
- DeclID PrevDeclID = ReadDeclID(Record, Idx);
-
- T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
-
+
+ T *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID));
+ if (FirstDecl != D) {
// We delay loading of the redeclaration chain to avoid deeply nested calls.
// We temporarily set the first (canonical) declaration as the previous one
// which is the one that matters and mark the real previous DeclID to be
// loaded & attached later on.
D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(FirstDecl);
-
- if (Kind == PointsToPrevious) {
- // Make a note that we need to wire up this declaration to its
- // previous declaration, later. We don't need to do this for the first
- // declaration in any given module file, because those will be wired
- // together later.
- Reader.PendingPreviousDecls.push_back(std::make_pair(static_cast<T*>(D),
- PrevDeclID));
- }
- break;
- }
- }
-
- // The result structure takes care of note that we need to load the
+ }
+
+ // Note that this declaration has been deserialized.
+ Reader.RedeclsDeserialized.insert(static_cast<T *>(D));
+
+ // The result structure takes care to note that we need to load the
// other declaration chains for this ID.
return RedeclarableResult(Reader, FirstDeclID);
}
static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
}
+ // FIXME: Update common pointer for RedeclarableTemplateDecls?
+
// Don't introduce DCanon into the set of pending declaration chains.
Redecl.suppress();
Merged.push_back(Redecl.getFirstID());
// If ExistingCanon did not come from a module file, introduce the
- // first declaration that *does* come from a module file is in the
+ // first declaration that *does* come from a module file to the
// set of pending declaration chains, so that we merge this
// declaration.
if (!ExistingCanon->isFromASTFile() &&
class RedeclChainVisitor {
ASTReader &Reader;
SmallVectorImpl<DeclID> &SearchDecls;
+ llvm::SmallPtrSet<Decl *, 16> &Deserialized;
GlobalDeclID CanonID;
- llvm::SmallVector<std::pair<Decl *, Decl *>, 4> Chains;
+ llvm::SmallVector<Decl *, 4> Chain;
public:
RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
+ llvm::SmallPtrSet<Decl *, 16> &Deserialized,
GlobalDeclID CanonID)
- : Reader(Reader), SearchDecls(SearchDecls), CanonID(CanonID) { }
+ : Reader(Reader), SearchDecls(SearchDecls), Deserialized(Deserialized),
+ CanonID(CanonID) { }
static bool visit(ModuleFile &M, bool Preorder, void *UserData) {
if (Preorder)
return static_cast<RedeclChainVisitor *>(UserData)->visit(M);
}
+ void addToChain(Decl *D) {
+ if (!D)
+ return;
+
+ if (Deserialized.count(D)) {
+ Deserialized.erase(D);
+ Chain.push_back(D);
+ }
+ }
+
void searchForID(ModuleFile &M, GlobalDeclID GlobalID) {
// Map global ID of the first declaration down to the local ID
// used in this module file.
// Perform a binary search to find the local redeclarations for this
// declaration (if any).
const LocalRedeclarationsInfo *Result
- = std::lower_bound(M.RedeclarationsInfo,
- M.RedeclarationsInfo + M.LocalNumRedeclarationsInfos,
+ = std::lower_bound(M.RedeclarationsMap,
+ M.RedeclarationsMap + M.LocalNumRedeclarationsInMap,
ID, CompareLocalRedeclarationsInfoToID());
- if (Result == M.RedeclarationsInfo + M.LocalNumRedeclarationsInfos ||
+ if (Result == M.RedeclarationsMap + M.LocalNumRedeclarationsInMap ||
Result->FirstID != ID) {
// If we have a previously-canonical singleton declaration that was
// merged into another redeclaration chain, create a trivial chain
if (GlobalID != CanonID &&
GlobalID - NUM_PREDEF_DECL_IDS >= M.BaseDeclID &&
GlobalID - NUM_PREDEF_DECL_IDS < M.BaseDeclID + M.LocalNumDecls) {
- if (Decl *D = Reader.GetDecl(GlobalID))
- Chains.push_back(std::make_pair(D, D));
+ addToChain(Reader.GetDecl(GlobalID));
}
return;
}
// Dig out the starting/ending declarations.
- Decl *FirstLocalDecl = Reader.GetLocalDecl(M, Result->FirstLocalID);
- Decl *LastLocalDecl = Reader.GetLocalDecl(M, Result->LastLocalID);
- if (!FirstLocalDecl || !LastLocalDecl)
- return;
-
- // Append this redeclaration chain to the list.
- Chains.push_back(std::make_pair(FirstLocalDecl, LastLocalDecl));
+ unsigned Offset = Result->Offset;
+ unsigned N = M.RedeclarationChains[Offset];
+ M.RedeclarationChains[Offset++] = 0; // Don't try to deserialize again
+ for (unsigned I = 0; I != N; ++I)
+ addToChain(Reader.GetLocalDecl(M, M.RedeclarationChains[Offset++]));
}
bool visit(ModuleFile &M) {
return false;
}
- ArrayRef<std::pair<Decl *, Decl *> > getChains() const {
- return Chains;
- }
-
- void addParsed(Decl *FirstParsedDecl, Decl *LastParsedDecl) {
- Chains.push_back(std::make_pair(FirstParsedDecl, LastParsedDecl));
+ ArrayRef<Decl *> getChain() const {
+ return Chain;
}
};
}
if (MergedPos != MergedDecls.end())
SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end());
- // Build up the list of redeclaration chains.
- RedeclChainVisitor Visitor(*this, SearchDecls, CanonID);
+ // Build up the list of redeclarations.
+ RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID);
ModuleMgr.visitDepthFirst(&RedeclChainVisitor::visit, &Visitor);
// Retrieve the chains.
- ArrayRef<std::pair<Decl *, Decl *> > Chains = Visitor.getChains();
- if (Chains.empty())
+ ArrayRef<Decl *> Chain = Visitor.getChain();
+ if (Chain.empty())
return;
- // Capture all of the parsed declarations and put them at the end.
+ // Hook up the chains.
Decl *MostRecent = CanonDecl->getMostRecentDecl();
- Decl *FirstParsed = MostRecent;
- if (CanonDecl != MostRecent && !MostRecent->isFromASTFile()) {
- Decl *Current = MostRecent;
- while (Decl *Prev = Current->getPreviousDecl()) {
- if (Prev == CanonDecl)
- break;
-
- if (Prev->isFromASTFile()) {
- Current = Prev;
- continue;
- }
-
- // Chain all of the parsed declarations together.
- ASTDeclReader::attachPreviousDecl(FirstParsed, Prev);
- FirstParsed = Prev;
- Current = Prev;
- }
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (Chain[I] == CanonDecl)
+ continue;
- Visitor.addParsed(FirstParsed, MostRecent);
+ ASTDeclReader::attachPreviousDecl(Chain[I], MostRecent);
+ MostRecent = Chain[I];
}
-
- // Hook up the separate chains.
- Chains = Visitor.getChains();
- if (Chains[0].first != CanonDecl)
- ASTDeclReader::attachPreviousDecl(Chains[0].first, CanonDecl);
- for (unsigned I = 1, N = Chains.size(); I != N; ++I)
- ASTDeclReader::attachPreviousDecl(Chains[I].first, Chains[I-1].second);
- ASTDeclReader::attachLatestDecl(CanonDecl, Chains.back().second);
+
+ ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
}
namespace {
RECORD(IMPORTS);
RECORD(REFERENCED_SELECTOR_POOL);
RECORD(TU_UPDATE_LEXICAL);
- RECORD(LOCAL_REDECLARATIONS);
+ RECORD(LOCAL_REDECLARATIONS_MAP);
RECORD(SEMA_DECL_REFS);
RECORD(WEAK_UNDECLARED_IDENTIFIERS);
RECORD(PENDING_IMPLICIT_INSTANTIATIONS);
RECORD(OBJC_CHAINED_CATEGORIES);
RECORD(FILE_SORTED_DECLS);
RECORD(IMPORTED_MODULES);
-
+ RECORD(MERGED_DECLARATIONS);
+ RECORD(LOCAL_REDECLARATIONS);
+
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
RECORD(SM_SLOC_FILE_ENTRY);
Stream.EmitRecord(OPENCL_EXTENSIONS, Record);
}
+void ASTWriter::WriteRedeclarations() {
+ RecordData LocalRedeclChains;
+ SmallVector<serialization::LocalRedeclarationsInfo, 2> LocalRedeclsMap;
+
+ for (unsigned I = 0, N = Redeclarations.size(); I != N; ++I) {
+ Decl *First = Redeclarations[I];
+ assert(First->getPreviousDecl() == 0 && "Not the first declaration?");
+
+ Decl *MostRecent = First->getMostRecentDecl();
+
+ // If we only have a single declaration, there is no point in storing
+ // a redeclaration chain.
+ if (First == MostRecent)
+ continue;
+
+ unsigned Offset = LocalRedeclChains.size();
+ unsigned Size = 0;
+ LocalRedeclChains.push_back(0); // Placeholder for the size.
+
+ // Collect the set of local redeclarations of this declaration.
+ for (Decl *Prev = MostRecent; Prev != First;
+ Prev = Prev->getPreviousDecl()) {
+ if (!Prev->isFromASTFile()) {
+ AddDeclRef(Prev, LocalRedeclChains);
+ ++Size;
+ }
+ }
+ LocalRedeclChains[Offset] = Size;
+
+ // Reverse the set of local redeclarations, so that we store them in
+ // order (since we found them in reverse order).
+ std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
+
+ // Add the mapping from the first ID to the set of local declarations.
+ LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
+ LocalRedeclsMap.push_back(Info);
+
+ assert(N == Redeclarations.size() &&
+ "Deserialized a declaration we shouldn't have");
+ }
+
+ if (LocalRedeclChains.empty())
+ return;
+
+ // Sort the local redeclarations map by the first declaration ID,
+ // since the reader will be performing binary searches on this information.
+ llvm::array_pod_sort(LocalRedeclsMap.begin(), LocalRedeclsMap.end());
+
+ // Emit the local redeclarations map.
+ using namespace llvm;
+ llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS_MAP));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
+
+ RecordData Record;
+ Record.push_back(LOCAL_REDECLARATIONS_MAP);
+ Record.push_back(LocalRedeclsMap.size());
+ Stream.EmitRecordWithBlob(AbbrevID, Record,
+ reinterpret_cast<char*>(LocalRedeclsMap.data()),
+ LocalRedeclsMap.size() * sizeof(LocalRedeclarationsInfo));
+
+ // Emit the redeclaration chains.
+ Stream.EmitRecord(LOCAL_REDECLARATIONS, LocalRedeclChains);
+}
+
void ASTWriter::WriteMergedDecls() {
if (!Chain || Chain->MergedDecls.empty())
return;
WriteDeclReplacementsBlock();
WriteChainedObjCCategories();
WriteMergedDecls();
-
- if (!LocalRedeclarations.empty()) {
- // Sort the local redeclarations info by the first declaration ID,
- // since the reader will be perforing binary searches on this information.
- llvm::array_pod_sort(LocalRedeclarations.begin(),LocalRedeclarations.end());
-
- llvm::BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
- Abbrev->Add(BitCodeAbbrevOp(LOCAL_REDECLARATIONS));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # of entries
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
- unsigned AbbrevID = Stream.EmitAbbrev(Abbrev);
-
- Record.clear();
- Record.push_back(LOCAL_REDECLARATIONS);
- Record.push_back(LocalRedeclarations.size());
- Stream.EmitRecordWithBlob(AbbrevID, Record,
- reinterpret_cast<char*>(LocalRedeclarations.data()),
- LocalRedeclarations.size() * sizeof(LocalRedeclarationsInfo));
- }
+ WriteRedeclarations();
// Some simple statistics
Record.clear();
if (!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
- !D->getPreviousDecl() &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- !D->getPreviousDecl() &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
- !D->getPreviousDecl() &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
!D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
- !D->getPreviousDecl() &&
+ D->getFirstDeclaration() == D->getMostRecentDecl() &&
!D->hasCXXDirectInitializer() &&
D->getInit() == 0 &&
!isa<ParmVarDecl>(D) &&
template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
- enum { FirstDeclaration = 0, FirstInFile, PointsToPrevious };
- T *Prev = D->getPreviousDecl();
T *First = D->getFirstDeclaration();
-
- if (!Prev) {
- Record.push_back(FirstDeclaration);
- } else {
- Record.push_back(Prev->isFromASTFile()? FirstInFile : PointsToPrevious);
+ if (First->getMostRecentDecl() != First) {
+ // There is more than one declaration of this entity, so we will need to
+ // write a redeclaration chain.
Writer.AddDeclRef(First, Record);
- Writer.AddDeclRef(D->getPreviousDecl(), Record);
+ Writer.Redeclarations.insert(First);
+
+ // Make sure that we serialize both the previous and the most-recent
+ // declarations, which (transitively) ensures that all declarations in the
+ // chain get serialized.
+ (void)Writer.GetDeclRef(D->getPreviousDecl());
+ (void)Writer.GetDeclRef(First->getMostRecentDecl());
+ } else {
+ // We use the sentinel value 0 to indicate an only declaration.
+ Record.push_back(0);
}
- if (D->RedeclLink.getPointer() != D && (!Prev || Prev->isFromASTFile())) {
- // Capture the set of redeclarations in this file.
- LocalRedeclarationsInfo LocalInfo = {
- Writer.GetDeclRef(First),
- Writer.GetDeclRef(static_cast<T*>(D)),
- Writer.GetDeclRef(D->getMostRecentDecl())
- };
- Writer.LocalRedeclarations.push_back(LocalInfo);
- }
}
//===----------------------------------------------------------------------===//
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0),
- FileSortedDecls(0), RedeclarationsInfo(0), LocalNumRedeclarationsInfos(0),
+ FileSortedDecls(0), RedeclarationsMap(0), LocalNumRedeclarationsInMap(0),
LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0)
{}