clang API Documentation
00001 //===--- CacheTokens.cpp - Caching of lexer tokens for PTH support --------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This provides a possible implementation of PTH support for Clang that is 00011 // based on caching lexed tokens and identifiers. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "clang/Frontend/Utils.h" 00016 #include "clang/Basic/Diagnostic.h" 00017 #include "clang/Basic/FileManager.h" 00018 #include "clang/Basic/FileSystemStatCache.h" 00019 #include "clang/Basic/IdentifierTable.h" 00020 #include "clang/Basic/SourceManager.h" 00021 #include "clang/Lex/Lexer.h" 00022 #include "clang/Lex/Preprocessor.h" 00023 #include "llvm/ADT/StringExtras.h" 00024 #include "llvm/ADT/StringMap.h" 00025 #include "llvm/Support/EndianStream.h" 00026 #include "llvm/Support/FileSystem.h" 00027 #include "llvm/Support/MemoryBuffer.h" 00028 #include "llvm/Support/OnDiskHashTable.h" 00029 #include "llvm/Support/Path.h" 00030 #include "llvm/Support/raw_ostream.h" 00031 00032 // FIXME: put this somewhere else? 00033 #ifndef S_ISDIR 00034 #define S_ISDIR(x) (((x)&_S_IFDIR)!=0) 00035 #endif 00036 00037 using namespace clang; 00038 00039 //===----------------------------------------------------------------------===// 00040 // PTH-specific stuff. 00041 //===----------------------------------------------------------------------===// 00042 00043 typedef uint32_t Offset; 00044 00045 namespace { 00046 class PTHEntry { 00047 Offset TokenData, PPCondData; 00048 00049 public: 00050 PTHEntry() {} 00051 00052 PTHEntry(Offset td, Offset ppcd) 00053 : TokenData(td), PPCondData(ppcd) {} 00054 00055 Offset getTokenOffset() const { return TokenData; } 00056 Offset getPPCondTableOffset() const { return PPCondData; } 00057 }; 00058 00059 00060 class PTHEntryKeyVariant { 00061 union { const FileEntry* FE; const char* Path; }; 00062 enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind; 00063 FileData *Data; 00064 00065 public: 00066 PTHEntryKeyVariant(const FileEntry *fe) : FE(fe), Kind(IsFE), Data(nullptr) {} 00067 00068 PTHEntryKeyVariant(FileData *Data, const char *path) 00069 : Path(path), Kind(IsDE), Data(new FileData(*Data)) {} 00070 00071 explicit PTHEntryKeyVariant(const char *path) 00072 : Path(path), Kind(IsNoExist), Data(nullptr) {} 00073 00074 bool isFile() const { return Kind == IsFE; } 00075 00076 StringRef getString() const { 00077 return Kind == IsFE ? FE->getName() : Path; 00078 } 00079 00080 unsigned getKind() const { return (unsigned) Kind; } 00081 00082 void EmitData(raw_ostream& Out) { 00083 using namespace llvm::support; 00084 endian::Writer<little> LE(Out); 00085 switch (Kind) { 00086 case IsFE: { 00087 // Emit stat information. 00088 llvm::sys::fs::UniqueID UID = FE->getUniqueID(); 00089 LE.write<uint64_t>(UID.getFile()); 00090 LE.write<uint64_t>(UID.getDevice()); 00091 LE.write<uint64_t>(FE->getModificationTime()); 00092 LE.write<uint64_t>(FE->getSize()); 00093 } break; 00094 case IsDE: 00095 // Emit stat information. 00096 LE.write<uint64_t>(Data->UniqueID.getFile()); 00097 LE.write<uint64_t>(Data->UniqueID.getDevice()); 00098 LE.write<uint64_t>(Data->ModTime); 00099 LE.write<uint64_t>(Data->Size); 00100 delete Data; 00101 break; 00102 default: 00103 break; 00104 } 00105 } 00106 00107 unsigned getRepresentationLength() const { 00108 return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8; 00109 } 00110 }; 00111 00112 class FileEntryPTHEntryInfo { 00113 public: 00114 typedef PTHEntryKeyVariant key_type; 00115 typedef key_type key_type_ref; 00116 00117 typedef PTHEntry data_type; 00118 typedef const PTHEntry& data_type_ref; 00119 00120 typedef unsigned hash_value_type; 00121 typedef unsigned offset_type; 00122 00123 static hash_value_type ComputeHash(PTHEntryKeyVariant V) { 00124 return llvm::HashString(V.getString()); 00125 } 00126 00127 static std::pair<unsigned,unsigned> 00128 EmitKeyDataLength(raw_ostream& Out, PTHEntryKeyVariant V, 00129 const PTHEntry& E) { 00130 using namespace llvm::support; 00131 endian::Writer<little> LE(Out); 00132 00133 unsigned n = V.getString().size() + 1 + 1; 00134 LE.write<uint16_t>(n); 00135 00136 unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0); 00137 LE.write<uint8_t>(m); 00138 00139 return std::make_pair(n, m); 00140 } 00141 00142 static void EmitKey(raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ 00143 using namespace llvm::support; 00144 // Emit the entry kind. 00145 endian::Writer<little>(Out).write<uint8_t>((unsigned)V.getKind()); 00146 // Emit the string. 00147 Out.write(V.getString().data(), n - 1); 00148 } 00149 00150 static void EmitData(raw_ostream& Out, PTHEntryKeyVariant V, 00151 const PTHEntry& E, unsigned) { 00152 using namespace llvm::support; 00153 endian::Writer<little> LE(Out); 00154 00155 // For file entries emit the offsets into the PTH file for token data 00156 // and the preprocessor blocks table. 00157 if (V.isFile()) { 00158 LE.write<uint32_t>(E.getTokenOffset()); 00159 LE.write<uint32_t>(E.getPPCondTableOffset()); 00160 } 00161 00162 // Emit any other data associated with the key (i.e., stat information). 00163 V.EmitData(Out); 00164 } 00165 }; 00166 00167 class OffsetOpt { 00168 bool valid; 00169 Offset off; 00170 public: 00171 OffsetOpt() : valid(false) {} 00172 bool hasOffset() const { return valid; } 00173 Offset getOffset() const { assert(valid); return off; } 00174 void setOffset(Offset o) { off = o; valid = true; } 00175 }; 00176 } // end anonymous namespace 00177 00178 typedef llvm::OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap; 00179 00180 namespace { 00181 class PTHWriter { 00182 typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap; 00183 typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy; 00184 00185 IDMap IM; 00186 llvm::raw_fd_ostream& Out; 00187 Preprocessor& PP; 00188 uint32_t idcount; 00189 PTHMap PM; 00190 CachedStrsTy CachedStrs; 00191 Offset CurStrOffset; 00192 std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries; 00193 00194 //// Get the persistent id for the given IdentifierInfo*. 00195 uint32_t ResolveID(const IdentifierInfo* II); 00196 00197 /// Emit a token to the PTH file. 00198 void EmitToken(const Token& T); 00199 00200 void Emit8(uint32_t V) { 00201 using namespace llvm::support; 00202 endian::Writer<little>(Out).write<uint8_t>(V); 00203 } 00204 00205 void Emit16(uint32_t V) { 00206 using namespace llvm::support; 00207 endian::Writer<little>(Out).write<uint16_t>(V); 00208 } 00209 00210 void Emit32(uint32_t V) { 00211 using namespace llvm::support; 00212 endian::Writer<little>(Out).write<uint32_t>(V); 00213 } 00214 00215 void EmitBuf(const char *Ptr, unsigned NumBytes) { 00216 Out.write(Ptr, NumBytes); 00217 } 00218 00219 void EmitString(StringRef V) { 00220 using namespace llvm::support; 00221 endian::Writer<little>(Out).write<uint16_t>(V.size()); 00222 EmitBuf(V.data(), V.size()); 00223 } 00224 00225 /// EmitIdentifierTable - Emits two tables to the PTH file. The first is 00226 /// a hashtable mapping from identifier strings to persistent IDs. 00227 /// The second is a straight table mapping from persistent IDs to string data 00228 /// (the keys of the first table). 00229 std::pair<Offset, Offset> EmitIdentifierTable(); 00230 00231 /// EmitFileTable - Emit a table mapping from file name strings to PTH 00232 /// token data. 00233 Offset EmitFileTable() { return PM.Emit(Out); } 00234 00235 PTHEntry LexTokens(Lexer& L); 00236 Offset EmitCachedSpellings(); 00237 00238 public: 00239 PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp) 00240 : Out(out), PP(pp), idcount(0), CurStrOffset(0) {} 00241 00242 PTHMap &getPM() { return PM; } 00243 void GeneratePTH(const std::string &MainFile); 00244 }; 00245 } // end anonymous namespace 00246 00247 uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) { 00248 // Null IdentifierInfo's map to the persistent ID 0. 00249 if (!II) 00250 return 0; 00251 00252 IDMap::iterator I = IM.find(II); 00253 if (I != IM.end()) 00254 return I->second; // We've already added 1. 00255 00256 IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL. 00257 return idcount; 00258 } 00259 00260 void PTHWriter::EmitToken(const Token& T) { 00261 // Emit the token kind, flags, and length. 00262 Emit32(((uint32_t) T.getKind()) | ((((uint32_t) T.getFlags())) << 8)| 00263 (((uint32_t) T.getLength()) << 16)); 00264 00265 if (!T.isLiteral()) { 00266 Emit32(ResolveID(T.getIdentifierInfo())); 00267 } else { 00268 // We cache *un-cleaned* spellings. This gives us 100% fidelity with the 00269 // source code. 00270 StringRef s(T.getLiteralData(), T.getLength()); 00271 00272 // Get the string entry. 00273 llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s); 00274 00275 // If this is a new string entry, bump the PTH offset. 00276 if (!E->getValue().hasOffset()) { 00277 E->getValue().setOffset(CurStrOffset); 00278 StrEntries.push_back(E); 00279 CurStrOffset += s.size() + 1; 00280 } 00281 00282 // Emit the relative offset into the PTH file for the spelling string. 00283 Emit32(E->getValue().getOffset()); 00284 } 00285 00286 // Emit the offset into the original source file of this token so that we 00287 // can reconstruct its SourceLocation. 00288 Emit32(PP.getSourceManager().getFileOffset(T.getLocation())); 00289 } 00290 00291 PTHEntry PTHWriter::LexTokens(Lexer& L) { 00292 // Pad 0's so that we emit tokens to a 4-byte alignment. 00293 // This speed up reading them back in. 00294 using namespace llvm::support; 00295 endian::Writer<little> LE(Out); 00296 uint32_t TokenOff = Out.tell(); 00297 for (uint64_t N = llvm::OffsetToAlignment(TokenOff, 4); N; --N, ++TokenOff) 00298 LE.write<uint8_t>(0); 00299 00300 // Keep track of matching '#if' ... '#endif'. 00301 typedef std::vector<std::pair<Offset, unsigned> > PPCondTable; 00302 PPCondTable PPCond; 00303 std::vector<unsigned> PPStartCond; 00304 bool ParsingPreprocessorDirective = false; 00305 Token Tok; 00306 00307 do { 00308 L.LexFromRawLexer(Tok); 00309 NextToken: 00310 00311 if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) && 00312 ParsingPreprocessorDirective) { 00313 // Insert an eod token into the token cache. It has the same 00314 // position as the next token that is not on the same line as the 00315 // preprocessor directive. Observe that we continue processing 00316 // 'Tok' when we exit this branch. 00317 Token Tmp = Tok; 00318 Tmp.setKind(tok::eod); 00319 Tmp.clearFlag(Token::StartOfLine); 00320 Tmp.setIdentifierInfo(nullptr); 00321 EmitToken(Tmp); 00322 ParsingPreprocessorDirective = false; 00323 } 00324 00325 if (Tok.is(tok::raw_identifier)) { 00326 PP.LookUpIdentifierInfo(Tok); 00327 EmitToken(Tok); 00328 continue; 00329 } 00330 00331 if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { 00332 // Special processing for #include. Store the '#' token and lex 00333 // the next token. 00334 assert(!ParsingPreprocessorDirective); 00335 Offset HashOff = (Offset) Out.tell(); 00336 00337 // Get the next token. 00338 Token NextTok; 00339 L.LexFromRawLexer(NextTok); 00340 00341 // If we see the start of line, then we had a null directive "#". In 00342 // this case, discard both tokens. 00343 if (NextTok.isAtStartOfLine()) 00344 goto NextToken; 00345 00346 // The token is the start of a directive. Emit it. 00347 EmitToken(Tok); 00348 Tok = NextTok; 00349 00350 // Did we see 'include'/'import'/'include_next'? 00351 if (Tok.isNot(tok::raw_identifier)) { 00352 EmitToken(Tok); 00353 continue; 00354 } 00355 00356 IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok); 00357 tok::PPKeywordKind K = II->getPPKeywordID(); 00358 00359 ParsingPreprocessorDirective = true; 00360 00361 switch (K) { 00362 case tok::pp_not_keyword: 00363 // Invalid directives "#foo" can occur in #if 0 blocks etc, just pass 00364 // them through. 00365 default: 00366 break; 00367 00368 case tok::pp_include: 00369 case tok::pp_import: 00370 case tok::pp_include_next: { 00371 // Save the 'include' token. 00372 EmitToken(Tok); 00373 // Lex the next token as an include string. 00374 L.setParsingPreprocessorDirective(true); 00375 L.LexIncludeFilename(Tok); 00376 L.setParsingPreprocessorDirective(false); 00377 assert(!Tok.isAtStartOfLine()); 00378 if (Tok.is(tok::raw_identifier)) 00379 PP.LookUpIdentifierInfo(Tok); 00380 00381 break; 00382 } 00383 case tok::pp_if: 00384 case tok::pp_ifdef: 00385 case tok::pp_ifndef: { 00386 // Add an entry for '#if' and friends. We initially set the target 00387 // index to 0. This will get backpatched when we hit #endif. 00388 PPStartCond.push_back(PPCond.size()); 00389 PPCond.push_back(std::make_pair(HashOff, 0U)); 00390 break; 00391 } 00392 case tok::pp_endif: { 00393 // Add an entry for '#endif'. We set the target table index to itself. 00394 // This will later be set to zero when emitting to the PTH file. We 00395 // use 0 for uninitialized indices because that is easier to debug. 00396 unsigned index = PPCond.size(); 00397 // Backpatch the opening '#if' entry. 00398 assert(!PPStartCond.empty()); 00399 assert(PPCond.size() > PPStartCond.back()); 00400 assert(PPCond[PPStartCond.back()].second == 0); 00401 PPCond[PPStartCond.back()].second = index; 00402 PPStartCond.pop_back(); 00403 // Add the new entry to PPCond. 00404 PPCond.push_back(std::make_pair(HashOff, index)); 00405 EmitToken(Tok); 00406 00407 // Some files have gibberish on the same line as '#endif'. 00408 // Discard these tokens. 00409 do 00410 L.LexFromRawLexer(Tok); 00411 while (Tok.isNot(tok::eof) && !Tok.isAtStartOfLine()); 00412 // We have the next token in hand. 00413 // Don't immediately lex the next one. 00414 goto NextToken; 00415 } 00416 case tok::pp_elif: 00417 case tok::pp_else: { 00418 // Add an entry for #elif or #else. 00419 // This serves as both a closing and opening of a conditional block. 00420 // This means that its entry will get backpatched later. 00421 unsigned index = PPCond.size(); 00422 // Backpatch the previous '#if' entry. 00423 assert(!PPStartCond.empty()); 00424 assert(PPCond.size() > PPStartCond.back()); 00425 assert(PPCond[PPStartCond.back()].second == 0); 00426 PPCond[PPStartCond.back()].second = index; 00427 PPStartCond.pop_back(); 00428 // Now add '#elif' as a new block opening. 00429 PPCond.push_back(std::make_pair(HashOff, 0U)); 00430 PPStartCond.push_back(index); 00431 break; 00432 } 00433 } 00434 } 00435 00436 EmitToken(Tok); 00437 } 00438 while (Tok.isNot(tok::eof)); 00439 00440 assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals."); 00441 00442 // Next write out PPCond. 00443 Offset PPCondOff = (Offset) Out.tell(); 00444 00445 // Write out the size of PPCond so that clients can identifer empty tables. 00446 Emit32(PPCond.size()); 00447 00448 for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) { 00449 Emit32(PPCond[i].first - TokenOff); 00450 uint32_t x = PPCond[i].second; 00451 assert(x != 0 && "PPCond entry not backpatched."); 00452 // Emit zero for #endifs. This allows us to do checking when 00453 // we read the PTH file back in. 00454 Emit32(x == i ? 0 : x); 00455 } 00456 00457 return PTHEntry(TokenOff, PPCondOff); 00458 } 00459 00460 Offset PTHWriter::EmitCachedSpellings() { 00461 // Write each cached strings to the PTH file. 00462 Offset SpellingsOff = Out.tell(); 00463 00464 for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator 00465 I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I) 00466 EmitBuf((*I)->getKeyData(), (*I)->getKeyLength()+1 /*nul included*/); 00467 00468 return SpellingsOff; 00469 } 00470 00471 void PTHWriter::GeneratePTH(const std::string &MainFile) { 00472 // Generate the prologue. 00473 Out << "cfe-pth" << '\0'; 00474 Emit32(PTHManager::Version); 00475 00476 // Leave 4 words for the prologue. 00477 Offset PrologueOffset = Out.tell(); 00478 for (unsigned i = 0; i < 4; ++i) 00479 Emit32(0); 00480 00481 // Write the name of the MainFile. 00482 if (!MainFile.empty()) { 00483 EmitString(MainFile); 00484 } else { 00485 // String with 0 bytes. 00486 Emit16(0); 00487 } 00488 Emit8(0); 00489 00490 // Iterate over all the files in SourceManager. Create a lexer 00491 // for each file and cache the tokens. 00492 SourceManager &SM = PP.getSourceManager(); 00493 const LangOptions &LOpts = PP.getLangOpts(); 00494 00495 for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(), 00496 E = SM.fileinfo_end(); I != E; ++I) { 00497 const SrcMgr::ContentCache &C = *I->second; 00498 const FileEntry *FE = C.OrigEntry; 00499 00500 // FIXME: Handle files with non-absolute paths. 00501 if (llvm::sys::path::is_relative(FE->getName())) 00502 continue; 00503 00504 const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM); 00505 if (!B) continue; 00506 00507 FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); 00508 const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); 00509 Lexer L(FID, FromFile, SM, LOpts); 00510 PM.insert(FE, LexTokens(L)); 00511 } 00512 00513 // Write out the identifier table. 00514 const std::pair<Offset,Offset> &IdTableOff = EmitIdentifierTable(); 00515 00516 // Write out the cached strings table. 00517 Offset SpellingOff = EmitCachedSpellings(); 00518 00519 // Write out the file table. 00520 Offset FileTableOff = EmitFileTable(); 00521 00522 // Finally, write the prologue. 00523 Out.seek(PrologueOffset); 00524 Emit32(IdTableOff.first); 00525 Emit32(IdTableOff.second); 00526 Emit32(FileTableOff); 00527 Emit32(SpellingOff); 00528 } 00529 00530 namespace { 00531 /// StatListener - A simple "interpose" object used to monitor stat calls 00532 /// invoked by FileManager while processing the original sources used 00533 /// as input to PTH generation. StatListener populates the PTHWriter's 00534 /// file map with stat information for directories as well as negative stats. 00535 /// Stat information for files are populated elsewhere. 00536 class StatListener : public FileSystemStatCache { 00537 PTHMap &PM; 00538 public: 00539 StatListener(PTHMap &pm) : PM(pm) {} 00540 ~StatListener() {} 00541 00542 LookupResult getStat(const char *Path, FileData &Data, bool isFile, 00543 std::unique_ptr<vfs::File> *F, 00544 vfs::FileSystem &FS) override { 00545 LookupResult Result = statChained(Path, Data, isFile, F, FS); 00546 00547 if (Result == CacheMissing) // Failed 'stat'. 00548 PM.insert(PTHEntryKeyVariant(Path), PTHEntry()); 00549 else if (Data.IsDirectory) { 00550 // Only cache directories with absolute paths. 00551 if (llvm::sys::path::is_relative(Path)) 00552 return Result; 00553 00554 PM.insert(PTHEntryKeyVariant(&Data, Path), PTHEntry()); 00555 } 00556 00557 return Result; 00558 } 00559 }; 00560 } // end anonymous namespace 00561 00562 00563 void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { 00564 // Get the name of the main file. 00565 const SourceManager &SrcMgr = PP.getSourceManager(); 00566 const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID()); 00567 SmallString<128> MainFilePath(MainFile->getName()); 00568 00569 llvm::sys::fs::make_absolute(MainFilePath); 00570 00571 // Create the PTHWriter. 00572 PTHWriter PW(*OS, PP); 00573 00574 // Install the 'stat' system call listener in the FileManager. 00575 auto StatCacheOwner = llvm::make_unique<StatListener>(PW.getPM()); 00576 StatListener *StatCache = StatCacheOwner.get(); 00577 PP.getFileManager().addStatCache(std::move(StatCacheOwner), 00578 /*AtBeginning=*/true); 00579 00580 // Lex through the entire file. This will populate SourceManager with 00581 // all of the header information. 00582 Token Tok; 00583 PP.EnterMainSourceFile(); 00584 do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); 00585 00586 // Generate the PTH file. 00587 PP.getFileManager().removeStatCache(StatCache); 00588 PW.GeneratePTH(MainFilePath.str()); 00589 } 00590 00591 //===----------------------------------------------------------------------===// 00592 00593 namespace { 00594 class PTHIdKey { 00595 public: 00596 const IdentifierInfo* II; 00597 uint32_t FileOffset; 00598 }; 00599 00600 class PTHIdentifierTableTrait { 00601 public: 00602 typedef PTHIdKey* key_type; 00603 typedef key_type key_type_ref; 00604 00605 typedef uint32_t data_type; 00606 typedef data_type data_type_ref; 00607 00608 typedef unsigned hash_value_type; 00609 typedef unsigned offset_type; 00610 00611 static hash_value_type ComputeHash(PTHIdKey* key) { 00612 return llvm::HashString(key->II->getName()); 00613 } 00614 00615 static std::pair<unsigned,unsigned> 00616 EmitKeyDataLength(raw_ostream& Out, const PTHIdKey* key, uint32_t) { 00617 using namespace llvm::support; 00618 unsigned n = key->II->getLength() + 1; 00619 endian::Writer<little>(Out).write<uint16_t>(n); 00620 return std::make_pair(n, sizeof(uint32_t)); 00621 } 00622 00623 static void EmitKey(raw_ostream& Out, PTHIdKey* key, unsigned n) { 00624 // Record the location of the key data. This is used when generating 00625 // the mapping from persistent IDs to strings. 00626 key->FileOffset = Out.tell(); 00627 Out.write(key->II->getNameStart(), n); 00628 } 00629 00630 static void EmitData(raw_ostream& Out, PTHIdKey*, uint32_t pID, 00631 unsigned) { 00632 using namespace llvm::support; 00633 endian::Writer<little>(Out).write<uint32_t>(pID); 00634 } 00635 }; 00636 } // end anonymous namespace 00637 00638 /// EmitIdentifierTable - Emits two tables to the PTH file. The first is 00639 /// a hashtable mapping from identifier strings to persistent IDs. The second 00640 /// is a straight table mapping from persistent IDs to string data (the 00641 /// keys of the first table). 00642 /// 00643 std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() { 00644 // Build two maps: 00645 // (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset) 00646 // (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs 00647 00648 // Note that we use 'calloc', so all the bytes are 0. 00649 PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey)); 00650 00651 // Create the hashtable. 00652 llvm::OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap; 00653 00654 // Generate mapping from persistent IDs -> IdentifierInfo*. 00655 for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) { 00656 // Decrement by 1 because we are using a vector for the lookup and 00657 // 0 is reserved for NULL. 00658 assert(I->second > 0); 00659 assert(I->second-1 < idcount); 00660 unsigned idx = I->second-1; 00661 00662 // Store the mapping from persistent ID to IdentifierInfo* 00663 IIDMap[idx].II = I->first; 00664 00665 // Store the reverse mapping in a hashtable. 00666 IIOffMap.insert(&IIDMap[idx], I->second); 00667 } 00668 00669 // Write out the inverse map first. This causes the PCIDKey entries to 00670 // record PTH file offsets for the string data. This is used to write 00671 // the second table. 00672 Offset StringTableOffset = IIOffMap.Emit(Out); 00673 00674 // Now emit the table mapping from persistent IDs to PTH file offsets. 00675 Offset IDOff = Out.tell(); 00676 Emit32(idcount); // Emit the number of identifiers. 00677 for (unsigned i = 0 ; i < idcount; ++i) 00678 Emit32(IIDMap[i].FileOffset); 00679 00680 // Finally, release the inverse map. 00681 free(IIDMap); 00682 00683 return std::make_pair(IDOff, StringTableOffset); 00684 }