diff options
Diffstat (limited to 'clang/lib/Frontend')
-rw-r--r-- | clang/lib/Frontend/PCHReader.cpp | 135 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHWriter.cpp | 173 |
2 files changed, 307 insertions, 1 deletions
diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 62d0ba4f9f0..5a1e8820674 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -1085,6 +1085,114 @@ unsigned PCHStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { //===----------------------------------------------------------------------===// namespace { +class VISIBILITY_HIDDEN PCHMethodPoolLookupTrait { + PCHReader &Reader; + +public: + typedef std::pair<ObjCMethodList, ObjCMethodList> data_type; + + typedef Selector external_key_type; + typedef external_key_type internal_key_type; + + explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + return R; + } + + // This hopefully will just get inlined and removed by the optimizer. + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); + } + + internal_key_type ReadKey(const unsigned char* d, unsigned n) { + using namespace clang::io; + SelectorTable &SelTable = Reader.getContext().Selectors; + unsigned N = ReadUnalignedLE16(d); + IdentifierInfo *FirstII + = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); + if (N == 0) + return SelTable.getNullarySelector(FirstII); + else if (N == 1) + return SelTable.getUnarySelector(FirstII); + + llvm::SmallVector<IdentifierInfo *, 16> Args; + Args.push_back(FirstII); + for (unsigned I = 1; I != N; ++I) + Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d))); + + return SelTable.getSelector(N, &Args[0]); + } + + data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) { + using namespace clang::io; + unsigned NumInstanceMethods = ReadUnalignedLE16(d); + unsigned NumFactoryMethods = ReadUnalignedLE16(d); + + data_type Result; + + // Load instance methods + ObjCMethodList *Prev = 0; + for (unsigned I = 0; I != NumInstanceMethods; ++I) { + ObjCMethodDecl *Method + = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); + if (!Result.first.Method) { + // This is the first method, which is the easy case. + Result.first.Method = Method; + Prev = &Result.first; + continue; + } + + Prev->Next = new ObjCMethodList(Method, 0); + Prev = Prev->Next; + } + + // Load factory methods + Prev = 0; + for (unsigned I = 0; I != NumFactoryMethods; ++I) { + ObjCMethodDecl *Method + = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); + if (!Result.second.Method) { + // This is the first method, which is the easy case. + Result.second.Method = Method; + Prev = &Result.second; + continue; + } + + Prev->Next = new ObjCMethodList(Method, 0); + Prev = Prev->Next; + } + + return Result; + } +}; + +} // end anonymous namespace + +/// \brief The on-disk hash table used for the global method pool. +typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait> + PCHMethodPoolLookupTable; + +namespace { class VISIBILITY_HIDDEN PCHIdentifierLookupTrait { PCHReader &Reader; @@ -1844,6 +1952,14 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset, } LocallyScopedExternalDecls.swap(Record); break; + + case pch::METHOD_POOL: + MethodPoolLookupTable + = PCHMethodPoolLookupTable::Create( + (const unsigned char *)BlobStart + Record[0], + (const unsigned char *)BlobStart, + PCHMethodPoolLookupTrait(*this)); + break; } } Error("Premature end of bitstream"); @@ -2539,6 +2655,7 @@ Decl *PCHReader::GetDecl(pch::DeclID ID) { return 0; unsigned Index = ID - 1; + assert(Index < DeclAlreadyLoaded.size() && "Declaration ID out of range"); if (DeclAlreadyLoaded[Index]) return reinterpret_cast<Decl *>(DeclOffsets[Index]); @@ -2679,7 +2796,8 @@ void PCHReader::PrintStats() { void PCHReader::InitializeSema(Sema &S) { SemaObj = &S; - + S.ExternalSource = this; + // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { @@ -2719,6 +2837,21 @@ IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) { return *Pos; } +std::pair<ObjCMethodList, ObjCMethodList> +PCHReader::ReadMethodPool(Selector Sel) { + if (!MethodPoolLookupTable) + return std::pair<ObjCMethodList, ObjCMethodList>(); + + // Try to find this selector within our on-disk hash table. + PCHMethodPoolLookupTable *PoolTable + = (PCHMethodPoolLookupTable*)MethodPoolLookupTable; + PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel); + if (Pos == PoolTable->end()) + return std::pair<ObjCMethodList, ObjCMethodList>();; + + return *Pos; +} + void PCHReader::SetIdentifierInfo(unsigned ID, const IdentifierInfo *II) { assert(ID && "Non-zero identifier ID required"); IdentifierData[ID - 1] = reinterpret_cast<uint64_t>(II); diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index de4b9990b12..581ca051a52 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -1774,6 +1774,176 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { } namespace { +// Trait used for the on-disk hash table used in the method pool. +class VISIBILITY_HIDDEN PCHMethodPoolTrait { + PCHWriter &Writer; + +public: + typedef Selector key_type; + typedef key_type key_type_ref; + + typedef std::pair<ObjCMethodList, ObjCMethodList> data_type; + typedef const data_type& data_type_ref; + + explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { } + + static unsigned ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = clang::BernsteinHashPartial(II->getName(), II->getLength(), R); + return R; + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel, + data_type_ref Methods) { + unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); + clang::io::Emit16(Out, KeyLen); + unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + DataLen += 4; + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + DataLen += 4; + clang::io::Emit16(Out, DataLen); + return std::make_pair(KeyLen, DataLen); + } + + void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) { + // FIXME: Keep track of the location of the key data (the + // selector), so we can fold the selector table's storage into + // this hash table. + unsigned N = Sel.getNumArgs(); + clang::io::Emit16(Out, N); + if (N == 0) + N = 1; + for (unsigned I = 0; I != N; ++I) + clang::io::Emit32(Out, + Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); + } + + void EmitData(llvm::raw_ostream& Out, key_type_ref, + data_type_ref Methods, unsigned) { + unsigned NumInstanceMethods = 0; + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + ++NumInstanceMethods; + + unsigned NumFactoryMethods = 0; + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + ++NumFactoryMethods; + + clang::io::Emit16(Out, NumInstanceMethods); + clang::io::Emit16(Out, NumFactoryMethods); + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + clang::io::Emit16(Out, NumFactoryMethods); + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + } +}; +} // end anonymous namespace + +/// \brief Write the method pool into the PCH file. +/// +/// The method pool contains both instance and factory methods, stored +/// in an on-disk hash table indexed by the selector. +void PCHWriter::WriteMethodPool(Sema &SemaRef) { + using namespace llvm; + + // Create and write out the blob that contains the instance and + // factor method pools. + bool Empty = true; + { + OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator; + + // Create the on-disk hash table representation. Start by + // iterating through the instance method pool. + PCHMethodPoolTrait::key_type Key; + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + Instance = SemaRef.InstanceMethodPool.begin(), + InstanceEnd = SemaRef.InstanceMethodPool.end(); + Instance != InstanceEnd; ++Instance) { + // Check whether there is a factory method with the same + // selector. + llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory + = SemaRef.FactoryMethodPool.find(Instance->first); + + if (Factory == SemaRef.FactoryMethodPool.end()) + Generator.insert(Instance->first, + std::make_pair(Instance->second, + ObjCMethodList())); + else + Generator.insert(Instance->first, + std::make_pair(Instance->second, Factory->second)); + + Empty = false; + } + + // Now iterate through the factory method pool, to pick up any + // selectors that weren't already in the instance method pool. + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + Factory = SemaRef.FactoryMethodPool.begin(), + FactoryEnd = SemaRef.FactoryMethodPool.end(); + Factory != FactoryEnd; ++Factory) { + // Check whether there is an instance method with the same + // selector. If so, there is no work to do here. + llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance + = SemaRef.InstanceMethodPool.find(Factory->first); + + if (Instance == SemaRef.InstanceMethodPool.end()) + Generator.insert(Factory->first, + std::make_pair(ObjCMethodList(), Factory->second)); + + Empty = false; + } + + if (Empty) + return; + + // Create the on-disk hash table in a buffer. + llvm::SmallVector<char, 4096> MethodPool; + uint32_t BucketOffset; + { + PCHMethodPoolTrait Trait(*this); + llvm::raw_svector_ostream Out(MethodPool); + // Make sure that no bucket is at offset 0 + clang::io::Emit16(Out, 0); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the identifier table + RecordData Record; + Record.push_back(pch::METHOD_POOL); + Record.push_back(BucketOffset); + Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, + &MethodPool.front(), + MethodPool.size()); + } +} + +namespace { class VISIBILITY_HIDDEN PCHIdentifierTableTrait { PCHWriter &Writer; Preprocessor &PP; @@ -1880,6 +2050,8 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { { PCHIdentifierTableTrait Trait(*this, PP); llvm::raw_svector_ostream Out(IdentifierTable); + // Make sure that no bucket is at offset 0 + clang::io::Emit16(Out, 0); BucketOffset = Generator.Emit(Out, Trait); } @@ -2113,6 +2285,7 @@ void PCHWriter::WritePCH(Sema &SemaRef) { WritePreprocessor(PP); WriteTypesBlock(Context); WriteDeclsBlock(Context); + WriteMethodPool(SemaRef); WriteSelectorTable(); WriteIdentifierTable(PP); Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets); |