1*f4a2713aSLionel Sambuc //===--- PTHLexer.cpp - Lex from a token stream ---------------------------===// 2*f4a2713aSLionel Sambuc // 3*f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure 4*f4a2713aSLionel Sambuc // 5*f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source 6*f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details. 7*f4a2713aSLionel Sambuc // 8*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 9*f4a2713aSLionel Sambuc // 10*f4a2713aSLionel Sambuc // This file implements the PTHLexer interface. 11*f4a2713aSLionel Sambuc // 12*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 13*f4a2713aSLionel Sambuc 14*f4a2713aSLionel Sambuc #include "clang/Lex/PTHLexer.h" 15*f4a2713aSLionel Sambuc #include "clang/Basic/FileManager.h" 16*f4a2713aSLionel Sambuc #include "clang/Basic/FileSystemStatCache.h" 17*f4a2713aSLionel Sambuc #include "clang/Basic/IdentifierTable.h" 18*f4a2713aSLionel Sambuc #include "clang/Basic/OnDiskHashTable.h" 19*f4a2713aSLionel Sambuc #include "clang/Basic/TokenKinds.h" 20*f4a2713aSLionel Sambuc #include "clang/Lex/LexDiagnostic.h" 21*f4a2713aSLionel Sambuc #include "clang/Lex/PTHManager.h" 22*f4a2713aSLionel Sambuc #include "clang/Lex/Preprocessor.h" 23*f4a2713aSLionel Sambuc #include "clang/Lex/Token.h" 24*f4a2713aSLionel Sambuc #include "llvm/ADT/OwningPtr.h" 25*f4a2713aSLionel Sambuc #include "llvm/ADT/StringExtras.h" 26*f4a2713aSLionel Sambuc #include "llvm/ADT/StringMap.h" 27*f4a2713aSLionel Sambuc #include "llvm/Support/MemoryBuffer.h" 28*f4a2713aSLionel Sambuc #include "llvm/Support/system_error.h" 29*f4a2713aSLionel Sambuc using namespace clang; 30*f4a2713aSLionel Sambuc using namespace clang::io; 31*f4a2713aSLionel Sambuc 32*f4a2713aSLionel Sambuc #define DISK_TOKEN_SIZE (1+1+2+4+4) 33*f4a2713aSLionel Sambuc 34*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 35*f4a2713aSLionel Sambuc // PTHLexer methods. 36*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 37*f4a2713aSLionel Sambuc 38*f4a2713aSLionel Sambuc PTHLexer::PTHLexer(Preprocessor &PP, FileID FID, const unsigned char *D, 39*f4a2713aSLionel Sambuc const unsigned char *ppcond, PTHManager &PM) 40*f4a2713aSLionel Sambuc : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), LastHashTokPtr(0), 41*f4a2713aSLionel Sambuc PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM) { 42*f4a2713aSLionel Sambuc 43*f4a2713aSLionel Sambuc FileStartLoc = PP.getSourceManager().getLocForStartOfFile(FID); 44*f4a2713aSLionel Sambuc } 45*f4a2713aSLionel Sambuc 46*f4a2713aSLionel Sambuc bool PTHLexer::Lex(Token& Tok) { 47*f4a2713aSLionel Sambuc //===--------------------------------------==// 48*f4a2713aSLionel Sambuc // Read the raw token data. 49*f4a2713aSLionel Sambuc //===--------------------------------------==// 50*f4a2713aSLionel Sambuc 51*f4a2713aSLionel Sambuc // Shadow CurPtr into an automatic variable. 52*f4a2713aSLionel Sambuc const unsigned char *CurPtrShadow = CurPtr; 53*f4a2713aSLionel Sambuc 54*f4a2713aSLionel Sambuc // Read in the data for the token. 55*f4a2713aSLionel Sambuc unsigned Word0 = ReadLE32(CurPtrShadow); 56*f4a2713aSLionel Sambuc uint32_t IdentifierID = ReadLE32(CurPtrShadow); 57*f4a2713aSLionel Sambuc uint32_t FileOffset = ReadLE32(CurPtrShadow); 58*f4a2713aSLionel Sambuc 59*f4a2713aSLionel Sambuc tok::TokenKind TKind = (tok::TokenKind) (Word0 & 0xFF); 60*f4a2713aSLionel Sambuc Token::TokenFlags TFlags = (Token::TokenFlags) ((Word0 >> 8) & 0xFF); 61*f4a2713aSLionel Sambuc uint32_t Len = Word0 >> 16; 62*f4a2713aSLionel Sambuc 63*f4a2713aSLionel Sambuc CurPtr = CurPtrShadow; 64*f4a2713aSLionel Sambuc 65*f4a2713aSLionel Sambuc //===--------------------------------------==// 66*f4a2713aSLionel Sambuc // Construct the token itself. 67*f4a2713aSLionel Sambuc //===--------------------------------------==// 68*f4a2713aSLionel Sambuc 69*f4a2713aSLionel Sambuc Tok.startToken(); 70*f4a2713aSLionel Sambuc Tok.setKind(TKind); 71*f4a2713aSLionel Sambuc Tok.setFlag(TFlags); 72*f4a2713aSLionel Sambuc assert(!LexingRawMode); 73*f4a2713aSLionel Sambuc Tok.setLocation(FileStartLoc.getLocWithOffset(FileOffset)); 74*f4a2713aSLionel Sambuc Tok.setLength(Len); 75*f4a2713aSLionel Sambuc 76*f4a2713aSLionel Sambuc // Handle identifiers. 77*f4a2713aSLionel Sambuc if (Tok.isLiteral()) { 78*f4a2713aSLionel Sambuc Tok.setLiteralData((const char*) (PTHMgr.SpellingBase + IdentifierID)); 79*f4a2713aSLionel Sambuc } 80*f4a2713aSLionel Sambuc else if (IdentifierID) { 81*f4a2713aSLionel Sambuc MIOpt.ReadToken(); 82*f4a2713aSLionel Sambuc IdentifierInfo *II = PTHMgr.GetIdentifierInfo(IdentifierID-1); 83*f4a2713aSLionel Sambuc 84*f4a2713aSLionel Sambuc Tok.setIdentifierInfo(II); 85*f4a2713aSLionel Sambuc 86*f4a2713aSLionel Sambuc // Change the kind of this identifier to the appropriate token kind, e.g. 87*f4a2713aSLionel Sambuc // turning "for" into a keyword. 88*f4a2713aSLionel Sambuc Tok.setKind(II->getTokenID()); 89*f4a2713aSLionel Sambuc 90*f4a2713aSLionel Sambuc if (II->isHandleIdentifierCase()) 91*f4a2713aSLionel Sambuc return PP->HandleIdentifier(Tok); 92*f4a2713aSLionel Sambuc 93*f4a2713aSLionel Sambuc return true; 94*f4a2713aSLionel Sambuc } 95*f4a2713aSLionel Sambuc 96*f4a2713aSLionel Sambuc //===--------------------------------------==// 97*f4a2713aSLionel Sambuc // Process the token. 98*f4a2713aSLionel Sambuc //===--------------------------------------==// 99*f4a2713aSLionel Sambuc if (TKind == tok::eof) { 100*f4a2713aSLionel Sambuc // Save the end-of-file token. 101*f4a2713aSLionel Sambuc EofToken = Tok; 102*f4a2713aSLionel Sambuc 103*f4a2713aSLionel Sambuc assert(!ParsingPreprocessorDirective); 104*f4a2713aSLionel Sambuc assert(!LexingRawMode); 105*f4a2713aSLionel Sambuc 106*f4a2713aSLionel Sambuc return LexEndOfFile(Tok); 107*f4a2713aSLionel Sambuc } 108*f4a2713aSLionel Sambuc 109*f4a2713aSLionel Sambuc if (TKind == tok::hash && Tok.isAtStartOfLine()) { 110*f4a2713aSLionel Sambuc LastHashTokPtr = CurPtr - DISK_TOKEN_SIZE; 111*f4a2713aSLionel Sambuc assert(!LexingRawMode); 112*f4a2713aSLionel Sambuc PP->HandleDirective(Tok); 113*f4a2713aSLionel Sambuc 114*f4a2713aSLionel Sambuc return false; 115*f4a2713aSLionel Sambuc } 116*f4a2713aSLionel Sambuc 117*f4a2713aSLionel Sambuc if (TKind == tok::eod) { 118*f4a2713aSLionel Sambuc assert(ParsingPreprocessorDirective); 119*f4a2713aSLionel Sambuc ParsingPreprocessorDirective = false; 120*f4a2713aSLionel Sambuc return true; 121*f4a2713aSLionel Sambuc } 122*f4a2713aSLionel Sambuc 123*f4a2713aSLionel Sambuc MIOpt.ReadToken(); 124*f4a2713aSLionel Sambuc return true; 125*f4a2713aSLionel Sambuc } 126*f4a2713aSLionel Sambuc 127*f4a2713aSLionel Sambuc bool PTHLexer::LexEndOfFile(Token &Result) { 128*f4a2713aSLionel Sambuc // If we hit the end of the file while parsing a preprocessor directive, 129*f4a2713aSLionel Sambuc // end the preprocessor directive first. The next token returned will 130*f4a2713aSLionel Sambuc // then be the end of file. 131*f4a2713aSLionel Sambuc if (ParsingPreprocessorDirective) { 132*f4a2713aSLionel Sambuc ParsingPreprocessorDirective = false; // Done parsing the "line". 133*f4a2713aSLionel Sambuc return true; // Have a token. 134*f4a2713aSLionel Sambuc } 135*f4a2713aSLionel Sambuc 136*f4a2713aSLionel Sambuc assert(!LexingRawMode); 137*f4a2713aSLionel Sambuc 138*f4a2713aSLionel Sambuc // If we are in a #if directive, emit an error. 139*f4a2713aSLionel Sambuc while (!ConditionalStack.empty()) { 140*f4a2713aSLionel Sambuc if (PP->getCodeCompletionFileLoc() != FileStartLoc) 141*f4a2713aSLionel Sambuc PP->Diag(ConditionalStack.back().IfLoc, 142*f4a2713aSLionel Sambuc diag::err_pp_unterminated_conditional); 143*f4a2713aSLionel Sambuc ConditionalStack.pop_back(); 144*f4a2713aSLionel Sambuc } 145*f4a2713aSLionel Sambuc 146*f4a2713aSLionel Sambuc // Finally, let the preprocessor handle this. 147*f4a2713aSLionel Sambuc return PP->HandleEndOfFile(Result); 148*f4a2713aSLionel Sambuc } 149*f4a2713aSLionel Sambuc 150*f4a2713aSLionel Sambuc // FIXME: We can just grab the last token instead of storing a copy 151*f4a2713aSLionel Sambuc // into EofToken. 152*f4a2713aSLionel Sambuc void PTHLexer::getEOF(Token& Tok) { 153*f4a2713aSLionel Sambuc assert(EofToken.is(tok::eof)); 154*f4a2713aSLionel Sambuc Tok = EofToken; 155*f4a2713aSLionel Sambuc } 156*f4a2713aSLionel Sambuc 157*f4a2713aSLionel Sambuc void PTHLexer::DiscardToEndOfLine() { 158*f4a2713aSLionel Sambuc assert(ParsingPreprocessorDirective && ParsingFilename == false && 159*f4a2713aSLionel Sambuc "Must be in a preprocessing directive!"); 160*f4a2713aSLionel Sambuc 161*f4a2713aSLionel Sambuc // We assume that if the preprocessor wishes to discard to the end of 162*f4a2713aSLionel Sambuc // the line that it also means to end the current preprocessor directive. 163*f4a2713aSLionel Sambuc ParsingPreprocessorDirective = false; 164*f4a2713aSLionel Sambuc 165*f4a2713aSLionel Sambuc // Skip tokens by only peeking at their token kind and the flags. 166*f4a2713aSLionel Sambuc // We don't need to actually reconstruct full tokens from the token buffer. 167*f4a2713aSLionel Sambuc // This saves some copies and it also reduces IdentifierInfo* lookup. 168*f4a2713aSLionel Sambuc const unsigned char* p = CurPtr; 169*f4a2713aSLionel Sambuc while (1) { 170*f4a2713aSLionel Sambuc // Read the token kind. Are we at the end of the file? 171*f4a2713aSLionel Sambuc tok::TokenKind x = (tok::TokenKind) (uint8_t) *p; 172*f4a2713aSLionel Sambuc if (x == tok::eof) break; 173*f4a2713aSLionel Sambuc 174*f4a2713aSLionel Sambuc // Read the token flags. Are we at the start of the next line? 175*f4a2713aSLionel Sambuc Token::TokenFlags y = (Token::TokenFlags) (uint8_t) p[1]; 176*f4a2713aSLionel Sambuc if (y & Token::StartOfLine) break; 177*f4a2713aSLionel Sambuc 178*f4a2713aSLionel Sambuc // Skip to the next token. 179*f4a2713aSLionel Sambuc p += DISK_TOKEN_SIZE; 180*f4a2713aSLionel Sambuc } 181*f4a2713aSLionel Sambuc 182*f4a2713aSLionel Sambuc CurPtr = p; 183*f4a2713aSLionel Sambuc } 184*f4a2713aSLionel Sambuc 185*f4a2713aSLionel Sambuc /// SkipBlock - Used by Preprocessor to skip the current conditional block. 186*f4a2713aSLionel Sambuc bool PTHLexer::SkipBlock() { 187*f4a2713aSLionel Sambuc assert(CurPPCondPtr && "No cached PP conditional information."); 188*f4a2713aSLionel Sambuc assert(LastHashTokPtr && "No known '#' token."); 189*f4a2713aSLionel Sambuc 190*f4a2713aSLionel Sambuc const unsigned char* HashEntryI = 0; 191*f4a2713aSLionel Sambuc uint32_t TableIdx; 192*f4a2713aSLionel Sambuc 193*f4a2713aSLionel Sambuc do { 194*f4a2713aSLionel Sambuc // Read the token offset from the side-table. 195*f4a2713aSLionel Sambuc uint32_t Offset = ReadLE32(CurPPCondPtr); 196*f4a2713aSLionel Sambuc 197*f4a2713aSLionel Sambuc // Read the target table index from the side-table. 198*f4a2713aSLionel Sambuc TableIdx = ReadLE32(CurPPCondPtr); 199*f4a2713aSLionel Sambuc 200*f4a2713aSLionel Sambuc // Compute the actual memory address of the '#' token data for this entry. 201*f4a2713aSLionel Sambuc HashEntryI = TokBuf + Offset; 202*f4a2713aSLionel Sambuc 203*f4a2713aSLionel Sambuc // Optmization: "Sibling jumping". #if...#else...#endif blocks can 204*f4a2713aSLionel Sambuc // contain nested blocks. In the side-table we can jump over these 205*f4a2713aSLionel Sambuc // nested blocks instead of doing a linear search if the next "sibling" 206*f4a2713aSLionel Sambuc // entry is not at a location greater than LastHashTokPtr. 207*f4a2713aSLionel Sambuc if (HashEntryI < LastHashTokPtr && TableIdx) { 208*f4a2713aSLionel Sambuc // In the side-table we are still at an entry for a '#' token that 209*f4a2713aSLionel Sambuc // is earlier than the last one we saw. Check if the location we would 210*f4a2713aSLionel Sambuc // stride gets us closer. 211*f4a2713aSLionel Sambuc const unsigned char* NextPPCondPtr = 212*f4a2713aSLionel Sambuc PPCond + TableIdx*(sizeof(uint32_t)*2); 213*f4a2713aSLionel Sambuc assert(NextPPCondPtr >= CurPPCondPtr); 214*f4a2713aSLionel Sambuc // Read where we should jump to. 215*f4a2713aSLionel Sambuc const unsigned char* HashEntryJ = TokBuf + ReadLE32(NextPPCondPtr); 216*f4a2713aSLionel Sambuc 217*f4a2713aSLionel Sambuc if (HashEntryJ <= LastHashTokPtr) { 218*f4a2713aSLionel Sambuc // Jump directly to the next entry in the side table. 219*f4a2713aSLionel Sambuc HashEntryI = HashEntryJ; 220*f4a2713aSLionel Sambuc TableIdx = ReadLE32(NextPPCondPtr); 221*f4a2713aSLionel Sambuc CurPPCondPtr = NextPPCondPtr; 222*f4a2713aSLionel Sambuc } 223*f4a2713aSLionel Sambuc } 224*f4a2713aSLionel Sambuc } 225*f4a2713aSLionel Sambuc while (HashEntryI < LastHashTokPtr); 226*f4a2713aSLionel Sambuc assert(HashEntryI == LastHashTokPtr && "No PP-cond entry found for '#'"); 227*f4a2713aSLionel Sambuc assert(TableIdx && "No jumping from #endifs."); 228*f4a2713aSLionel Sambuc 229*f4a2713aSLionel Sambuc // Update our side-table iterator. 230*f4a2713aSLionel Sambuc const unsigned char* NextPPCondPtr = PPCond + TableIdx*(sizeof(uint32_t)*2); 231*f4a2713aSLionel Sambuc assert(NextPPCondPtr >= CurPPCondPtr); 232*f4a2713aSLionel Sambuc CurPPCondPtr = NextPPCondPtr; 233*f4a2713aSLionel Sambuc 234*f4a2713aSLionel Sambuc // Read where we should jump to. 235*f4a2713aSLionel Sambuc HashEntryI = TokBuf + ReadLE32(NextPPCondPtr); 236*f4a2713aSLionel Sambuc uint32_t NextIdx = ReadLE32(NextPPCondPtr); 237*f4a2713aSLionel Sambuc 238*f4a2713aSLionel Sambuc // By construction NextIdx will be zero if this is a #endif. This is useful 239*f4a2713aSLionel Sambuc // to know to obviate lexing another token. 240*f4a2713aSLionel Sambuc bool isEndif = NextIdx == 0; 241*f4a2713aSLionel Sambuc 242*f4a2713aSLionel Sambuc // This case can occur when we see something like this: 243*f4a2713aSLionel Sambuc // 244*f4a2713aSLionel Sambuc // #if ... 245*f4a2713aSLionel Sambuc // /* a comment or nothing */ 246*f4a2713aSLionel Sambuc // #elif 247*f4a2713aSLionel Sambuc // 248*f4a2713aSLionel Sambuc // If we are skipping the first #if block it will be the case that CurPtr 249*f4a2713aSLionel Sambuc // already points 'elif'. Just return. 250*f4a2713aSLionel Sambuc 251*f4a2713aSLionel Sambuc if (CurPtr > HashEntryI) { 252*f4a2713aSLionel Sambuc assert(CurPtr == HashEntryI + DISK_TOKEN_SIZE); 253*f4a2713aSLionel Sambuc // Did we reach a #endif? If so, go ahead and consume that token as well. 254*f4a2713aSLionel Sambuc if (isEndif) 255*f4a2713aSLionel Sambuc CurPtr += DISK_TOKEN_SIZE*2; 256*f4a2713aSLionel Sambuc else 257*f4a2713aSLionel Sambuc LastHashTokPtr = HashEntryI; 258*f4a2713aSLionel Sambuc 259*f4a2713aSLionel Sambuc return isEndif; 260*f4a2713aSLionel Sambuc } 261*f4a2713aSLionel Sambuc 262*f4a2713aSLionel Sambuc // Otherwise, we need to advance. Update CurPtr to point to the '#' token. 263*f4a2713aSLionel Sambuc CurPtr = HashEntryI; 264*f4a2713aSLionel Sambuc 265*f4a2713aSLionel Sambuc // Update the location of the last observed '#'. This is useful if we 266*f4a2713aSLionel Sambuc // are skipping multiple blocks. 267*f4a2713aSLionel Sambuc LastHashTokPtr = CurPtr; 268*f4a2713aSLionel Sambuc 269*f4a2713aSLionel Sambuc // Skip the '#' token. 270*f4a2713aSLionel Sambuc assert(((tok::TokenKind)*CurPtr) == tok::hash); 271*f4a2713aSLionel Sambuc CurPtr += DISK_TOKEN_SIZE; 272*f4a2713aSLionel Sambuc 273*f4a2713aSLionel Sambuc // Did we reach a #endif? If so, go ahead and consume that token as well. 274*f4a2713aSLionel Sambuc if (isEndif) { CurPtr += DISK_TOKEN_SIZE*2; } 275*f4a2713aSLionel Sambuc 276*f4a2713aSLionel Sambuc return isEndif; 277*f4a2713aSLionel Sambuc } 278*f4a2713aSLionel Sambuc 279*f4a2713aSLionel Sambuc SourceLocation PTHLexer::getSourceLocation() { 280*f4a2713aSLionel Sambuc // getSourceLocation is not on the hot path. It is used to get the location 281*f4a2713aSLionel Sambuc // of the next token when transitioning back to this lexer when done 282*f4a2713aSLionel Sambuc // handling a #included file. Just read the necessary data from the token 283*f4a2713aSLionel Sambuc // data buffer to construct the SourceLocation object. 284*f4a2713aSLionel Sambuc // NOTE: This is a virtual function; hence it is defined out-of-line. 285*f4a2713aSLionel Sambuc const unsigned char *OffsetPtr = CurPtr + (DISK_TOKEN_SIZE - 4); 286*f4a2713aSLionel Sambuc uint32_t Offset = ReadLE32(OffsetPtr); 287*f4a2713aSLionel Sambuc return FileStartLoc.getLocWithOffset(Offset); 288*f4a2713aSLionel Sambuc } 289*f4a2713aSLionel Sambuc 290*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 291*f4a2713aSLionel Sambuc // PTH file lookup: map from strings to file data. 292*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 293*f4a2713aSLionel Sambuc 294*f4a2713aSLionel Sambuc /// PTHFileLookup - This internal data structure is used by the PTHManager 295*f4a2713aSLionel Sambuc /// to map from FileEntry objects managed by FileManager to offsets within 296*f4a2713aSLionel Sambuc /// the PTH file. 297*f4a2713aSLionel Sambuc namespace { 298*f4a2713aSLionel Sambuc class PTHFileData { 299*f4a2713aSLionel Sambuc const uint32_t TokenOff; 300*f4a2713aSLionel Sambuc const uint32_t PPCondOff; 301*f4a2713aSLionel Sambuc public: 302*f4a2713aSLionel Sambuc PTHFileData(uint32_t tokenOff, uint32_t ppCondOff) 303*f4a2713aSLionel Sambuc : TokenOff(tokenOff), PPCondOff(ppCondOff) {} 304*f4a2713aSLionel Sambuc 305*f4a2713aSLionel Sambuc uint32_t getTokenOffset() const { return TokenOff; } 306*f4a2713aSLionel Sambuc uint32_t getPPCondOffset() const { return PPCondOff; } 307*f4a2713aSLionel Sambuc }; 308*f4a2713aSLionel Sambuc 309*f4a2713aSLionel Sambuc 310*f4a2713aSLionel Sambuc class PTHFileLookupCommonTrait { 311*f4a2713aSLionel Sambuc public: 312*f4a2713aSLionel Sambuc typedef std::pair<unsigned char, const char*> internal_key_type; 313*f4a2713aSLionel Sambuc 314*f4a2713aSLionel Sambuc static unsigned ComputeHash(internal_key_type x) { 315*f4a2713aSLionel Sambuc return llvm::HashString(x.second); 316*f4a2713aSLionel Sambuc } 317*f4a2713aSLionel Sambuc 318*f4a2713aSLionel Sambuc static std::pair<unsigned, unsigned> 319*f4a2713aSLionel Sambuc ReadKeyDataLength(const unsigned char*& d) { 320*f4a2713aSLionel Sambuc unsigned keyLen = (unsigned) ReadUnalignedLE16(d); 321*f4a2713aSLionel Sambuc unsigned dataLen = (unsigned) *(d++); 322*f4a2713aSLionel Sambuc return std::make_pair(keyLen, dataLen); 323*f4a2713aSLionel Sambuc } 324*f4a2713aSLionel Sambuc 325*f4a2713aSLionel Sambuc static internal_key_type ReadKey(const unsigned char* d, unsigned) { 326*f4a2713aSLionel Sambuc unsigned char k = *(d++); // Read the entry kind. 327*f4a2713aSLionel Sambuc return std::make_pair(k, (const char*) d); 328*f4a2713aSLionel Sambuc } 329*f4a2713aSLionel Sambuc }; 330*f4a2713aSLionel Sambuc 331*f4a2713aSLionel Sambuc class PTHFileLookupTrait : public PTHFileLookupCommonTrait { 332*f4a2713aSLionel Sambuc public: 333*f4a2713aSLionel Sambuc typedef const FileEntry* external_key_type; 334*f4a2713aSLionel Sambuc typedef PTHFileData data_type; 335*f4a2713aSLionel Sambuc 336*f4a2713aSLionel Sambuc static internal_key_type GetInternalKey(const FileEntry* FE) { 337*f4a2713aSLionel Sambuc return std::make_pair((unsigned char) 0x1, FE->getName()); 338*f4a2713aSLionel Sambuc } 339*f4a2713aSLionel Sambuc 340*f4a2713aSLionel Sambuc static bool EqualKey(internal_key_type a, internal_key_type b) { 341*f4a2713aSLionel Sambuc return a.first == b.first && strcmp(a.second, b.second) == 0; 342*f4a2713aSLionel Sambuc } 343*f4a2713aSLionel Sambuc 344*f4a2713aSLionel Sambuc static PTHFileData ReadData(const internal_key_type& k, 345*f4a2713aSLionel Sambuc const unsigned char* d, unsigned) { 346*f4a2713aSLionel Sambuc assert(k.first == 0x1 && "Only file lookups can match!"); 347*f4a2713aSLionel Sambuc uint32_t x = ::ReadUnalignedLE32(d); 348*f4a2713aSLionel Sambuc uint32_t y = ::ReadUnalignedLE32(d); 349*f4a2713aSLionel Sambuc return PTHFileData(x, y); 350*f4a2713aSLionel Sambuc } 351*f4a2713aSLionel Sambuc }; 352*f4a2713aSLionel Sambuc 353*f4a2713aSLionel Sambuc class PTHStringLookupTrait { 354*f4a2713aSLionel Sambuc public: 355*f4a2713aSLionel Sambuc typedef uint32_t 356*f4a2713aSLionel Sambuc data_type; 357*f4a2713aSLionel Sambuc 358*f4a2713aSLionel Sambuc typedef const std::pair<const char*, unsigned> 359*f4a2713aSLionel Sambuc external_key_type; 360*f4a2713aSLionel Sambuc 361*f4a2713aSLionel Sambuc typedef external_key_type internal_key_type; 362*f4a2713aSLionel Sambuc 363*f4a2713aSLionel Sambuc static bool EqualKey(const internal_key_type& a, 364*f4a2713aSLionel Sambuc const internal_key_type& b) { 365*f4a2713aSLionel Sambuc return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 366*f4a2713aSLionel Sambuc : false; 367*f4a2713aSLionel Sambuc } 368*f4a2713aSLionel Sambuc 369*f4a2713aSLionel Sambuc static unsigned ComputeHash(const internal_key_type& a) { 370*f4a2713aSLionel Sambuc return llvm::HashString(StringRef(a.first, a.second)); 371*f4a2713aSLionel Sambuc } 372*f4a2713aSLionel Sambuc 373*f4a2713aSLionel Sambuc // This hopefully will just get inlined and removed by the optimizer. 374*f4a2713aSLionel Sambuc static const internal_key_type& 375*f4a2713aSLionel Sambuc GetInternalKey(const external_key_type& x) { return x; } 376*f4a2713aSLionel Sambuc 377*f4a2713aSLionel Sambuc static std::pair<unsigned, unsigned> 378*f4a2713aSLionel Sambuc ReadKeyDataLength(const unsigned char*& d) { 379*f4a2713aSLionel Sambuc return std::make_pair((unsigned) ReadUnalignedLE16(d), sizeof(uint32_t)); 380*f4a2713aSLionel Sambuc } 381*f4a2713aSLionel Sambuc 382*f4a2713aSLionel Sambuc static std::pair<const char*, unsigned> 383*f4a2713aSLionel Sambuc ReadKey(const unsigned char* d, unsigned n) { 384*f4a2713aSLionel Sambuc assert(n >= 2 && d[n-1] == '\0'); 385*f4a2713aSLionel Sambuc return std::make_pair((const char*) d, n-1); 386*f4a2713aSLionel Sambuc } 387*f4a2713aSLionel Sambuc 388*f4a2713aSLionel Sambuc static uint32_t ReadData(const internal_key_type& k, const unsigned char* d, 389*f4a2713aSLionel Sambuc unsigned) { 390*f4a2713aSLionel Sambuc return ::ReadUnalignedLE32(d); 391*f4a2713aSLionel Sambuc } 392*f4a2713aSLionel Sambuc }; 393*f4a2713aSLionel Sambuc 394*f4a2713aSLionel Sambuc } // end anonymous namespace 395*f4a2713aSLionel Sambuc 396*f4a2713aSLionel Sambuc typedef OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup; 397*f4a2713aSLionel Sambuc typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup; 398*f4a2713aSLionel Sambuc 399*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 400*f4a2713aSLionel Sambuc // PTHManager methods. 401*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 402*f4a2713aSLionel Sambuc 403*f4a2713aSLionel Sambuc PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup, 404*f4a2713aSLionel Sambuc const unsigned char* idDataTable, 405*f4a2713aSLionel Sambuc IdentifierInfo** perIDCache, 406*f4a2713aSLionel Sambuc void* stringIdLookup, unsigned numIds, 407*f4a2713aSLionel Sambuc const unsigned char* spellingBase, 408*f4a2713aSLionel Sambuc const char* originalSourceFile) 409*f4a2713aSLionel Sambuc : Buf(buf), PerIDCache(perIDCache), FileLookup(fileLookup), 410*f4a2713aSLionel Sambuc IdDataTable(idDataTable), StringIdLookup(stringIdLookup), 411*f4a2713aSLionel Sambuc NumIds(numIds), PP(0), SpellingBase(spellingBase), 412*f4a2713aSLionel Sambuc OriginalSourceFile(originalSourceFile) {} 413*f4a2713aSLionel Sambuc 414*f4a2713aSLionel Sambuc PTHManager::~PTHManager() { 415*f4a2713aSLionel Sambuc delete Buf; 416*f4a2713aSLionel Sambuc delete (PTHFileLookup*) FileLookup; 417*f4a2713aSLionel Sambuc delete (PTHStringIdLookup*) StringIdLookup; 418*f4a2713aSLionel Sambuc free(PerIDCache); 419*f4a2713aSLionel Sambuc } 420*f4a2713aSLionel Sambuc 421*f4a2713aSLionel Sambuc static void InvalidPTH(DiagnosticsEngine &Diags, const char *Msg) { 422*f4a2713aSLionel Sambuc Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, Msg)); 423*f4a2713aSLionel Sambuc } 424*f4a2713aSLionel Sambuc 425*f4a2713aSLionel Sambuc PTHManager *PTHManager::Create(const std::string &file, 426*f4a2713aSLionel Sambuc DiagnosticsEngine &Diags) { 427*f4a2713aSLionel Sambuc // Memory map the PTH file. 428*f4a2713aSLionel Sambuc OwningPtr<llvm::MemoryBuffer> File; 429*f4a2713aSLionel Sambuc 430*f4a2713aSLionel Sambuc if (llvm::MemoryBuffer::getFile(file, File)) { 431*f4a2713aSLionel Sambuc // FIXME: Add ec.message() to this diag. 432*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 433*f4a2713aSLionel Sambuc return 0; 434*f4a2713aSLionel Sambuc } 435*f4a2713aSLionel Sambuc 436*f4a2713aSLionel Sambuc // Get the buffer ranges and check if there are at least three 32-bit 437*f4a2713aSLionel Sambuc // words at the end of the file. 438*f4a2713aSLionel Sambuc const unsigned char *BufBeg = (const unsigned char*)File->getBufferStart(); 439*f4a2713aSLionel Sambuc const unsigned char *BufEnd = (const unsigned char*)File->getBufferEnd(); 440*f4a2713aSLionel Sambuc 441*f4a2713aSLionel Sambuc // Check the prologue of the file. 442*f4a2713aSLionel Sambuc if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 4 + 4) || 443*f4a2713aSLionel Sambuc memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth")) != 0) { 444*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 445*f4a2713aSLionel Sambuc return 0; 446*f4a2713aSLionel Sambuc } 447*f4a2713aSLionel Sambuc 448*f4a2713aSLionel Sambuc // Read the PTH version. 449*f4a2713aSLionel Sambuc const unsigned char *p = BufBeg + (sizeof("cfe-pth")); 450*f4a2713aSLionel Sambuc unsigned Version = ReadLE32(p); 451*f4a2713aSLionel Sambuc 452*f4a2713aSLionel Sambuc if (Version < PTHManager::Version) { 453*f4a2713aSLionel Sambuc InvalidPTH(Diags, 454*f4a2713aSLionel Sambuc Version < PTHManager::Version 455*f4a2713aSLionel Sambuc ? "PTH file uses an older PTH format that is no longer supported" 456*f4a2713aSLionel Sambuc : "PTH file uses a newer PTH format that cannot be read"); 457*f4a2713aSLionel Sambuc return 0; 458*f4a2713aSLionel Sambuc } 459*f4a2713aSLionel Sambuc 460*f4a2713aSLionel Sambuc // Compute the address of the index table at the end of the PTH file. 461*f4a2713aSLionel Sambuc const unsigned char *PrologueOffset = p; 462*f4a2713aSLionel Sambuc 463*f4a2713aSLionel Sambuc if (PrologueOffset >= BufEnd) { 464*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 465*f4a2713aSLionel Sambuc return 0; 466*f4a2713aSLionel Sambuc } 467*f4a2713aSLionel Sambuc 468*f4a2713aSLionel Sambuc // Construct the file lookup table. This will be used for mapping from 469*f4a2713aSLionel Sambuc // FileEntry*'s to cached tokens. 470*f4a2713aSLionel Sambuc const unsigned char* FileTableOffset = PrologueOffset + sizeof(uint32_t)*2; 471*f4a2713aSLionel Sambuc const unsigned char* FileTable = BufBeg + ReadLE32(FileTableOffset); 472*f4a2713aSLionel Sambuc 473*f4a2713aSLionel Sambuc if (!(FileTable > BufBeg && FileTable < BufEnd)) { 474*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 475*f4a2713aSLionel Sambuc return 0; // FIXME: Proper error diagnostic? 476*f4a2713aSLionel Sambuc } 477*f4a2713aSLionel Sambuc 478*f4a2713aSLionel Sambuc OwningPtr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg)); 479*f4a2713aSLionel Sambuc 480*f4a2713aSLionel Sambuc // Warn if the PTH file is empty. We still want to create a PTHManager 481*f4a2713aSLionel Sambuc // as the PTH could be used with -include-pth. 482*f4a2713aSLionel Sambuc if (FL->isEmpty()) 483*f4a2713aSLionel Sambuc InvalidPTH(Diags, "PTH file contains no cached source data"); 484*f4a2713aSLionel Sambuc 485*f4a2713aSLionel Sambuc // Get the location of the table mapping from persistent ids to the 486*f4a2713aSLionel Sambuc // data needed to reconstruct identifiers. 487*f4a2713aSLionel Sambuc const unsigned char* IDTableOffset = PrologueOffset + sizeof(uint32_t)*0; 488*f4a2713aSLionel Sambuc const unsigned char* IData = BufBeg + ReadLE32(IDTableOffset); 489*f4a2713aSLionel Sambuc 490*f4a2713aSLionel Sambuc if (!(IData >= BufBeg && IData < BufEnd)) { 491*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 492*f4a2713aSLionel Sambuc return 0; 493*f4a2713aSLionel Sambuc } 494*f4a2713aSLionel Sambuc 495*f4a2713aSLionel Sambuc // Get the location of the hashtable mapping between strings and 496*f4a2713aSLionel Sambuc // persistent IDs. 497*f4a2713aSLionel Sambuc const unsigned char* StringIdTableOffset = PrologueOffset + sizeof(uint32_t)*1; 498*f4a2713aSLionel Sambuc const unsigned char* StringIdTable = BufBeg + ReadLE32(StringIdTableOffset); 499*f4a2713aSLionel Sambuc if (!(StringIdTable >= BufBeg && StringIdTable < BufEnd)) { 500*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 501*f4a2713aSLionel Sambuc return 0; 502*f4a2713aSLionel Sambuc } 503*f4a2713aSLionel Sambuc 504*f4a2713aSLionel Sambuc OwningPtr<PTHStringIdLookup> SL(PTHStringIdLookup::Create(StringIdTable, 505*f4a2713aSLionel Sambuc BufBeg)); 506*f4a2713aSLionel Sambuc 507*f4a2713aSLionel Sambuc // Get the location of the spelling cache. 508*f4a2713aSLionel Sambuc const unsigned char* spellingBaseOffset = PrologueOffset + sizeof(uint32_t)*3; 509*f4a2713aSLionel Sambuc const unsigned char* spellingBase = BufBeg + ReadLE32(spellingBaseOffset); 510*f4a2713aSLionel Sambuc if (!(spellingBase >= BufBeg && spellingBase < BufEnd)) { 511*f4a2713aSLionel Sambuc Diags.Report(diag::err_invalid_pth_file) << file; 512*f4a2713aSLionel Sambuc return 0; 513*f4a2713aSLionel Sambuc } 514*f4a2713aSLionel Sambuc 515*f4a2713aSLionel Sambuc // Get the number of IdentifierInfos and pre-allocate the identifier cache. 516*f4a2713aSLionel Sambuc uint32_t NumIds = ReadLE32(IData); 517*f4a2713aSLionel Sambuc 518*f4a2713aSLionel Sambuc // Pre-allocate the persistent ID -> IdentifierInfo* cache. We use calloc() 519*f4a2713aSLionel Sambuc // so that we in the best case only zero out memory once when the OS returns 520*f4a2713aSLionel Sambuc // us new pages. 521*f4a2713aSLionel Sambuc IdentifierInfo** PerIDCache = 0; 522*f4a2713aSLionel Sambuc 523*f4a2713aSLionel Sambuc if (NumIds) { 524*f4a2713aSLionel Sambuc PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache)); 525*f4a2713aSLionel Sambuc if (!PerIDCache) { 526*f4a2713aSLionel Sambuc InvalidPTH(Diags, "Could not allocate memory for processing PTH file"); 527*f4a2713aSLionel Sambuc return 0; 528*f4a2713aSLionel Sambuc } 529*f4a2713aSLionel Sambuc } 530*f4a2713aSLionel Sambuc 531*f4a2713aSLionel Sambuc // Compute the address of the original source file. 532*f4a2713aSLionel Sambuc const unsigned char* originalSourceBase = PrologueOffset + sizeof(uint32_t)*4; 533*f4a2713aSLionel Sambuc unsigned len = ReadUnalignedLE16(originalSourceBase); 534*f4a2713aSLionel Sambuc if (!len) originalSourceBase = 0; 535*f4a2713aSLionel Sambuc 536*f4a2713aSLionel Sambuc // Create the new PTHManager. 537*f4a2713aSLionel Sambuc return new PTHManager(File.take(), FL.take(), IData, PerIDCache, 538*f4a2713aSLionel Sambuc SL.take(), NumIds, spellingBase, 539*f4a2713aSLionel Sambuc (const char*) originalSourceBase); 540*f4a2713aSLionel Sambuc } 541*f4a2713aSLionel Sambuc 542*f4a2713aSLionel Sambuc IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { 543*f4a2713aSLionel Sambuc // Look in the PTH file for the string data for the IdentifierInfo object. 544*f4a2713aSLionel Sambuc const unsigned char* TableEntry = IdDataTable + sizeof(uint32_t)*PersistentID; 545*f4a2713aSLionel Sambuc const unsigned char* IDData = 546*f4a2713aSLionel Sambuc (const unsigned char*)Buf->getBufferStart() + ReadLE32(TableEntry); 547*f4a2713aSLionel Sambuc assert(IDData < (const unsigned char*)Buf->getBufferEnd()); 548*f4a2713aSLionel Sambuc 549*f4a2713aSLionel Sambuc // Allocate the object. 550*f4a2713aSLionel Sambuc std::pair<IdentifierInfo,const unsigned char*> *Mem = 551*f4a2713aSLionel Sambuc Alloc.Allocate<std::pair<IdentifierInfo,const unsigned char*> >(); 552*f4a2713aSLionel Sambuc 553*f4a2713aSLionel Sambuc Mem->second = IDData; 554*f4a2713aSLionel Sambuc assert(IDData[0] != '\0'); 555*f4a2713aSLionel Sambuc IdentifierInfo *II = new ((void*) Mem) IdentifierInfo(); 556*f4a2713aSLionel Sambuc 557*f4a2713aSLionel Sambuc // Store the new IdentifierInfo in the cache. 558*f4a2713aSLionel Sambuc PerIDCache[PersistentID] = II; 559*f4a2713aSLionel Sambuc assert(II->getNameStart() && II->getNameStart()[0] != '\0'); 560*f4a2713aSLionel Sambuc return II; 561*f4a2713aSLionel Sambuc } 562*f4a2713aSLionel Sambuc 563*f4a2713aSLionel Sambuc IdentifierInfo* PTHManager::get(StringRef Name) { 564*f4a2713aSLionel Sambuc PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup); 565*f4a2713aSLionel Sambuc // Double check our assumption that the last character isn't '\0'. 566*f4a2713aSLionel Sambuc assert(Name.empty() || Name.back() != '\0'); 567*f4a2713aSLionel Sambuc PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(), 568*f4a2713aSLionel Sambuc Name.size())); 569*f4a2713aSLionel Sambuc if (I == SL.end()) // No identifier found? 570*f4a2713aSLionel Sambuc return 0; 571*f4a2713aSLionel Sambuc 572*f4a2713aSLionel Sambuc // Match found. Return the identifier! 573*f4a2713aSLionel Sambuc assert(*I > 0); 574*f4a2713aSLionel Sambuc return GetIdentifierInfo(*I-1); 575*f4a2713aSLionel Sambuc } 576*f4a2713aSLionel Sambuc 577*f4a2713aSLionel Sambuc PTHLexer *PTHManager::CreateLexer(FileID FID) { 578*f4a2713aSLionel Sambuc const FileEntry *FE = PP->getSourceManager().getFileEntryForID(FID); 579*f4a2713aSLionel Sambuc if (!FE) 580*f4a2713aSLionel Sambuc return 0; 581*f4a2713aSLionel Sambuc 582*f4a2713aSLionel Sambuc // Lookup the FileEntry object in our file lookup data structure. It will 583*f4a2713aSLionel Sambuc // return a variant that indicates whether or not there is an offset within 584*f4a2713aSLionel Sambuc // the PTH file that contains cached tokens. 585*f4a2713aSLionel Sambuc PTHFileLookup& PFL = *((PTHFileLookup*)FileLookup); 586*f4a2713aSLionel Sambuc PTHFileLookup::iterator I = PFL.find(FE); 587*f4a2713aSLionel Sambuc 588*f4a2713aSLionel Sambuc if (I == PFL.end()) // No tokens available? 589*f4a2713aSLionel Sambuc return 0; 590*f4a2713aSLionel Sambuc 591*f4a2713aSLionel Sambuc const PTHFileData& FileData = *I; 592*f4a2713aSLionel Sambuc 593*f4a2713aSLionel Sambuc const unsigned char *BufStart = (const unsigned char *)Buf->getBufferStart(); 594*f4a2713aSLionel Sambuc // Compute the offset of the token data within the buffer. 595*f4a2713aSLionel Sambuc const unsigned char* data = BufStart + FileData.getTokenOffset(); 596*f4a2713aSLionel Sambuc 597*f4a2713aSLionel Sambuc // Get the location of pp-conditional table. 598*f4a2713aSLionel Sambuc const unsigned char* ppcond = BufStart + FileData.getPPCondOffset(); 599*f4a2713aSLionel Sambuc uint32_t Len = ReadLE32(ppcond); 600*f4a2713aSLionel Sambuc if (Len == 0) ppcond = 0; 601*f4a2713aSLionel Sambuc 602*f4a2713aSLionel Sambuc assert(PP && "No preprocessor set yet!"); 603*f4a2713aSLionel Sambuc return new PTHLexer(*PP, FID, data, ppcond, *this); 604*f4a2713aSLionel Sambuc } 605*f4a2713aSLionel Sambuc 606*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 607*f4a2713aSLionel Sambuc // 'stat' caching. 608*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===// 609*f4a2713aSLionel Sambuc 610*f4a2713aSLionel Sambuc namespace { 611*f4a2713aSLionel Sambuc class PTHStatData { 612*f4a2713aSLionel Sambuc public: 613*f4a2713aSLionel Sambuc const bool HasData; 614*f4a2713aSLionel Sambuc uint64_t Size; 615*f4a2713aSLionel Sambuc time_t ModTime; 616*f4a2713aSLionel Sambuc llvm::sys::fs::UniqueID UniqueID; 617*f4a2713aSLionel Sambuc bool IsDirectory; 618*f4a2713aSLionel Sambuc 619*f4a2713aSLionel Sambuc PTHStatData(uint64_t Size, time_t ModTime, llvm::sys::fs::UniqueID UniqueID, 620*f4a2713aSLionel Sambuc bool IsDirectory) 621*f4a2713aSLionel Sambuc : HasData(true), Size(Size), ModTime(ModTime), UniqueID(UniqueID), 622*f4a2713aSLionel Sambuc IsDirectory(IsDirectory) {} 623*f4a2713aSLionel Sambuc 624*f4a2713aSLionel Sambuc PTHStatData() : HasData(false) {} 625*f4a2713aSLionel Sambuc }; 626*f4a2713aSLionel Sambuc 627*f4a2713aSLionel Sambuc class PTHStatLookupTrait : public PTHFileLookupCommonTrait { 628*f4a2713aSLionel Sambuc public: 629*f4a2713aSLionel Sambuc typedef const char* external_key_type; // const char* 630*f4a2713aSLionel Sambuc typedef PTHStatData data_type; 631*f4a2713aSLionel Sambuc 632*f4a2713aSLionel Sambuc static internal_key_type GetInternalKey(const char *path) { 633*f4a2713aSLionel Sambuc // The key 'kind' doesn't matter here because it is ignored in EqualKey. 634*f4a2713aSLionel Sambuc return std::make_pair((unsigned char) 0x0, path); 635*f4a2713aSLionel Sambuc } 636*f4a2713aSLionel Sambuc 637*f4a2713aSLionel Sambuc static bool EqualKey(internal_key_type a, internal_key_type b) { 638*f4a2713aSLionel Sambuc // When doing 'stat' lookups we don't care about the kind of 'a' and 'b', 639*f4a2713aSLionel Sambuc // just the paths. 640*f4a2713aSLionel Sambuc return strcmp(a.second, b.second) == 0; 641*f4a2713aSLionel Sambuc } 642*f4a2713aSLionel Sambuc 643*f4a2713aSLionel Sambuc static data_type ReadData(const internal_key_type& k, const unsigned char* d, 644*f4a2713aSLionel Sambuc unsigned) { 645*f4a2713aSLionel Sambuc 646*f4a2713aSLionel Sambuc if (k.first /* File or Directory */) { 647*f4a2713aSLionel Sambuc bool IsDirectory = true; 648*f4a2713aSLionel Sambuc if (k.first == 0x1 /* File */) { 649*f4a2713aSLionel Sambuc IsDirectory = false; 650*f4a2713aSLionel Sambuc d += 4 * 2; // Skip the first 2 words. 651*f4a2713aSLionel Sambuc } 652*f4a2713aSLionel Sambuc 653*f4a2713aSLionel Sambuc uint64_t File = ReadUnalignedLE64(d); 654*f4a2713aSLionel Sambuc uint64_t Device = ReadUnalignedLE64(d); 655*f4a2713aSLionel Sambuc llvm::sys::fs::UniqueID UniqueID(File, Device); 656*f4a2713aSLionel Sambuc time_t ModTime = ReadUnalignedLE64(d); 657*f4a2713aSLionel Sambuc uint64_t Size = ReadUnalignedLE64(d); 658*f4a2713aSLionel Sambuc return data_type(Size, ModTime, UniqueID, IsDirectory); 659*f4a2713aSLionel Sambuc } 660*f4a2713aSLionel Sambuc 661*f4a2713aSLionel Sambuc // Negative stat. Don't read anything. 662*f4a2713aSLionel Sambuc return data_type(); 663*f4a2713aSLionel Sambuc } 664*f4a2713aSLionel Sambuc }; 665*f4a2713aSLionel Sambuc 666*f4a2713aSLionel Sambuc class PTHStatCache : public FileSystemStatCache { 667*f4a2713aSLionel Sambuc typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy; 668*f4a2713aSLionel Sambuc CacheTy Cache; 669*f4a2713aSLionel Sambuc 670*f4a2713aSLionel Sambuc public: 671*f4a2713aSLionel Sambuc PTHStatCache(PTHFileLookup &FL) : 672*f4a2713aSLionel Sambuc Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(), 673*f4a2713aSLionel Sambuc FL.getBase()) {} 674*f4a2713aSLionel Sambuc 675*f4a2713aSLionel Sambuc ~PTHStatCache() {} 676*f4a2713aSLionel Sambuc 677*f4a2713aSLionel Sambuc LookupResult getStat(const char *Path, FileData &Data, bool isFile, 678*f4a2713aSLionel Sambuc int *FileDescriptor) { 679*f4a2713aSLionel Sambuc // Do the lookup for the file's data in the PTH file. 680*f4a2713aSLionel Sambuc CacheTy::iterator I = Cache.find(Path); 681*f4a2713aSLionel Sambuc 682*f4a2713aSLionel Sambuc // If we don't get a hit in the PTH file just forward to 'stat'. 683*f4a2713aSLionel Sambuc if (I == Cache.end()) 684*f4a2713aSLionel Sambuc return statChained(Path, Data, isFile, FileDescriptor); 685*f4a2713aSLionel Sambuc 686*f4a2713aSLionel Sambuc const PTHStatData &D = *I; 687*f4a2713aSLionel Sambuc 688*f4a2713aSLionel Sambuc if (!D.HasData) 689*f4a2713aSLionel Sambuc return CacheMissing; 690*f4a2713aSLionel Sambuc 691*f4a2713aSLionel Sambuc Data.Size = D.Size; 692*f4a2713aSLionel Sambuc Data.ModTime = D.ModTime; 693*f4a2713aSLionel Sambuc Data.UniqueID = D.UniqueID; 694*f4a2713aSLionel Sambuc Data.IsDirectory = D.IsDirectory; 695*f4a2713aSLionel Sambuc Data.IsNamedPipe = false; 696*f4a2713aSLionel Sambuc Data.InPCH = true; 697*f4a2713aSLionel Sambuc 698*f4a2713aSLionel Sambuc return CacheExists; 699*f4a2713aSLionel Sambuc } 700*f4a2713aSLionel Sambuc }; 701*f4a2713aSLionel Sambuc } // end anonymous namespace 702*f4a2713aSLionel Sambuc 703*f4a2713aSLionel Sambuc FileSystemStatCache *PTHManager::createStatCache() { 704*f4a2713aSLionel Sambuc return new PTHStatCache(*((PTHFileLookup*) FileLookup)); 705*f4a2713aSLionel Sambuc } 706