r246497 - [modules] Rework serialized DeclContext lookup table management. Instead of
Rafael EspĂndola via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 1 05:32:53 PDT 2015
Any chance this is what caused the following leak?
http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-bootstrap/builds/8340/steps/check-clang%20asan/logs/stdio
Cheers,
Rafael
On 31 August 2015 at 18:17, Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
> Author: rsmith
> Date: Mon Aug 31 17:17:11 2015
> New Revision: 246497
>
> URL: http://llvm.org/viewvc/llvm-project?rev=246497&view=rev
> Log:
> [modules] Rework serialized DeclContext lookup table management. Instead of
> walking the loaded ModuleFiles looking for lookup tables for the context, store
> them all in one place, and merge them together if we find we have too many
> (currently, more than 4). If we do merge, include the merged form in our
> serialized lookup table, so that downstream readers never need to look at our
> imports' tables.
>
> This gives a huge performance improvement to builds with very large numbers of
> modules (in some cases, more than a 2x speedup was observed).
>
> Added:
> cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h
> Modified:
> cfe/trunk/include/clang/Serialization/ASTBitCodes.h
> cfe/trunk/include/clang/Serialization/ASTReader.h
> cfe/trunk/include/clang/Serialization/ASTWriter.h
> cfe/trunk/include/clang/Serialization/Module.h
> cfe/trunk/lib/Serialization/ASTReader.cpp
> cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> cfe/trunk/lib/Serialization/ASTReaderInternals.h
> cfe/trunk/lib/Serialization/ASTWriter.cpp
> cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> cfe/trunk/lib/Serialization/Module.cpp
> cfe/trunk/test/Modules/cxx-templates.cpp
> cfe/trunk/test/Modules/merge-using-decls.cpp
>
> Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
> +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Mon Aug 31 17:17:11 2015
> @@ -1530,4 +1530,23 @@ namespace clang {
> }
> } // end namespace clang
>
> +namespace llvm {
> + template <> struct DenseMapInfo<clang::serialization::DeclarationNameKey> {
> + static clang::serialization::DeclarationNameKey getEmptyKey() {
> + return clang::serialization::DeclarationNameKey(-1, 1);
> + }
> + static clang::serialization::DeclarationNameKey getTombstoneKey() {
> + return clang::serialization::DeclarationNameKey(-1, 2);
> + }
> + static unsigned
> + getHashValue(const clang::serialization::DeclarationNameKey &Key) {
> + return Key.getHash();
> + }
> + static bool isEqual(const clang::serialization::DeclarationNameKey &L,
> + const clang::serialization::DeclarationNameKey &R) {
> + return L == R;
> + }
> + };
> +}
> +
> #endif
>
> Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
> +++ cfe/trunk/include/clang/Serialization/ASTReader.h Mon Aug 31 17:17:11 2015
> @@ -282,9 +282,8 @@ class ReadMethodPoolVisitor;
>
> namespace reader {
> class ASTIdentifierLookupTrait;
> - /// \brief The on-disk hash table used for the DeclContext's Name lookup table.
> - typedef llvm::OnDiskIterableChainedHashTable<ASTDeclContextNameLookupTrait>
> - ASTDeclContextNameLookupTable;
> + /// \brief The on-disk hash table(s) used for DeclContext name lookup.
> + struct DeclContextLookupTable;
> }
>
> } // end namespace serialization
> @@ -507,6 +506,10 @@ private:
> /// \brief Map from the TU to its lexical contents from each module file.
> std::vector<std::pair<ModuleFile*, LexicalContents>> TULexicalDecls;
>
> + /// \brief Map from a DeclContext to its lookup tables.
> + llvm::DenseMap<const DeclContext *,
> + serialization::reader::DeclContextLookupTable> Lookups;
> +
> // Updates for visible decls can occur for other contexts than just the
> // TU, and when we read those update records, the actual context may not
> // be available yet, so have this pending map using the ID as a key. It
> @@ -514,7 +517,6 @@ private:
> struct PendingVisibleUpdate {
> ModuleFile *Mod;
> const unsigned char *Data;
> - unsigned BucketOffset;
> };
> typedef SmallVector<PendingVisibleUpdate, 1> DeclContextVisibleUpdates;
>
> @@ -1089,6 +1091,10 @@ public:
> Visit(GetExistingDecl(ID));
> }
>
> + /// \brief Get the loaded lookup tables for \p Primary, if any.
> + const serialization::reader::DeclContextLookupTable *
> + getLoadedLookupTables(DeclContext *Primary) const;
> +
> private:
> struct ImportedModule {
> ModuleFile *Mod;
> @@ -1870,6 +1876,13 @@ public:
> /// Note: overrides method in ExternalASTSource
> Module *getModule(unsigned ID) override;
>
> + /// \brief Retrieve the module file with a given local ID within the specified
> + /// ModuleFile.
> + ModuleFile *getLocalModuleFile(ModuleFile &M, unsigned ID);
> +
> + /// \brief Get an ID for the given module file.
> + unsigned getModuleFileID(ModuleFile *M);
> +
> /// \brief Return a descriptor for the corresponding module.
> llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
> /// \brief Return a descriptor for the module.
>
> Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Serialization/ASTWriter.h (original)
> +++ cfe/trunk/include/clang/Serialization/ASTWriter.h Mon Aug 31 17:17:11 2015
> @@ -529,8 +529,8 @@ private:
> bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
> bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC);
>
> - uint32_t GenerateNameLookupTable(const DeclContext *DC,
> - llvm::SmallVectorImpl<char> &LookupTable);
> + void GenerateNameLookupTable(const DeclContext *DC,
> + llvm::SmallVectorImpl<char> &LookupTable);
> uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
> uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
> void WriteTypeDeclOffsets();
> @@ -849,6 +849,7 @@ public:
> unsigned getExprImplicitCastAbbrev() const { return ExprImplicitCastAbbrev; }
>
> bool hasChain() const { return Chain; }
> + ASTReader *getChain() const { return Chain; }
>
> // ASTDeserializationListener implementation
> void ReaderInitialized(ASTReader *Reader) override;
>
> Modified: cfe/trunk/include/clang/Serialization/Module.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/Module.h?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Serialization/Module.h (original)
> +++ cfe/trunk/include/clang/Serialization/Module.h Mon Aug 31 17:17:11 2015
> @@ -50,14 +50,6 @@ enum ModuleKind {
> MK_MainFile ///< File is a PCH file treated as the actual main file.
> };
>
> -/// \brief Information about the contents of a DeclContext.
> -struct DeclContextInfo {
> - DeclContextInfo() : NameLookupTableData() {}
> -
> - llvm::OnDiskIterableChainedHashTable<reader::ASTDeclContextNameLookupTrait>
> - *NameLookupTableData; // an ASTDeclContextNameLookupTable.
> -};
> -
> /// \brief The input file that has been loaded from this AST file, along with
> /// bools indicating whether this was an overridden buffer or if it was
> /// out-of-date or not-found.
> @@ -416,13 +408,6 @@ public:
> /// indexed by the C++ ctor initializer list ID minus 1.
> const uint32_t *CXXCtorInitializersOffsets;
>
> - typedef llvm::DenseMap<const DeclContext *, DeclContextInfo>
> - DeclContextInfosMap;
> -
> - /// \brief Information about the lexical and visible declarations
> - /// for each DeclContext.
> - DeclContextInfosMap DeclContextInfos;
> -
> /// \brief Array of file-level DeclIDs sorted by file.
> const serialization::DeclID *FileSortedDecls;
> unsigned NumFileSortedDecls;
>
> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Aug 31 17:17:11 2015
> @@ -20,6 +20,7 @@
> #include "clang/AST/Expr.h"
> #include "clang/AST/ExprCXX.h"
> #include "clang/Frontend/PCHContainerOperations.h"
> +#include "clang/AST/ASTMutationListener.h"
> #include "clang/AST/NestedNameSpecifier.h"
> #include "clang/AST/Type.h"
> #include "clang/AST/TypeLocVisitor.h"
> @@ -903,6 +904,13 @@ unsigned DeclarationNameKey::getHash() c
> return ID.ComputeHash();
> }
>
> +ModuleFile *
> +ASTDeclContextNameLookupTrait::ReadFileRef(const unsigned char *&d) {
> + using namespace llvm::support;
> + uint32_t ModuleFileID = endian::readNext<uint32_t, little, unaligned>(d);
> + return Reader.getLocalModuleFile(F, ModuleFileID);
> +}
> +
> std::pair<unsigned, unsigned>
> ASTDeclContextNameLookupTrait::ReadKeyDataLength(const unsigned char *&d) {
> using namespace llvm::support;
> @@ -948,15 +956,15 @@ ASTDeclContextNameLookupTrait::ReadKey(c
> return DeclarationNameKey(Kind, Data);
> }
>
> -ASTDeclContextNameLookupTrait::data_type
> -ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
> - const unsigned char *d,
> - unsigned DataLen) {
> +void ASTDeclContextNameLookupTrait::ReadDataInto(internal_key_type,
> + const unsigned char *d,
> + unsigned DataLen,
> + data_type &Val) {
> using namespace llvm::support;
> - unsigned NumDecls = DataLen / 4;
> - LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
> - const_cast<unsigned char *>(d));
> - return std::make_pair(Start, Start + NumDecls);
> + for (unsigned NumDecls = DataLen / 4; NumDecls; --NumDecls) {
> + uint32_t LocalID = endian::readNext<uint32_t, little, unaligned>(d);
> + Val.insert(Reader.getGlobalDeclID(F, LocalID));
> + }
> }
>
> bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M,
> @@ -1015,9 +1023,8 @@ bool ASTReader::ReadVisibleDeclContextSt
>
> // We can't safely determine the primary context yet, so delay attaching the
> // lookup table until we're done with recursive deserialization.
> - unsigned BucketOffset = Record[0];
> - PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{
> - &M, (const unsigned char *)Blob.data(), BucketOffset});
> + auto *Data = (const unsigned char*)Blob.data();
> + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&M, Data});
> return false;
> }
>
> @@ -2551,9 +2558,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, u
> unsigned Idx = 0;
> serialization::DeclID ID = ReadDeclID(F, Record, Idx);
> auto *Data = (const unsigned char*)Blob.data();
> - unsigned BucketOffset = Record[Idx++];
> - PendingVisibleUpdates[ID].push_back(
> - PendingVisibleUpdate{&F, Data, BucketOffset});
> + PendingVisibleUpdates[ID].push_back(PendingVisibleUpdate{&F, Data});
> // If we've already loaded the decl, perform the updates when we finish
> // loading this block.
> if (Decl *D = GetExistingDecl(ID))
> @@ -6354,196 +6359,48 @@ void ASTReader::FindFileRegionDecls(File
> Decls.push_back(GetDecl(getGlobalDeclID(*DInfo.Mod, *DIt)));
> }
>
> -/// \brief Retrieve the "definitive" module file for the definition of the
> -/// given declaration context, if there is one.
> -///
> -/// The "definitive" module file is the only place where we need to look to
> -/// find information about the declarations within the given declaration
> -/// context. For example, C++ and Objective-C classes, C structs/unions, and
> -/// Objective-C protocols, categories, and extensions are all defined in a
> -/// single place in the source code, so they have definitive module files
> -/// associated with them. C++ namespaces, on the other hand, can have
> -/// definitions in multiple different module files.
> -///
> -/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's
> -/// NDEBUG checking.
> -static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
> - ASTReader &Reader) {
> - if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
> - return Reader.getOwningModuleFile(cast<Decl>(DefDC));
> -
> - return nullptr;
> -}
> -
> -namespace {
> - /// \brief ModuleFile visitor used to perform name lookup into a
> - /// declaration context.
> - class DeclContextNameLookupVisitor {
> - ASTReader &Reader;
> - const DeclContext *Context;
> - DeclarationName Name;
> - DeclarationNameKey NameKey;
> - unsigned NameHash;
> - SmallVectorImpl<NamedDecl *> &Decls;
> - llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet;
> -
> - public:
> - DeclContextNameLookupVisitor(ASTReader &Reader, const DeclContext *Context,
> - DeclarationName Name,
> - SmallVectorImpl<NamedDecl *> &Decls,
> - llvm::SmallPtrSetImpl<NamedDecl *> &DeclSet)
> - : Reader(Reader), Context(Context), Name(Name), NameKey(Name),
> - NameHash(NameKey.getHash()), Decls(Decls), DeclSet(DeclSet) {}
> -
> - bool operator()(ModuleFile &M) {
> - // Check whether we have any visible declaration information for
> - // this context in this module.
> - auto Info = M.DeclContextInfos.find(Context);
> - if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
> - return false;
> -
> - // Look for this name within this module.
> - ASTDeclContextNameLookupTable *LookupTable =
> - Info->second.NameLookupTableData;
> - ASTDeclContextNameLookupTable::iterator Pos =
> - LookupTable->find_hashed(NameKey, NameHash);
> - if (Pos == LookupTable->end())
> - return false;
> -
> - bool FoundAnything = false;
> - ASTDeclContextNameLookupTrait::data_type Data = *Pos;
> - for (; Data.first != Data.second; ++Data.first) {
> - NamedDecl *ND = Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
> - if (!ND)
> - continue;
> -
> - if (ND->getDeclName() != Name) {
> - // Not all names map to a unique DeclarationNameKey.
> - assert(DeclarationNameKey(ND->getDeclName()) == NameKey &&
> - "mismatched name for decl in decl context lookup table?");
> - continue;
> - }
> -
> - // Record this declaration.
> - FoundAnything = true;
> - if (DeclSet.insert(ND).second)
> - Decls.push_back(ND);
> - }
> -
> - return FoundAnything;
> - }
> - };
> -}
> -
> bool
> ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
> DeclarationName Name) {
> - assert(DC->hasExternalVisibleStorage() &&
> + assert(DC->hasExternalVisibleStorage() && DC == DC->getPrimaryContext() &&
> "DeclContext has no visible decls in storage");
> if (!Name)
> return false;
>
> + auto It = Lookups.find(DC);
> + if (It == Lookups.end())
> + return false;
> +
> Deserializing LookupResults(this);
>
> + // Load the list of declarations.
> SmallVector<NamedDecl *, 64> Decls;
> - llvm::SmallPtrSet<NamedDecl*, 64> DeclSet;
> -
> - DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls, DeclSet);
> -
> - // If we can definitively determine which module file to look into,
> - // only look there. Otherwise, look in all module files.
> - if (ModuleFile *Definitive = getDefinitiveModuleFileFor(DC, *this))
> - Visitor(*Definitive);
> - else
> - ModuleMgr.visit(Visitor);
> + for (DeclID ID : It->second.Table.find(Name)) {
> + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
> + if (ND->getDeclName() == Name)
> + Decls.push_back(ND);
> + }
>
> ++NumVisibleDeclContextsRead;
> SetExternalVisibleDeclsForName(DC, Name, Decls);
> return !Decls.empty();
> }
>
> -namespace {
> - /// \brief ModuleFile visitor used to retrieve all visible names in a
> - /// declaration context.
> - class DeclContextAllNamesVisitor {
> - ASTReader &Reader;
> - SmallVectorImpl<const DeclContext *> &Contexts;
> - DeclsMap &Decls;
> - llvm::SmallPtrSet<NamedDecl *, 256> DeclSet;
> - bool VisitAll;
> -
> - public:
> - DeclContextAllNamesVisitor(ASTReader &Reader,
> - SmallVectorImpl<const DeclContext *> &Contexts,
> - DeclsMap &Decls, bool VisitAll)
> - : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
> -
> - bool operator()(ModuleFile &M) {
> - // Check whether we have any visible declaration information for
> - // this context in this module.
> - ModuleFile::DeclContextInfosMap::iterator Info;
> - bool FoundInfo = false;
> - for (unsigned I = 0, N = Contexts.size(); I != N; ++I) {
> - Info = M.DeclContextInfos.find(Contexts[I]);
> - if (Info != M.DeclContextInfos.end() &&
> - Info->second.NameLookupTableData) {
> - FoundInfo = true;
> - break;
> - }
> - }
> -
> - if (!FoundInfo)
> - return false;
> -
> - ASTDeclContextNameLookupTable *LookupTable =
> - Info->second.NameLookupTableData;
> - bool FoundAnything = false;
> - for (ASTDeclContextNameLookupTable::data_iterator
> - I = LookupTable->data_begin(), E = LookupTable->data_end();
> - I != E;
> - ++I) {
> - ASTDeclContextNameLookupTrait::data_type Data = *I;
> - for (; Data.first != Data.second; ++Data.first) {
> - NamedDecl *ND = Reader.GetLocalDeclAs<NamedDecl>(M, *Data.first);
> - if (!ND)
> - continue;
> -
> - // Record this declaration.
> - FoundAnything = true;
> - if (DeclSet.insert(ND).second)
> - Decls[ND->getDeclName()].push_back(ND);
> - }
> - }
> -
> - return FoundAnything && !VisitAll;
> - }
> - };
> -}
> -
> void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
> if (!DC->hasExternalVisibleStorage())
> return;
> +
> + auto It = Lookups.find(DC);
> + assert(It != Lookups.end() &&
> + "have external visible storage but no lookup tables");
> +
> DeclsMap Decls;
>
> - // Compute the declaration contexts we need to look into. Multiple such
> - // declaration contexts occur when two declaration contexts from disjoint
> - // modules get merged, e.g., when two namespaces with the same name are
> - // independently defined in separate modules.
> - SmallVector<const DeclContext *, 2> Contexts;
> - Contexts.push_back(DC);
> -
> - if (DC->isNamespace()) {
> - KeyDeclsMap::iterator Key =
> - KeyDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
> - if (Key != KeyDecls.end()) {
> - for (unsigned I = 0, N = Key->second.size(); I != N; ++I)
> - Contexts.push_back(cast<DeclContext>(GetDecl(Key->second[I])));
> - }
> + for (DeclID ID : It->second.Table.findAll()) {
> + NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
> + Decls[ND->getDeclName()].push_back(ND);
> }
>
> - DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
> - /*VisitAll=*/DC->isFileContext());
> - ModuleMgr.visit(Visitor);
> ++NumVisibleDeclContextsRead;
>
> for (DeclsMap::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
> @@ -6552,6 +6409,12 @@ void ASTReader::completeVisibleDeclsMap(
> const_cast<DeclContext *>(DC)->setHasExternalVisibleStorage(false);
> }
>
> +const serialization::reader::DeclContextLookupTable *
> +ASTReader::getLoadedLookupTables(DeclContext *Primary) const {
> + auto I = Lookups.find(Primary);
> + return I == Lookups.end() ? nullptr : &I->second;
> +}
> +
> /// \brief Under non-PCH compilation the consumer receives the objc methods
> /// before receiving the implementation, and codegen depends on this.
> /// We simulate this by deserializing and passing to consumer the methods of the
> @@ -7383,6 +7246,37 @@ Module *ASTReader::getModule(unsigned ID
> return getSubmodule(ID);
> }
>
> +ModuleFile *ASTReader::getLocalModuleFile(ModuleFile &F, unsigned ID) {
> + if (ID & 1) {
> + // It's a module, look it up by submodule ID.
> + auto I = GlobalSubmoduleMap.find(getGlobalSubmoduleID(F, ID >> 1));
> + return I == GlobalSubmoduleMap.end() ? nullptr : I->second;
> + } else {
> + // It's a prefix (preamble, PCH, ...). Look it up by index.
> + unsigned IndexFromEnd = ID >> 1;
> + assert(IndexFromEnd && "got reference to unknown module file");
> + return getModuleManager().pch_modules().end()[-IndexFromEnd];
> + }
> +}
> +
> +unsigned ASTReader::getModuleFileID(ModuleFile *F) {
> + if (!F)
> + return 1;
> +
> + // For a file representing a module, use the submodule ID of the top-level
> + // module as the file ID. For any other kind of file, the number of such
> + // files loaded beforehand will be the same on reload.
> + // FIXME: Is this true even if we have an explicit module file and a PCH?
> + if (F->isModule())
> + // FIXME: BaseSubmoduleID appears to be off by one.
> + return ((F->BaseSubmoduleID + 1) << 1) | 1;
> +
> + auto PCHModules = getModuleManager().pch_modules();
> + auto I = std::find(PCHModules.begin(), PCHModules.end(), F);
> + assert(I != PCHModules.end() && "emitting reference to unknown file");
> + return (I - PCHModules.end()) << 1;
> +}
> +
> ExternalASTSource::ASTSourceDescriptor
> ASTReader::getSourceDescriptor(const Module &M) {
> StringRef Dir, Filename;
> @@ -8431,6 +8325,8 @@ void ASTReader::FinishedDeserializing()
> for (auto Update : Updates) {
> auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
> auto ESI = FPT->getExtProtoInfo().ExceptionSpec;
> + if (auto *Listener = Context.getASTMutationListener())
> + Listener->ResolvedExceptionSpec(cast<FunctionDecl>(Update.second));
> for (auto *Redecl : Update.second->redecls())
> Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
> }
>
> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Mon Aug 31 17:17:11 2015
> @@ -1489,6 +1489,8 @@ void ASTDeclReader::MergeDefinitionData(
> Reader.PendingDefinitions.erase(MergeDD.Definition);
> MergeDD.Definition->IsCompleteDefinition = false;
> mergeDefinitionVisibility(DD.Definition, MergeDD.Definition);
> + assert(Reader.Lookups.find(MergeDD.Definition) == Reader.Lookups.end() &&
> + "already loaded pending lookups for merged definition");
> }
>
> auto PFDI = Reader.PendingFakeDefinitionData.find(&DD);
> @@ -3346,15 +3348,10 @@ void ASTReader::loadDeclUpdateRecords(se
> PendingVisibleUpdates.erase(I);
>
> auto *DC = cast<DeclContext>(D)->getPrimaryContext();
> - for (const PendingVisibleUpdate &Update : VisibleUpdates) {
> - auto *&LookupTable = Update.Mod->DeclContextInfos[DC].NameLookupTableData;
> - assert(!LookupTable && "multiple lookup tables for DC in module");
> - LookupTable = reader::ASTDeclContextNameLookupTable::Create(
> - Update.Data + Update.BucketOffset,
> - Update.Data + sizeof(uint32_t),
> - Update.Data,
> + for (const PendingVisibleUpdate &Update : VisibleUpdates)
> + Lookups[DC].Table.add(
> + Update.Mod, Update.Data,
> reader::ASTDeclContextNameLookupTrait(*this, *Update.Mod));
> - }
> DC->setHasExternalVisibleStorage(true);
> }
>
>
> Modified: cfe/trunk/lib/Serialization/ASTReaderInternals.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderInternals.h?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderInternals.h (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderInternals.h Mon Aug 31 17:17:11 2015
> @@ -15,8 +15,12 @@
>
> #include "clang/AST/DeclarationName.h"
> #include "clang/Serialization/ASTBitCodes.h"
> +#include "llvm/ADT/DenseSet.h"
> +#include "llvm/ADT/PointerUnion.h"
> +#include "llvm/ADT/TinyPtrVector.h"
> #include "llvm/Support/Endian.h"
> #include "llvm/Support/OnDiskHashTable.h"
> +#include "MultiOnDiskHashTable.h"
> #include <utility>
>
> namespace clang {
> @@ -39,14 +43,15 @@ class ASTDeclContextNameLookupTrait {
> ModuleFile &F;
>
> public:
> - /// \brief Pair of begin/end iterators for DeclIDs.
> - ///
> - /// Note that these declaration IDs are local to the module that contains this
> - /// particular lookup t
> - typedef llvm::support::ulittle32_t LE32DeclID;
> - typedef std::pair<LE32DeclID *, LE32DeclID *> data_type;
> + // Maximum number of lookup tables we allow before condensing the tables.
> + static const int MaxTables = 4;
> +
> + /// The lookup result is a list of global declaration IDs.
> + // FIXME: LLVM doesn't really have a good data structure for this.
> + typedef llvm::DenseSet<DeclID> data_type;
> typedef unsigned hash_value_type;
> typedef unsigned offset_type;
> + typedef ModuleFile *file_type;
>
> typedef DeclarationName external_key_type;
> typedef DeclarationNameKey internal_key_type;
> @@ -54,8 +59,7 @@ public:
> explicit ASTDeclContextNameLookupTrait(ASTReader &Reader, ModuleFile &F)
> : Reader(Reader), F(F) { }
>
> - static bool EqualKey(const internal_key_type& a,
> - const internal_key_type& b) {
> + static bool EqualKey(const internal_key_type &a, const internal_key_type &b) {
> return a == b;
> }
>
> @@ -71,8 +75,18 @@ public:
>
> internal_key_type ReadKey(const unsigned char *d, unsigned);
>
> - data_type ReadData(internal_key_type, const unsigned char *d,
> - unsigned DataLen);
> + void ReadDataInto(internal_key_type, const unsigned char *d,
> + unsigned DataLen, data_type &Val);
> +
> + static void MergeDataInto(const data_type &From, data_type &To) {
> + To.insert(From.begin(), From.end());
> + }
> +
> + file_type ReadFileRef(const unsigned char *&d);
> +};
> +
> +struct DeclContextLookupTable {
> + MultiOnDiskHashTable<ASTDeclContextNameLookupTrait> Table;
> };
>
> /// \brief Base class for the trait describing the on-disk hash table for the
>
> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Aug 31 17:17:11 2015
> @@ -13,6 +13,8 @@
>
> #include "clang/Serialization/ASTWriter.h"
> #include "ASTCommon.h"
> +#include "ASTReaderInternals.h"
> +#include "MultiOnDiskHashTable.h"
> #include "clang/AST/ASTContext.h"
> #include "clang/AST/Decl.h"
> #include "clang/AST/DeclContextInternals.h"
> @@ -3338,12 +3340,14 @@ namespace {
> // Trait used for the on-disk hash table used in the method pool.
> class ASTDeclContextNameLookupTrait {
> ASTWriter &Writer;
> + llvm::SmallVector<DeclID, 64> DeclIDs;
>
> public:
> typedef DeclarationNameKey key_type;
> typedef key_type key_type_ref;
>
> - typedef DeclContext::lookup_result data_type;
> + /// A start and end index into DeclIDs, representing a sequence of decls.
> + typedef std::pair<unsigned, unsigned> data_type;
> typedef const data_type& data_type_ref;
>
> typedef unsigned hash_value_type;
> @@ -3351,10 +3355,40 @@ public:
>
> explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
>
> + template<typename Coll>
> + data_type getData(const Coll &Decls) {
> + unsigned Start = DeclIDs.size();
> + for (NamedDecl *D : Decls) {
> + DeclIDs.push_back(
> + Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), D)));
> + }
> + return std::make_pair(Start, DeclIDs.size());
> + }
> +
> + data_type ImportData(const reader::ASTDeclContextNameLookupTrait::data_type &FromReader) {
> + unsigned Start = DeclIDs.size();
> + for (auto ID : FromReader)
> + DeclIDs.push_back(ID);
> + return std::make_pair(Start, DeclIDs.size());
> + }
> +
> + static bool EqualKey(key_type_ref a, key_type_ref b) {
> + return a == b;
> + }
> +
> hash_value_type ComputeHash(DeclarationNameKey Name) {
> return Name.getHash();
> }
>
> + void EmitFileRef(raw_ostream &Out, ModuleFile *F) const {
> + assert(Writer.hasChain() &&
> + "have reference to loaded module file but no chain?");
> +
> + using namespace llvm::support;
> + endian::Writer<little>(Out)
> + .write<uint32_t>(Writer.getChain()->getModuleFileID(F));
> + }
> +
> std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &Out,
> DeclarationNameKey Name,
> data_type_ref Lookup) {
> @@ -3381,7 +3415,9 @@ public:
> LE.write<uint16_t>(KeyLen);
>
> // 4 bytes for each DeclID.
> - unsigned DataLen = 4 * Lookup.size();
> + unsigned DataLen = 4 * (Lookup.second - Lookup.first);
> + assert(uint16_t(DataLen) == DataLen &&
> + "too many decls for serialized lookup result");
> LE.write<uint16_t>(DataLen);
>
> return std::make_pair(KeyLen, DataLen);
> @@ -3421,11 +3457,8 @@ public:
> using namespace llvm::support;
> endian::Writer<little> LE(Out);
> uint64_t Start = Out.tell(); (void)Start;
> - for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
> - I != E; ++I)
> - LE.write<uint32_t>(
> - Writer.GetDeclRef(getDeclForLocalLookup(Writer.getLangOpts(), *I)));
> -
> + for (unsigned I = Lookup.first, N = Lookup.second; I != N; ++I)
> + LE.write<uint32_t>(DeclIDs[I]);
> assert(Out.tell() - Start == DataLen && "Data length is wrong");
> }
> };
> @@ -3445,7 +3478,7 @@ bool ASTWriter::isLookupResultEntirelyEx
> return true;
> }
>
> -uint32_t
> +void
> ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
> llvm::SmallVectorImpl<char> &LookupTable) {
> assert(!ConstDC->HasLazyLocalLexicalLookups &&
> @@ -3457,8 +3490,8 @@ ASTWriter::GenerateNameLookupTable(const
> assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
>
> // Create the on-disk hash table representation.
> - llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
> - Generator;
> + MultiOnDiskHashTableGenerator<reader::ASTDeclContextNameLookupTrait,
> + ASTDeclContextNameLookupTrait> Generator;
> ASTDeclContextNameLookupTrait Trait(*this);
>
> // The first step is to collect the declaration names which we need to
> @@ -3593,7 +3626,7 @@ ASTWriter::GenerateNameLookupTable(const
>
> switch (Name.getNameKind()) {
> default:
> - Generator.insert(Name, Result, Trait);
> + Generator.insert(Name, Trait.getData(Result), Trait);
> break;
>
> case DeclarationName::CXXConstructorName:
> @@ -3611,17 +3644,15 @@ ASTWriter::GenerateNameLookupTable(const
> // the key, only the kind of name is used.
> if (!ConstructorDecls.empty())
> Generator.insert(ConstructorDecls.front()->getDeclName(),
> - DeclContext::lookup_result(ConstructorDecls), Trait);
> + Trait.getData(ConstructorDecls), Trait);
> if (!ConversionDecls.empty())
> Generator.insert(ConversionDecls.front()->getDeclName(),
> - DeclContext::lookup_result(ConversionDecls), Trait);
> + Trait.getData(ConversionDecls), Trait);
>
> - // Create the on-disk hash table in a buffer.
> - llvm::raw_svector_ostream Out(LookupTable);
> - // Make sure that no bucket is at offset 0
> - using namespace llvm::support;
> - endian::Writer<little>(Out).write<uint32_t>(0);
> - return Generator.Emit(Out, Trait);
> + // Create the on-disk hash table. Also emit the existing imported and
> + // merged table if there is one.
> + auto *Lookups = Chain ? Chain->getLoadedLookupTables(DC) : nullptr;
> + Generator.emit(LookupTable, Trait, Lookups ? &Lookups->Table : nullptr);
> }
>
> /// \brief Write the block containing all of the declaration IDs
> @@ -3704,12 +3735,11 @@ uint64_t ASTWriter::WriteDeclContextVisi
>
> // Create the on-disk hash table in a buffer.
> SmallString<4096> LookupTable;
> - uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable);
> + GenerateNameLookupTable(DC, LookupTable);
>
> // Write the lookup table
> RecordData Record;
> Record.push_back(DECL_CONTEXT_VISIBLE);
> - Record.push_back(BucketOffset);
> Stream.EmitRecordWithBlob(DeclContextVisibleLookupAbbrev, Record,
> LookupTable);
> ++NumVisibleDeclContexts;
> @@ -3732,7 +3762,7 @@ void ASTWriter::WriteDeclContextVisibleU
>
> // Create the on-disk hash table in a buffer.
> SmallString<4096> LookupTable;
> - uint32_t BucketOffset = GenerateNameLookupTable(DC, LookupTable);
> + GenerateNameLookupTable(DC, LookupTable);
>
> // If we're updating a namespace, select a key declaration as the key for the
> // update record; those are the only ones that will be checked on reload.
> @@ -3743,7 +3773,6 @@ void ASTWriter::WriteDeclContextVisibleU
> RecordData Record;
> Record.push_back(UPDATE_VISIBLE);
> Record.push_back(getDeclID(cast<Decl>(DC)));
> - Record.push_back(BucketOffset);
> Stream.EmitRecordWithBlob(UpdateVisibleAbbrev, Record, LookupTable);
> }
>
> @@ -4207,7 +4236,6 @@ void ASTWriter::WriteASTCore(Sema &SemaR
> Abv = new llvm::BitCodeAbbrev();
> Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE));
> Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::VBR, 6));
> - Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed, 32));
> Abv->Add(llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob));
> UpdateVisibleAbbrev = Stream.EmitAbbrev(Abv);
> WriteDeclContextVisibleUpdate(TU);
>
> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Mon Aug 31 17:17:11 2015
> @@ -2049,7 +2049,6 @@ void ASTWriter::WriteDeclAbbrevs() {
>
> Abv = new BitCodeAbbrev();
> Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_VISIBLE));
> - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
> Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
> DeclContextVisibleLookupAbbrev = Stream.EmitAbbrev(Abv);
> }
>
> Modified: cfe/trunk/lib/Serialization/Module.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/Module.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/Module.cpp (original)
> +++ cfe/trunk/lib/Serialization/Module.cpp Mon Aug 31 17:17:11 2015
> @@ -45,13 +45,6 @@ ModuleFile::ModuleFile(ModuleKind Kind,
> {}
>
> ModuleFile::~ModuleFile() {
> - for (DeclContextInfosMap::iterator I = DeclContextInfos.begin(),
> - E = DeclContextInfos.end();
> - I != E; ++I) {
> - if (I->second.NameLookupTableData)
> - delete I->second.NameLookupTableData;
> - }
> -
> delete static_cast<ASTIdentifierLookupTable *>(IdentifierLookupTable);
> delete static_cast<HeaderFileInfoLookupTable *>(HeaderFileInfoTable);
> delete static_cast<ASTSelectorLookupTable *>(SelectorLookupTable);
>
> Added: cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h?rev=246497&view=auto
> ==============================================================================
> --- cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h (added)
> +++ cfe/trunk/lib/Serialization/MultiOnDiskHashTable.h Mon Aug 31 17:17:11 2015
> @@ -0,0 +1,318 @@
> +//===--- MultiOnDiskHashTable.h - Merged set of hash tables -----*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file provides a hash table data structure suitable for incremental and
> +// distributed storage across a set of files.
> +//
> +// Multiple hash tables from different files are implicitly merged to improve
> +// performance, and on reload the merged table will override those from other
> +// files.
> +//
> +//===----------------------------------------------------------------------===//
> +#ifndef LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H
> +#define LLVM_CLANG_LIB_SERIALIZATION_MULTIONDISKHASHTABLE_H
> +
> +#include "llvm/ADT/PointerUnion.h"
> +#include "llvm/Support/EndianStream.h"
> +#include "llvm/Support/OnDiskHashTable.h"
> +
> +namespace clang {
> +namespace serialization {
> +
> +class ModuleFile;
> +
> +/// \brief A collection of on-disk hash tables, merged when relevant for performance.
> +template<typename Info> class MultiOnDiskHashTable {
> +public:
> + /// A handle to a file, used when overriding tables.
> + typedef typename Info::file_type file_type;
> + /// A pointer to an on-disk representation of the hash table.
> + typedef const unsigned char *storage_type;
> +
> + typedef typename Info::external_key_type external_key_type;
> + typedef typename Info::internal_key_type internal_key_type;
> + typedef typename Info::data_type data_type;
> + typedef unsigned hash_value_type;
> +
> +private:
> + /// \brief A hash table stored on disk.
> + struct OnDiskTable {
> + typedef llvm::OnDiskIterableChainedHashTable<Info> HashTable;
> +
> + file_type File;
> + HashTable Table;
> +
> + OnDiskTable(file_type File, unsigned NumBuckets, unsigned NumEntries,
> + storage_type Buckets, storage_type Payload, storage_type Base,
> + const Info &InfoObj)
> + : File(File),
> + Table(NumBuckets, NumEntries, Buckets, Payload, Base, InfoObj) {}
> + };
> +
> + struct MergedTable {
> + std::vector<file_type> Files;
> + llvm::DenseMap<internal_key_type, data_type> Data;
> + };
> +
> + typedef llvm::PointerUnion<OnDiskTable*, MergedTable*> Table;
> + typedef llvm::TinyPtrVector<void*> TableVector;
> +
> + /// \brief The current set of on-disk and merged tables.
> + /// We manually store the opaque value of the Table because TinyPtrVector
> + /// can't cope with holding a PointerUnion directly.
> + /// There can be at most one MergedTable in this vector, and if present,
> + /// it is the first table.
> + TableVector Tables;
> +
> + /// \brief Files corresponding to overridden tables that we've not yet
> + /// discarded.
> + llvm::TinyPtrVector<file_type> PendingOverrides;
> +
> + struct AsOnDiskTable {
> + typedef OnDiskTable *result_type;
> + result_type operator()(void *P) const {
> + return Table::getFromOpaqueValue(P).template get<OnDiskTable *>();
> + }
> + };
> + typedef llvm::mapped_iterator<TableVector::iterator, AsOnDiskTable>
> + table_iterator;
> + typedef llvm::iterator_range<table_iterator> table_range;
> +
> + /// \brief The current set of on-disk tables.
> + table_range tables() {
> + auto Begin = Tables.begin(), End = Tables.end();
> + if (getMergedTable())
> + ++Begin;
> + return llvm::make_range(llvm::map_iterator(Begin, AsOnDiskTable()),
> + llvm::map_iterator(End, AsOnDiskTable()));
> + }
> +
> + MergedTable *getMergedTable() const {
> + // If we already have a merged table, it's the first one.
> + return Tables.empty() ? nullptr : Table::getFromOpaqueValue(*Tables.begin())
> + .template dyn_cast<MergedTable*>();
> + }
> +
> + /// \brief Delete all our current on-disk tables.
> + void clear() {
> + if (auto *M = getMergedTable())
> + delete M;
> + for (auto *T : tables())
> + delete T;
> + }
> +
> + void removeOverriddenTables() {
> + llvm::DenseSet<file_type> Files;
> + Files.insert(PendingOverrides.begin(), PendingOverrides.end());
> + Tables.erase(
> + std::remove_if(tables().begin().getCurrent(), Tables.end(), [&](void *T) -> bool {
> + auto *ODT = Table::getFromOpaqueValue(T).template get<OnDiskTable*>();
> + return Files.count(ODT->File);
> + }), Tables.end());
> + PendingOverrides.clear();
> + }
> +
> + void condense() {
> + MergedTable *Merged = getMergedTable();
> + if (!Merged)
> + Merged = new MergedTable;
> +
> + // Read in all the tables and merge them together.
> + // FIXME: Be smarter about which tables we merge.
> + for (auto *ODT : tables()) {
> + auto &HT = ODT->Table;
> + Info &InfoObj = HT.getInfoObj();
> +
> + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) {
> + auto *LocalPtr = I.getItem();
> +
> + // FIXME: Don't rely on the OnDiskHashTable format here.
> + auto L = InfoObj.ReadKeyDataLength(LocalPtr);
> + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first);
> + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second,
> + Merged->Data[Key]);
> + }
> +
> + Merged->Files.push_back(ODT->File);
> + delete ODT;
> + }
> +
> + Tables.clear();
> + Tables.push_back(Table(Merged).getOpaqueValue());
> + }
> +
> + /// The generator is permitted to read our merged table.
> + template<typename ReaderInfo, typename WriterInfo>
> + friend class MultiOnDiskHashTableGenerator;
> +
> +public:
> + MultiOnDiskHashTable() {}
> + MultiOnDiskHashTable(MultiOnDiskHashTable &&O)
> + : Tables(std::move(O.Tables)),
> + PendingOverrides(std::move(O.PendingOverrides)) {
> + O.Tables.clear();
> + }
> + MultiOnDiskHashTable &operator=(MultiOnDiskHashTable &&O) {
> + if (&O == this)
> + return *this;
> + clear();
> + Tables = std::move(O.Tables);
> + O.Tables.clear();
> + PendingOverrides = std::move(O.PendingOverrides);
> + return *this;
> + }
> + ~MultiOnDiskHashTable() { clear(); }
> +
> + /// \brief Add the table \p Data loaded from file \p File.
> + void add(file_type File, storage_type Data, Info InfoObj = Info()) {
> + using namespace llvm::support;
> + storage_type Ptr = Data;
> +
> + uint32_t BucketOffset = endian::readNext<uint32_t, little, unaligned>(Ptr);
> +
> + // Read the list of overridden files.
> + uint32_t NumFiles = endian::readNext<uint32_t, little, unaligned>(Ptr);
> + // FIXME: Add a reserve() to TinyPtrVector so that we don't need to make
> + // an additional copy.
> + llvm::SmallVector<file_type, 16> OverriddenFiles;
> + OverriddenFiles.reserve(NumFiles);
> + for (/**/; NumFiles != 0; --NumFiles)
> + OverriddenFiles.push_back(InfoObj.ReadFileRef(Ptr));
> + PendingOverrides.insert(PendingOverrides.end(), OverriddenFiles.begin(),
> + OverriddenFiles.end());
> +
> + // Read the OnDiskChainedHashTable header.
> + storage_type Buckets = Data + BucketOffset;
> + auto NumBucketsAndEntries =
> + OnDiskTable::HashTable::readNumBucketsAndEntries(Buckets);
> +
> + // Register the table.
> + Table NewTable = new OnDiskTable(File, NumBucketsAndEntries.first,
> + NumBucketsAndEntries.second,
> + Buckets, Ptr, Data, std::move(InfoObj));
> + Tables.push_back(NewTable.getOpaqueValue());
> + }
> +
> + /// \brief Find and read the lookup results for \p EKey.
> + data_type find(const external_key_type &EKey) {
> + data_type Result;
> +
> + if (!PendingOverrides.empty())
> + removeOverriddenTables();
> +
> + if (Tables.size() > Info::MaxTables)
> + condense();
> +
> + internal_key_type Key = Info::GetInternalKey(EKey);
> + auto KeyHash = Info::ComputeHash(Key);
> +
> + if (MergedTable *M = getMergedTable()) {
> + auto It = M->Data.find(Key);
> + if (It != M->Data.end())
> + Result = It->second;
> + }
> +
> + for (auto *ODT : tables()) {
> + auto &HT = ODT->Table;
> + auto It = HT.find_hashed(Key, KeyHash);
> + if (It != HT.end())
> + HT.getInfoObj().ReadDataInto(Key, It.getDataPtr(), It.getDataLen(),
> + Result);
> + }
> +
> + return Result;
> + }
> +
> + /// \brief Read all the lookup results into a single value. This only makes
> + /// sense if merging values across keys is meaningful.
> + data_type findAll() {
> + data_type Result;
> +
> + if (!PendingOverrides.empty())
> + removeOverriddenTables();
> +
> + if (MergedTable *M = getMergedTable()) {
> + for (auto &KV : M->Data)
> + Info::MergeDataInto(KV.second, Result);
> + }
> +
> + for (auto *ODT : tables()) {
> + auto &HT = ODT->Table;
> + Info &InfoObj = HT.getInfoObj();
> + for (auto I = HT.data_begin(), E = HT.data_end(); I != E; ++I) {
> + auto *LocalPtr = I.getItem();
> +
> + // FIXME: Don't rely on the OnDiskHashTable format here.
> + auto L = InfoObj.ReadKeyDataLength(LocalPtr);
> + const internal_key_type &Key = InfoObj.ReadKey(LocalPtr, L.first);
> + InfoObj.ReadDataInto(Key, LocalPtr + L.first, L.second, Result);
> + }
> + }
> +
> + return Result;
> + }
> +};
> +
> +/// \brief Writer for the on-disk hash table.
> +template<typename ReaderInfo, typename WriterInfo>
> +class MultiOnDiskHashTableGenerator {
> + typedef MultiOnDiskHashTable<ReaderInfo> BaseTable;
> + typedef llvm::OnDiskChainedHashTableGenerator<WriterInfo> Generator;
> +
> + Generator Gen;
> +
> +public:
> + MultiOnDiskHashTableGenerator() : Gen() {}
> +
> + void insert(typename WriterInfo::key_type_ref Key,
> + typename WriterInfo::data_type_ref Data, WriterInfo &Info) {
> + Gen.insert(Key, Data, Info);
> + }
> +
> + void emit(llvm::SmallVectorImpl<char> &Out, WriterInfo &Info,
> + const BaseTable *Base) {
> + using namespace llvm::support;
> + llvm::raw_svector_ostream OutStream(Out);
> +
> + // Write our header information.
> + {
> + endian::Writer<little> Writer(OutStream);
> +
> + // Reserve four bytes for the bucket offset.
> + Writer.write<uint32_t>(0);
> +
> + if (auto *Merged = Base ? Base->getMergedTable() : nullptr) {
> + // Write list of overridden files.
> + Writer.write<uint32_t>(Merged->Files.size());
> + for (const auto &F : Merged->Files)
> + Info.EmitFileRef(OutStream, F);
> +
> + // Add all merged entries from Base to the generator.
> + for (auto &KV : Merged->Data) {
> + if (!Gen.contains(KV.first, Info))
> + Gen.insert(KV.first, Info.ImportData(KV.second), Info);
> + }
> + } else {
> + Writer.write<uint32_t>(0);
> + }
> + }
> +
> + // Write the table itself.
> + uint32_t BucketOffset = Gen.Emit(OutStream, Info);
> +
> + // Replace the first four bytes with the bucket offset.
> + endian::write32le(Out.data(), BucketOffset);
> + }
> +};
> +
> +} // end namespace clang::serialization
> +} // end namespace clang
> +
> +
> +#endif
>
> Modified: cfe/trunk/test/Modules/cxx-templates.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/cxx-templates.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/test/Modules/cxx-templates.cpp (original)
> +++ cfe/trunk/test/Modules/cxx-templates.cpp Mon Aug 31 17:17:11 2015
> @@ -29,14 +29,14 @@ void g() {
> f<int>();
> f(); // expected-error {{no matching function}}
> // expected-note at Inputs/cxx-templates-b.h:3 {{couldn't infer template argument}}
> - // expected-note at Inputs/cxx-templates-b.h:4 {{requires single argument}}
> + // expected-note-re at Inputs/cxx-templates-a.h:4 {{requires {{single|1}} argument}}
>
> N::f(0);
> N::f<double>(1.0);
> N::f<int>();
> N::f(); // expected-error {{no matching function}}
> // expected-note at Inputs/cxx-templates-b.h:6 {{couldn't infer template argument}}
> - // expected-note at Inputs/cxx-templates-b.h:7 {{requires single argument}}
> + // expected-note-re at Inputs/cxx-templates-a.h:7 {{requires {{single|1}} argument}}
>
> template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
> template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
> @@ -179,10 +179,14 @@ namespace Std {
>
> // CHECK-GLOBAL: DeclarationName 'f'
> // CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
> +// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
> +// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
> // CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'
>
> // CHECK-NAMESPACE-N: DeclarationName 'f'
> // CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
> +// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
> +// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
> // CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f'
>
> // CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate
>
> Modified: cfe/trunk/test/Modules/merge-using-decls.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/merge-using-decls.cpp?rev=246497&r1=246496&r2=246497&view=diff
> ==============================================================================
> --- cfe/trunk/test/Modules/merge-using-decls.cpp (original)
> +++ cfe/trunk/test/Modules/merge-using-decls.cpp Mon Aug 31 17:17:11 2015
> @@ -31,7 +31,9 @@ template int UseAll<YA>();
> template int UseAll<YB>();
> template int UseAll<Y>();
>
> -#if ORDER == 1
> +// Which of these two sets of diagnostics is chosen is not important. It's OK
> +// if this varies with ORDER, but it must be consistent across runs.
> +#if 1
> // Here, we're instantiating the definition from 'A' and merging the definition
> // from 'B' into it.
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list