zcov: / lib/Lex/PTHLexer.cpp


Files: 1 Branches Taken: 45.9% 79 / 172
Generated: 2010-02-10 01:31 Branches Executed: 75.6% 130 / 172
Line Coverage: 76.3% 212 / 278


Programs: 2 Runs 3018


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

Generated: 2010-02-10 01:31 by zcov