blob: 3b949d0ab40a15c3db36f856a4d9f241f3a02d01 [file] [log] [blame]
Ted Kremenek274b2082008-11-12 21:37:15 +00001//===--- 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
Ted Kremenek0c6a77b2008-12-03 00:38:03 +000014#include "clang/Basic/TokenKinds.h"
15#include "clang/Basic/FileManager.h"
16#include "clang/Basic/IdentifierTable.h"
Douglas Gregor9378ba42009-04-20 07:08:21 +000017#include "clang/Basic/OnDiskHashTable.h"
Daniel Dunbar3574f462009-11-12 02:53:48 +000018#include "clang/Lex/LexDiagnostic.h"
Ted Kremenek274b2082008-11-12 21:37:15 +000019#include "clang/Lex/PTHLexer.h"
20#include "clang/Lex/Preprocessor.h"
Ted Kremenek0c6a77b2008-12-03 00:38:03 +000021#include "clang/Lex/PTHManager.h"
22#include "clang/Lex/Token.h"
23#include "clang/Lex/Preprocessor.h"
Ted Kremenek0c6a77b2008-12-03 00:38:03 +000024#include "llvm/ADT/OwningPtr.h"
Daniel Dunbar2596e422009-10-17 23:52:28 +000025#include "llvm/ADT/StringExtras.h"
26#include "llvm/ADT/StringMap.h"
Chris Lattner6f78c3b2009-01-22 23:50:07 +000027#include "llvm/Support/MemoryBuffer.h"
Ted Kremenek337edcd2009-02-12 03:26:59 +000028#include <sys/stat.h>
Ted Kremenek274b2082008-11-12 21:37:15 +000029using namespace clang;
Douglas Gregor9378ba42009-04-20 07:08:21 +000030using namespace clang::io;
Ted Kremenek274b2082008-11-12 21:37:15 +000031
Ted Kremenek7b78b7c2009-01-19 23:13:15 +000032#define DISK_TOKEN_SIZE (1+1+2+4+4)
Ted Kremenek268ee702008-12-12 18:34:08 +000033
Ted Kremenek0c6a77b2008-12-03 00:38:03 +000034//===----------------------------------------------------------------------===//
Ted Kremeneke5680f32008-12-23 01:30:52 +000035// PTHLexer methods.
36//===----------------------------------------------------------------------===//
37
Chris Lattnerda9d61c2009-01-18 01:57:14 +000038PTHLexer::PTHLexer(Preprocessor &PP, FileID FID, const unsigned char *D,
Ted Kremenek277faca2009-01-27 00:01:05 +000039 const unsigned char *ppcond, PTHManager &PM)
Chris Lattner2b2453a2009-01-17 06:22:33 +000040 : PreprocessorLexer(&PP, FID), TokBuf(D), CurPtr(D), LastHashTokPtr(0),
Ted Kremenek277faca2009-01-27 00:01:05 +000041 PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM) {
Mike Stump1eb44332009-09-09 15:08:12 +000042
Chris Lattner2b2453a2009-01-17 06:22:33 +000043 FileStartLoc = PP.getSourceManager().getLocForStartOfFile(FID);
Ted Kremenek5f074262009-01-09 22:05:30 +000044}
Ted Kremeneke5680f32008-12-23 01:30:52 +000045
46void PTHLexer::Lex(Token& Tok) {
47LexNextToken:
Ted Kremeneke5680f32008-12-23 01:30:52 +000048
Ted Kremenek866bdf72008-12-23 02:30:15 +000049 //===--------------------------------------==//
50 // Read the raw token data.
51 //===--------------------------------------==//
Mike Stump1eb44332009-09-09 15:08:12 +000052
Ted Kremenek866bdf72008-12-23 02:30:15 +000053 // Shadow CurPtr into an automatic variable.
Mike Stump1eb44332009-09-09 15:08:12 +000054 const unsigned char *CurPtrShadow = CurPtr;
Ted Kremenek866bdf72008-12-23 02:30:15 +000055
Chris Lattner1b5285e2009-01-18 02:10:31 +000056 // Read in the data for the token.
Chris Lattner5ff43172009-01-22 19:48:26 +000057 unsigned Word0 = ReadLE32(CurPtrShadow);
58 uint32_t IdentifierID = ReadLE32(CurPtrShadow);
59 uint32_t FileOffset = ReadLE32(CurPtrShadow);
Mike Stump1eb44332009-09-09 15:08:12 +000060
Ted Kremenek7b78b7c2009-01-19 23:13:15 +000061 tok::TokenKind TKind = (tok::TokenKind) (Word0 & 0xFF);
62 Token::TokenFlags TFlags = (Token::TokenFlags) ((Word0 >> 8) & 0xFF);
Chris Lattneraff6ef82009-01-21 07:21:56 +000063 uint32_t Len = Word0 >> 16;
Ted Kremenek7b78b7c2009-01-19 23:13:15 +000064
Chris Lattneraff6ef82009-01-21 07:21:56 +000065 CurPtr = CurPtrShadow;
Mike Stump1eb44332009-09-09 15:08:12 +000066
Ted Kremenek866bdf72008-12-23 02:30:15 +000067 //===--------------------------------------==//
68 // Construct the token itself.
69 //===--------------------------------------==//
Mike Stump1eb44332009-09-09 15:08:12 +000070
Ted Kremenek866bdf72008-12-23 02:30:15 +000071 Tok.startToken();
Chris Lattner898a0bb2009-01-18 02:34:01 +000072 Tok.setKind(TKind);
73 Tok.setFlag(TFlags);
Ted Kremenek59d08cb2008-12-23 19:24:24 +000074 assert(!LexingRawMode);
Chris Lattner2b2453a2009-01-17 06:22:33 +000075 Tok.setLocation(FileStartLoc.getFileLocWithOffset(FileOffset));
Ted Kremenek866bdf72008-12-23 02:30:15 +000076 Tok.setLength(Len);
77
Chris Lattnerd0a69692009-01-21 07:50:06 +000078 // Handle identifiers.
Ted Kremenek277faca2009-01-27 00:01:05 +000079 if (Tok.isLiteral()) {
80 Tok.setLiteralData((const char*) (PTHMgr.SpellingBase + IdentifierID));
81 }
82 else if (IdentifierID) {
Chris Lattnerd0a69692009-01-21 07:50:06 +000083 MIOpt.ReadToken();
84 IdentifierInfo *II = PTHMgr.GetIdentifierInfo(IdentifierID-1);
Mike Stump1eb44332009-09-09 15:08:12 +000085
Chris Lattnerd0a69692009-01-21 07:50:06 +000086 Tok.setIdentifierInfo(II);
Mike Stump1eb44332009-09-09 15:08:12 +000087
Chris Lattner863c4862009-01-23 18:35:48 +000088 // Change the kind of this identifier to the appropriate token kind, e.g.
89 // turning "for" into a keyword.
90 Tok.setKind(II->getTokenID());
Mike Stump1eb44332009-09-09 15:08:12 +000091
Chris Lattnerd0a69692009-01-21 07:50:06 +000092 if (II->isHandleIdentifierCase())
93 PP->HandleIdentifier(Tok);
94 return;
95 }
Mike Stump1eb44332009-09-09 15:08:12 +000096
Ted Kremenek866bdf72008-12-23 02:30:15 +000097 //===--------------------------------------==//
98 // Process the token.
99 //===--------------------------------------==//
Chris Lattner898a0bb2009-01-18 02:34:01 +0000100 if (TKind == tok::eof) {
Ted Kremeneke5680f32008-12-23 01:30:52 +0000101 // Save the end-of-file token.
102 EofToken = Tok;
Mike Stump1eb44332009-09-09 15:08:12 +0000103
Ted Kremeneke5680f32008-12-23 01:30:52 +0000104 Preprocessor *PPCache = PP;
Mike Stump1eb44332009-09-09 15:08:12 +0000105
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000106 assert(!ParsingPreprocessorDirective);
107 assert(!LexingRawMode);
Mike Stump1eb44332009-09-09 15:08:12 +0000108
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000109 // FIXME: Issue diagnostics similar to Lexer.
110 if (PP->HandleEndOfFile(Tok, false))
Ted Kremeneke5680f32008-12-23 01:30:52 +0000111 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000112
Ted Kremeneke5680f32008-12-23 01:30:52 +0000113 assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
114 return PPCache->Lex(Tok);
115 }
Mike Stump1eb44332009-09-09 15:08:12 +0000116
Chris Lattner898a0bb2009-01-18 02:34:01 +0000117 if (TKind == tok::hash && Tok.isAtStartOfLine()) {
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000118 LastHashTokPtr = CurPtr - DISK_TOKEN_SIZE;
119 assert(!LexingRawMode);
120 PP->HandleDirective(Tok);
Mike Stump1eb44332009-09-09 15:08:12 +0000121
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000122 if (PP->isCurrentLexer(this))
123 goto LexNextToken;
Mike Stump1eb44332009-09-09 15:08:12 +0000124
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000125 return PP->Lex(Tok);
126 }
Mike Stump1eb44332009-09-09 15:08:12 +0000127
Chris Lattner898a0bb2009-01-18 02:34:01 +0000128 if (TKind == tok::eom) {
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000129 assert(ParsingPreprocessorDirective);
Ted Kremeneke5680f32008-12-23 01:30:52 +0000130 ParsingPreprocessorDirective = false;
131 return;
132 }
Ted Kremeneke5680f32008-12-23 01:30:52 +0000133
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000134 MIOpt.ReadToken();
Ted Kremeneke5680f32008-12-23 01:30:52 +0000135}
136
137// FIXME: We can just grab the last token instead of storing a copy
138// into EofToken.
Ted Kremenek59d08cb2008-12-23 19:24:24 +0000139void PTHLexer::getEOF(Token& Tok) {
Ted Kremenekdefb7092009-01-09 00:36:11 +0000140 assert(EofToken.is(tok::eof));
Ted Kremeneke5680f32008-12-23 01:30:52 +0000141 Tok = EofToken;
142}
143
144void PTHLexer::DiscardToEndOfLine() {
145 assert(ParsingPreprocessorDirective && ParsingFilename == false &&
146 "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 ParsingPreprocessorDirective = false;
Mike Stump1eb44332009-09-09 15:08:12 +0000151
Ted Kremeneke5680f32008-12-23 01:30:52 +0000152 // 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.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000155 const unsigned char* p = CurPtr;
Ted Kremeneke5680f32008-12-23 01:30:52 +0000156 while (1) {
157 // Read the token kind. Are we at the end of the file?
158 tok::TokenKind x = (tok::TokenKind) (uint8_t) *p;
159 if (x == tok::eof) break;
Mike Stump1eb44332009-09-09 15:08:12 +0000160
Ted Kremeneke5680f32008-12-23 01:30:52 +0000161 // Read the token flags. Are we at the start of the next line?
162 Token::TokenFlags y = (Token::TokenFlags) (uint8_t) p[1];
163 if (y & Token::StartOfLine) break;
164
165 // Skip to the next token.
166 p += DISK_TOKEN_SIZE;
167 }
Mike Stump1eb44332009-09-09 15:08:12 +0000168
Ted Kremeneke5680f32008-12-23 01:30:52 +0000169 CurPtr = p;
170}
171
Ted Kremenek268ee702008-12-12 18:34:08 +0000172/// SkipBlock - Used by Preprocessor to skip the current conditional block.
173bool PTHLexer::SkipBlock() {
174 assert(CurPPCondPtr && "No cached PP conditional information.");
175 assert(LastHashTokPtr && "No known '#' token.");
Mike Stump1eb44332009-09-09 15:08:12 +0000176
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000177 const unsigned char* HashEntryI = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000178 uint32_t Offset;
Ted Kremenek268ee702008-12-12 18:34:08 +0000179 uint32_t TableIdx;
Mike Stump1eb44332009-09-09 15:08:12 +0000180
Ted Kremenek268ee702008-12-12 18:34:08 +0000181 do {
Ted Kremenek41a26602008-12-12 22:05:38 +0000182 // Read the token offset from the side-table.
Chris Lattner5ff43172009-01-22 19:48:26 +0000183 Offset = ReadLE32(CurPPCondPtr);
Mike Stump1eb44332009-09-09 15:08:12 +0000184
185 // Read the target table index from the side-table.
Chris Lattner5ff43172009-01-22 19:48:26 +0000186 TableIdx = ReadLE32(CurPPCondPtr);
Mike Stump1eb44332009-09-09 15:08:12 +0000187
Ted Kremenek41a26602008-12-12 22:05:38 +0000188 // Compute the actual memory address of the '#' token data for this entry.
189 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.
195 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.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000199 const unsigned char* NextPPCondPtr =
200 PPCond + TableIdx*(sizeof(uint32_t)*2);
Ted Kremenek41a26602008-12-12 22:05:38 +0000201 assert(NextPPCondPtr >= CurPPCondPtr);
202 // Read where we should jump to.
Chris Lattner5ff43172009-01-22 19:48:26 +0000203 uint32_t TmpOffset = ReadLE32(NextPPCondPtr);
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000204 const unsigned char* HashEntryJ = TokBuf + TmpOffset;
Mike Stump1eb44332009-09-09 15:08:12 +0000205
Ted Kremenek41a26602008-12-12 22:05:38 +0000206 if (HashEntryJ <= LastHashTokPtr) {
207 // Jump directly to the next entry in the side table.
208 HashEntryI = HashEntryJ;
209 Offset = TmpOffset;
Chris Lattner5ff43172009-01-22 19:48:26 +0000210 TableIdx = ReadLE32(NextPPCondPtr);
Ted Kremenek41a26602008-12-12 22:05:38 +0000211 CurPPCondPtr = NextPPCondPtr;
212 }
213 }
Ted Kremenek268ee702008-12-12 18:34:08 +0000214 }
Mike Stump1eb44332009-09-09 15:08:12 +0000215 while (HashEntryI < LastHashTokPtr);
Ted Kremenek41a26602008-12-12 22:05:38 +0000216 assert(HashEntryI == LastHashTokPtr && "No PP-cond entry found for '#'");
Ted Kremenek268ee702008-12-12 18:34:08 +0000217 assert(TableIdx && "No jumping from #endifs.");
Mike Stump1eb44332009-09-09 15:08:12 +0000218
Ted Kremenek268ee702008-12-12 18:34:08 +0000219 // Update our side-table iterator.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000220 const unsigned char* NextPPCondPtr = PPCond + TableIdx*(sizeof(uint32_t)*2);
Ted Kremenek268ee702008-12-12 18:34:08 +0000221 assert(NextPPCondPtr >= CurPPCondPtr);
222 CurPPCondPtr = NextPPCondPtr;
Mike Stump1eb44332009-09-09 15:08:12 +0000223
Ted Kremenek268ee702008-12-12 18:34:08 +0000224 // Read where we should jump to.
Chris Lattner5ff43172009-01-22 19:48:26 +0000225 HashEntryI = TokBuf + ReadLE32(NextPPCondPtr);
226 uint32_t NextIdx = ReadLE32(NextPPCondPtr);
Mike Stump1eb44332009-09-09 15:08:12 +0000227
Ted Kremenek268ee702008-12-12 18:34:08 +0000228 // By construction NextIdx will be zero if this is a #endif. This is useful
229 // to know to obviate lexing another token.
230 bool isEndif = NextIdx == 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000231
Ted Kremenek268ee702008-12-12 18:34:08 +0000232 // 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.
Mike Stump1eb44332009-09-09 15:08:12 +0000240
Ted Kremenek41a26602008-12-12 22:05:38 +0000241 if (CurPtr > HashEntryI) {
242 assert(CurPtr == HashEntryI + DISK_TOKEN_SIZE);
Ted Kremenek268ee702008-12-12 18:34:08 +0000243 // Did we reach a #endif? If so, go ahead and consume that token as well.
244 if (isEndif)
Ted Kremeneke5680f32008-12-23 01:30:52 +0000245 CurPtr += DISK_TOKEN_SIZE*2;
Ted Kremenek268ee702008-12-12 18:34:08 +0000246 else
Ted Kremenek41a26602008-12-12 22:05:38 +0000247 LastHashTokPtr = HashEntryI;
Mike Stump1eb44332009-09-09 15:08:12 +0000248
Ted Kremenek268ee702008-12-12 18:34:08 +0000249 return isEndif;
250 }
251
252 // Otherwise, we need to advance. Update CurPtr to point to the '#' token.
Ted Kremenek41a26602008-12-12 22:05:38 +0000253 CurPtr = HashEntryI;
Mike Stump1eb44332009-09-09 15:08:12 +0000254
Ted Kremenek268ee702008-12-12 18:34:08 +0000255 // Update the location of the last observed '#'. This is useful if we
256 // are skipping multiple blocks.
257 LastHashTokPtr = CurPtr;
Ted Kremenek268ee702008-12-12 18:34:08 +0000258
Ted Kremeneke5680f32008-12-23 01:30:52 +0000259 // Skip the '#' token.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000260 assert(((tok::TokenKind)*CurPtr) == tok::hash);
Ted Kremeneke5680f32008-12-23 01:30:52 +0000261 CurPtr += DISK_TOKEN_SIZE;
Mike Stump1eb44332009-09-09 15:08:12 +0000262
Ted Kremenek268ee702008-12-12 18:34:08 +0000263 // Did we reach a #endif? If so, go ahead and consume that token as well.
Ted Kremeneke5680f32008-12-23 01:30:52 +0000264 if (isEndif) { CurPtr += DISK_TOKEN_SIZE*2; }
Ted Kremenek268ee702008-12-12 18:34:08 +0000265
266 return isEndif;
267}
268
Ted Kremenek30a12ec2008-12-17 23:36:32 +0000269SourceLocation PTHLexer::getSourceLocation() {
Chris Lattner1b5285e2009-01-18 02:10:31 +0000270 // 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
Ted Kremenek30a12ec2008-12-17 23:36:32 +0000272 // 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.
Ted Kremenekb248d532009-01-21 22:41:38 +0000275 const unsigned char *OffsetPtr = CurPtr + (DISK_TOKEN_SIZE - 4);
Chris Lattner5ff43172009-01-22 19:48:26 +0000276 uint32_t Offset = ReadLE32(OffsetPtr);
Chris Lattner1b5285e2009-01-18 02:10:31 +0000277 return FileStartLoc.getFileLocWithOffset(Offset);
Ted Kremenek30a12ec2008-12-17 23:36:32 +0000278}
279
Ted Kremenek5f074262009-01-09 22:05:30 +0000280//===----------------------------------------------------------------------===//
Ted Kremenekd8c02922009-02-10 22:16:22 +0000281// PTH file lookup: map from strings to file data.
282//===----------------------------------------------------------------------===//
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000283
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.
287namespace {
Benjamin Kramer85b45212009-11-28 19:45:26 +0000288class PTHFileData {
Ted Kremenekd8c02922009-02-10 22:16:22 +0000289 const uint32_t TokenOff;
290 const uint32_t PPCondOff;
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000291public:
Ted Kremenekd8c02922009-02-10 22:16:22 +0000292 PTHFileData(uint32_t tokenOff, uint32_t ppCondOff)
293 : TokenOff(tokenOff), PPCondOff(ppCondOff) {}
Mike Stump1eb44332009-09-09 15:08:12 +0000294
295 uint32_t getTokenOffset() const { return TokenOff; }
296 uint32_t getPPCondOffset() const { return PPCondOff; }
Ted Kremenekd8c02922009-02-10 22:16:22 +0000297};
Mike Stump1eb44332009-09-09 15:08:12 +0000298
299
Benjamin Kramer85b45212009-11-28 19:45:26 +0000300class PTHFileLookupCommonTrait {
Ted Kremenekd8c02922009-02-10 22:16:22 +0000301public:
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000302 typedef std::pair<unsigned char, const char*> internal_key_type;
303
304 static unsigned ComputeHash(internal_key_type x) {
Daniel Dunbar2596e422009-10-17 23:52:28 +0000305 return llvm::HashString(x.second);
Ted Kremenekd8c02922009-02-10 22:16:22 +0000306 }
Mike Stump1eb44332009-09-09 15:08:12 +0000307
Ted Kremenekd8c02922009-02-10 22:16:22 +0000308 static std::pair<unsigned, unsigned>
309 ReadKeyDataLength(const unsigned char*& d) {
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000310 unsigned keyLen = (unsigned) ReadUnalignedLE16(d);
311 unsigned dataLen = (unsigned) *(d++);
312 return std::make_pair(keyLen, dataLen);
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000313 }
Mike Stump1eb44332009-09-09 15:08:12 +0000314
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000315 static internal_key_type ReadKey(const unsigned char* d, unsigned) {
316 unsigned char k = *(d++); // Read the entry kind.
317 return std::make_pair(k, (const char*) d);
Ted Kremenekd8c02922009-02-10 22:16:22 +0000318 }
Ted Kremenek337edcd2009-02-12 03:26:59 +0000319};
Mike Stump1eb44332009-09-09 15:08:12 +0000320
Benjamin Kramer85b45212009-11-28 19:45:26 +0000321class PTHFileLookupTrait : public PTHFileLookupCommonTrait {
Ted Kremenek337edcd2009-02-12 03:26:59 +0000322public:
323 typedef const FileEntry* external_key_type;
324 typedef PTHFileData data_type;
Mike Stump1eb44332009-09-09 15:08:12 +0000325
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000326 static internal_key_type GetInternalKey(const FileEntry* FE) {
327 return std::make_pair((unsigned char) 0x1, FE->getName());
Ted Kremenek337edcd2009-02-12 03:26:59 +0000328 }
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000329
330 static bool EqualKey(internal_key_type a, internal_key_type b) {
331 return a.first == b.first && strcmp(a.second, b.second) == 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000332 }
333
334 static PTHFileData ReadData(const internal_key_type& k,
335 const unsigned char* d, unsigned) {
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000336 assert(k.first == 0x1 && "Only file lookups can match!");
Ted Kremenekd8c02922009-02-10 22:16:22 +0000337 uint32_t x = ::ReadUnalignedLE32(d);
338 uint32_t y = ::ReadUnalignedLE32(d);
Mike Stump1eb44332009-09-09 15:08:12 +0000339 return PTHFileData(x, y);
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000340 }
341};
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000342
Benjamin Kramer85b45212009-11-28 19:45:26 +0000343class PTHStringLookupTrait {
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000344public:
Mike Stump1eb44332009-09-09 15:08:12 +0000345 typedef uint32_t
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000346 data_type;
347
348 typedef const std::pair<const char*, unsigned>
349 external_key_type;
350
351 typedef external_key_type internal_key_type;
Mike Stump1eb44332009-09-09 15:08:12 +0000352
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000353 static bool EqualKey(const internal_key_type& a,
354 const internal_key_type& b) {
355 return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0
356 : false;
357 }
Mike Stump1eb44332009-09-09 15:08:12 +0000358
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000359 static unsigned ComputeHash(const internal_key_type& a) {
Daniel Dunbar2596e422009-10-17 23:52:28 +0000360 return llvm::HashString(llvm::StringRef(a.first, a.second));
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000361 }
Mike Stump1eb44332009-09-09 15:08:12 +0000362
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000363 // This hopefully will just get inlined and removed by the optimizer.
364 static const internal_key_type&
365 GetInternalKey(const external_key_type& x) { return x; }
Mike Stump1eb44332009-09-09 15:08:12 +0000366
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000367 static std::pair<unsigned, unsigned>
368 ReadKeyDataLength(const unsigned char*& d) {
369 return std::make_pair((unsigned) ReadUnalignedLE16(d), sizeof(uint32_t));
370 }
Mike Stump1eb44332009-09-09 15:08:12 +0000371
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000372 static std::pair<const char*, unsigned>
373 ReadKey(const unsigned char* d, unsigned n) {
374 assert(n >= 2 && d[n-1] == '\0');
375 return std::make_pair((const char*) d, n-1);
376 }
Mike Stump1eb44332009-09-09 15:08:12 +0000377
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000378 static uint32_t ReadData(const internal_key_type& k, const unsigned char* d,
379 unsigned) {
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000380 return ::ReadUnalignedLE32(d);
381 }
382};
Mike Stump1eb44332009-09-09 15:08:12 +0000383
384} // end anonymous namespace
Ted Kremenekd8c02922009-02-10 22:16:22 +0000385
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000386typedef OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
387typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000388
389//===----------------------------------------------------------------------===//
390// PTHManager methods.
391//===----------------------------------------------------------------------===//
392
393PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000394 const unsigned char* idDataTable,
Mike Stump1eb44332009-09-09 15:08:12 +0000395 IdentifierInfo** perIDCache,
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000396 void* stringIdLookup, unsigned numIds,
Ted Kremenek68228632009-03-19 22:19:30 +0000397 const unsigned char* spellingBase,
398 const char* originalSourceFile)
Ted Kremenek6183e482008-12-03 01:16:39 +0000399: Buf(buf), PerIDCache(perIDCache), FileLookup(fileLookup),
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000400 IdDataTable(idDataTable), StringIdLookup(stringIdLookup),
Ted Kremenek68228632009-03-19 22:19:30 +0000401 NumIds(numIds), PP(0), SpellingBase(spellingBase),
402 OriginalSourceFile(originalSourceFile) {}
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000403
404PTHManager::~PTHManager() {
405 delete Buf;
406 delete (PTHFileLookup*) FileLookup;
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000407 delete (PTHStringIdLookup*) StringIdLookup;
Ted Kremenek0e50b6e2008-12-04 22:47:11 +0000408 free(PerIDCache);
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000409}
410
Daniel Dunbar3574f462009-11-12 02:53:48 +0000411static void InvalidPTH(Diagnostic &Diags, const char *Msg) {
412 Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, Msg));
Ted Kremenek26555b12009-01-28 21:02:43 +0000413}
414
Daniel Dunbar3574f462009-11-12 02:53:48 +0000415PTHManager* PTHManager::Create(const std::string& file, Diagnostic &Diags) {
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000416 // Memory map the PTH file.
417 llvm::OwningPtr<llvm::MemoryBuffer>
418 File(llvm::MemoryBuffer::getFile(file.c_str()));
Mike Stump1eb44332009-09-09 15:08:12 +0000419
Ted Kremenek8a6aec62009-01-28 20:49:33 +0000420 if (!File) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000421 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000422 return 0;
Ted Kremenek8a6aec62009-01-28 20:49:33 +0000423 }
Mike Stump1eb44332009-09-09 15:08:12 +0000424
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000425 // Get the buffer ranges and check if there are at least three 32-bit
426 // words at the end of the file.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000427 const unsigned char* BufBeg = (unsigned char*)File->getBufferStart();
428 const unsigned char* BufEnd = (unsigned char*)File->getBufferEnd();
Ted Kremeneke1b64982009-01-26 21:43:14 +0000429
430 // Check the prologue of the file.
Ted Kremenek4adc71a2009-01-26 22:16:12 +0000431 if ((BufEnd - BufBeg) < (signed) (sizeof("cfe-pth") + 3 + 4) ||
Ted Kremenek26555b12009-01-28 21:02:43 +0000432 memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth") - 1) != 0) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000433 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremeneke1b64982009-01-26 21:43:14 +0000434 return 0;
Ted Kremenek26555b12009-01-28 21:02:43 +0000435 }
Mike Stump1eb44332009-09-09 15:08:12 +0000436
Ted Kremenek67d15052009-01-26 21:50:21 +0000437 // Read the PTH version.
Ted Kremeneke1b64982009-01-26 21:43:14 +0000438 const unsigned char *p = BufBeg + (sizeof("cfe-pth") - 1);
Ted Kremenek67d15052009-01-26 21:50:21 +0000439 unsigned Version = ReadLE32(p);
Mike Stump1eb44332009-09-09 15:08:12 +0000440
Daniel Dunbar3574f462009-11-12 02:53:48 +0000441 if (Version < PTHManager::Version) {
442 InvalidPTH(Diags,
Mike Stump1eb44332009-09-09 15:08:12 +0000443 Version < PTHManager::Version
Ted Kremenek26555b12009-01-28 21:02:43 +0000444 ? "PTH file uses an older PTH format that is no longer supported"
445 : "PTH file uses a newer PTH format that cannot be read");
Ted Kremenek67d15052009-01-26 21:50:21 +0000446 return 0;
Ted Kremenek26555b12009-01-28 21:02:43 +0000447 }
Ted Kremenek67d15052009-01-26 21:50:21 +0000448
Mike Stump1eb44332009-09-09 15:08:12 +0000449 // Compute the address of the index table at the end of the PTH file.
Ted Kremeneka4bd8eb2009-02-11 23:34:32 +0000450 const unsigned char *PrologueOffset = p;
Mike Stump1eb44332009-09-09 15:08:12 +0000451
Ted Kremeneka4bd8eb2009-02-11 23:34:32 +0000452 if (PrologueOffset >= BufEnd) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000453 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremeneke1b64982009-01-26 21:43:14 +0000454 return 0;
Ted Kremenek26555b12009-01-28 21:02:43 +0000455 }
Mike Stump1eb44332009-09-09 15:08:12 +0000456
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000457 // Construct the file lookup table. This will be used for mapping from
458 // FileEntry*'s to cached tokens.
Ted Kremeneka4bd8eb2009-02-11 23:34:32 +0000459 const unsigned char* FileTableOffset = PrologueOffset + sizeof(uint32_t)*2;
Chris Lattner5ff43172009-01-22 19:48:26 +0000460 const unsigned char* FileTable = BufBeg + ReadLE32(FileTableOffset);
Mike Stump1eb44332009-09-09 15:08:12 +0000461
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000462 if (!(FileTable > BufBeg && FileTable < BufEnd)) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000463 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000464 return 0; // FIXME: Proper error diagnostic?
465 }
Mike Stump1eb44332009-09-09 15:08:12 +0000466
Ted Kremenekd8c02922009-02-10 22:16:22 +0000467 llvm::OwningPtr<PTHFileLookup> FL(PTHFileLookup::Create(FileTable, BufBeg));
Mike Stump1eb44332009-09-09 15:08:12 +0000468
Ted Kremenek1d201972009-03-20 17:54:25 +0000469 // Warn if the PTH file is empty. We still want to create a PTHManager
470 // as the PTH could be used with -include-pth.
471 if (FL->isEmpty())
Daniel Dunbar3574f462009-11-12 02:53:48 +0000472 InvalidPTH(Diags, "PTH file contains no cached source data");
Mike Stump1eb44332009-09-09 15:08:12 +0000473
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000474 // Get the location of the table mapping from persistent ids to the
475 // data needed to reconstruct identifiers.
Ted Kremeneka4bd8eb2009-02-11 23:34:32 +0000476 const unsigned char* IDTableOffset = PrologueOffset + sizeof(uint32_t)*0;
Chris Lattner5ff43172009-01-22 19:48:26 +0000477 const unsigned char* IData = BufBeg + ReadLE32(IDTableOffset);
Mike Stump1eb44332009-09-09 15:08:12 +0000478
Ted Kremenekcdd8f212009-01-21 07:34:28 +0000479 if (!(IData >= BufBeg && IData < BufEnd)) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000480 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremenek26555b12009-01-28 21:02:43 +0000481 return 0;
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000482 }
Mike Stump1eb44332009-09-09 15:08:12 +0000483
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000484 // Get the location of the hashtable mapping between strings and
485 // persistent IDs.
Ted Kremeneka4bd8eb2009-02-11 23:34:32 +0000486 const unsigned char* StringIdTableOffset = PrologueOffset + sizeof(uint32_t)*1;
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000487 const unsigned char* StringIdTable = BufBeg + ReadLE32(StringIdTableOffset);
488 if (!(StringIdTable >= BufBeg && StringIdTable < BufEnd)) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000489 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremenek26555b12009-01-28 21:02:43 +0000490 return 0;
Ted Kremenek72b1b152009-01-15 18:47:46 +0000491 }
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000492
493 llvm::OwningPtr<PTHStringIdLookup> SL(PTHStringIdLookup::Create(StringIdTable,
494 BufBeg));
Mike Stump1eb44332009-09-09 15:08:12 +0000495
Ted Kremenek277faca2009-01-27 00:01:05 +0000496 // Get the location of the spelling cache.
Ted Kremeneka4bd8eb2009-02-11 23:34:32 +0000497 const unsigned char* spellingBaseOffset = PrologueOffset + sizeof(uint32_t)*3;
Ted Kremenek277faca2009-01-27 00:01:05 +0000498 const unsigned char* spellingBase = BufBeg + ReadLE32(spellingBaseOffset);
499 if (!(spellingBase >= BufBeg && spellingBase < BufEnd)) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000500 Diags.Report(diag::err_invalid_pth_file) << file;
Ted Kremenek277faca2009-01-27 00:01:05 +0000501 return 0;
502 }
Mike Stump1eb44332009-09-09 15:08:12 +0000503
Ted Kremenek6183e482008-12-03 01:16:39 +0000504 // Get the number of IdentifierInfos and pre-allocate the identifier cache.
Chris Lattner5ff43172009-01-22 19:48:26 +0000505 uint32_t NumIds = ReadLE32(IData);
Mike Stump1eb44332009-09-09 15:08:12 +0000506
Ted Kremenek6183e482008-12-03 01:16:39 +0000507 // 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.
Ted Kremenekcdd8f212009-01-21 07:34:28 +0000510 IdentifierInfo** PerIDCache = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000511
Ted Kremenekcdd8f212009-01-21 07:34:28 +0000512 if (NumIds) {
Mike Stump1eb44332009-09-09 15:08:12 +0000513 PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache));
Ted Kremenekcdd8f212009-01-21 07:34:28 +0000514 if (!PerIDCache) {
Daniel Dunbar3574f462009-11-12 02:53:48 +0000515 InvalidPTH(Diags, "Could not allocate memory for processing PTH file");
Ted Kremenekcdd8f212009-01-21 07:34:28 +0000516 return 0;
517 }
Ted Kremenek6183e482008-12-03 01:16:39 +0000518 }
Ted Kremenekcdd8f212009-01-21 07:34:28 +0000519
Ted Kremenek68228632009-03-19 22:19:30 +0000520 // Compute the address of the original source file.
521 const unsigned char* originalSourceBase = PrologueOffset + sizeof(uint32_t)*4;
522 unsigned len = ReadUnalignedLE16(originalSourceBase);
Mike Stump1eb44332009-09-09 15:08:12 +0000523 if (!len) originalSourceBase = 0;
524
Ted Kremenek72b1b152009-01-15 18:47:46 +0000525 // Create the new PTHManager.
526 return new PTHManager(File.take(), FL.take(), IData, PerIDCache,
Ted Kremenek68228632009-03-19 22:19:30 +0000527 SL.take(), NumIds, spellingBase,
528 (const char*) originalSourceBase);
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000529}
Ted Kremenek68228632009-03-19 22:19:30 +0000530
Chris Lattner77ecb3a2009-01-18 02:57:21 +0000531IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) {
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000532 // Look in the PTH file for the string data for the IdentifierInfo object.
Chris Lattner77ecb3a2009-01-18 02:57:21 +0000533 const unsigned char* TableEntry = IdDataTable + sizeof(uint32_t)*PersistentID;
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000534 const unsigned char* IDData =
Chris Lattner5ff43172009-01-22 19:48:26 +0000535 (const unsigned char*)Buf->getBufferStart() + ReadLE32(TableEntry);
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000536 assert(IDData < (const unsigned char*)Buf->getBufferEnd());
Mike Stump1eb44332009-09-09 15:08:12 +0000537
Ted Kremenek72b1b152009-01-15 18:47:46 +0000538 // Allocate the object.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000539 std::pair<IdentifierInfo,const unsigned char*> *Mem =
540 Alloc.Allocate<std::pair<IdentifierInfo,const unsigned char*> >();
Ted Kremenek72b1b152009-01-15 18:47:46 +0000541
542 Mem->second = IDData;
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000543 assert(IDData[0] != '\0');
Ted Kremenekea9c26b2009-01-20 23:28:34 +0000544 IdentifierInfo *II = new ((void*) Mem) IdentifierInfo();
Mike Stump1eb44332009-09-09 15:08:12 +0000545
Ted Kremenek72b1b152009-01-15 18:47:46 +0000546 // Store the new IdentifierInfo in the cache.
Chris Lattner77ecb3a2009-01-18 02:57:21 +0000547 PerIDCache[PersistentID] = II;
Daniel Dunbare013d682009-10-18 20:26:12 +0000548 assert(II->getNameStart() && II->getNameStart()[0] != '\0');
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000549 return II;
550}
551
Kovarththanan Rajaratnam700030e2010-03-12 08:23:34 +0000552IdentifierInfo* PTHManager::get(llvm::StringRef Name) {
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000553 PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup);
554 // Double check our assumption that the last character isn't '\0'.
Kovarththanan Rajaratnam700030e2010-03-12 08:23:34 +0000555 assert(Name.empty() || Name.data()[Name.size()-1] != '\0');
556 PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(),
557 Name.size()));
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000558 if (I == SL.end()) // No identifier found?
559 return 0;
Ted Kremenek72b1b152009-01-15 18:47:46 +0000560
Ted Kremenek7e3a0042009-02-11 21:29:16 +0000561 // Match found. Return the identifier!
562 assert(*I > 0);
563 return GetIdentifierInfo(*I-1);
564}
Ted Kremenek72b1b152009-01-15 18:47:46 +0000565
Chris Lattnerf056d922009-01-17 08:06:50 +0000566PTHLexer *PTHManager::CreateLexer(FileID FID) {
567 const FileEntry *FE = PP->getSourceManager().getFileEntryForID(FID);
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000568 if (!FE)
569 return 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000570
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000571 // 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.
Ted Kremenekd8c02922009-02-10 22:16:22 +0000574 PTHFileLookup& PFL = *((PTHFileLookup*)FileLookup);
575 PTHFileLookup::iterator I = PFL.find(FE);
Mike Stump1eb44332009-09-09 15:08:12 +0000576
Ted Kremenekd8c02922009-02-10 22:16:22 +0000577 if (I == PFL.end()) // No tokens available?
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000578 return 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000579
580 const PTHFileData& FileData = *I;
581
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000582 const unsigned char *BufStart = (const unsigned char *)Buf->getBufferStart();
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000583 // Compute the offset of the token data within the buffer.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000584 const unsigned char* data = BufStart + FileData.getTokenOffset();
Ted Kremenek268ee702008-12-12 18:34:08 +0000585
586 // Get the location of pp-conditional table.
Chris Lattnerda9d61c2009-01-18 01:57:14 +0000587 const unsigned char* ppcond = BufStart + FileData.getPPCondOffset();
Chris Lattner5ff43172009-01-22 19:48:26 +0000588 uint32_t Len = ReadLE32(ppcond);
Chris Lattner1b5285e2009-01-18 02:10:31 +0000589 if (Len == 0) ppcond = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000590
Ted Kremenek72b1b152009-01-15 18:47:46 +0000591 assert(PP && "No preprocessor set yet!");
Mike Stump1eb44332009-09-09 15:08:12 +0000592 return new PTHLexer(*PP, FID, data, ppcond, *this);
Ted Kremenek0c6a77b2008-12-03 00:38:03 +0000593}
Ted Kremenek337edcd2009-02-12 03:26:59 +0000594
595//===----------------------------------------------------------------------===//
596// 'stat' caching.
597//===----------------------------------------------------------------------===//
598
599namespace {
Benjamin Kramer85b45212009-11-28 19:45:26 +0000600class PTHStatData {
Ted Kremenek337edcd2009-02-12 03:26:59 +0000601public:
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000602 const bool hasStat;
Ted Kremenek337edcd2009-02-12 03:26:59 +0000603 const ino_t ino;
604 const dev_t dev;
605 const mode_t mode;
606 const time_t mtime;
607 const off_t size;
Mike Stump1eb44332009-09-09 15:08:12 +0000608
Ted Kremenek337edcd2009-02-12 03:26:59 +0000609 PTHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
Mike Stump1eb44332009-09-09 15:08:12 +0000610 : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {}
611
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000612 PTHStatData()
613 : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {}
Ted Kremenek337edcd2009-02-12 03:26:59 +0000614};
Mike Stump1eb44332009-09-09 15:08:12 +0000615
Benjamin Kramer85b45212009-11-28 19:45:26 +0000616class PTHStatLookupTrait : public PTHFileLookupCommonTrait {
Ted Kremenek337edcd2009-02-12 03:26:59 +0000617public:
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000618 typedef const char* external_key_type; // const char*
Ted Kremenek337edcd2009-02-12 03:26:59 +0000619 typedef PTHStatData data_type;
Mike Stump1eb44332009-09-09 15:08:12 +0000620
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000621 static internal_key_type GetInternalKey(const char *path) {
622 // The key 'kind' doesn't matter here because it is ignored in EqualKey.
623 return std::make_pair((unsigned char) 0x0, path);
624 }
625
626 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 return strcmp(a.second, b.second) == 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000630 }
631
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000632 static data_type ReadData(const internal_key_type& k, const unsigned char* d,
Mike Stump1eb44332009-09-09 15:08:12 +0000633 unsigned) {
634
Ted Kremenekad6ce5c2009-02-13 22:07:44 +0000635 if (k.first /* File or Directory */) {
636 if (k.first == 0x1 /* File */) d += 4 * 2; // Skip the first 2 words.
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000637 ino_t ino = (ino_t) ReadUnalignedLE32(d);
638 dev_t dev = (dev_t) ReadUnalignedLE32(d);
639 mode_t mode = (mode_t) ReadUnalignedLE16(d);
Mike Stump1eb44332009-09-09 15:08:12 +0000640 time_t mtime = (time_t) ReadUnalignedLE64(d);
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000641 return data_type(ino, dev, mode, mtime, (off_t) ReadUnalignedLE64(d));
642 }
Ted Kremenekad6ce5c2009-02-13 22:07:44 +0000643
644 // Negative stat. Don't read anything.
Ted Kremeneka4b44dd2009-02-13 19:13:46 +0000645 return data_type();
Ted Kremenek337edcd2009-02-12 03:26:59 +0000646 }
647};
Ted Kremenek337edcd2009-02-12 03:26:59 +0000648
Benjamin Kramer85b45212009-11-28 19:45:26 +0000649class PTHStatCache : public StatSysCallCache {
Ted Kremenek337edcd2009-02-12 03:26:59 +0000650 typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
651 CacheTy Cache;
652
Mike Stump1eb44332009-09-09 15:08:12 +0000653public:
Ted Kremenek337edcd2009-02-12 03:26:59 +0000654 PTHStatCache(PTHFileLookup &FL) :
655 Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(),
656 FL.getBase()) {}
657
658 ~PTHStatCache() {}
Mike Stump1eb44332009-09-09 15:08:12 +0000659
Ted Kremenek337edcd2009-02-12 03:26:59 +0000660 int stat(const char *path, struct stat *buf) {
661 // Do the lookup for the file's data in the PTH file.
662 CacheTy::iterator I = Cache.find(path);
663
664 // If we don't get a hit in the PTH file just forward to 'stat'.
Kovarththanan Rajaratnam700030e2010-03-12 08:23:34 +0000665 if (I == Cache.end())
Douglas Gregor52e71082009-10-16 18:18:30 +0000666 return StatSysCallCache::stat(path, buf);
Mike Stump1eb44332009-09-09 15:08:12 +0000667
Ted Kremenek337edcd2009-02-12 03:26:59 +0000668 const PTHStatData& Data = *I;
Mike Stump1eb44332009-09-09 15:08:12 +0000669
Ted Kremenekad6ce5c2009-02-13 22:07:44 +0000670 if (!Data.hasStat)
671 return 1;
672
Ted Kremenek337edcd2009-02-12 03:26:59 +0000673 buf->st_ino = Data.ino;
674 buf->st_dev = Data.dev;
675 buf->st_mtime = Data.mtime;
676 buf->st_mode = Data.mode;
677 buf->st_size = Data.size;
678 return 0;
679 }
680};
Ted Kremenekd5785692009-02-23 23:27:54 +0000681} // end anonymous namespace
Ted Kremenek337edcd2009-02-12 03:26:59 +0000682
683StatSysCallCache *PTHManager::createStatCache() {
Ted Kremenek5f747d12009-02-12 03:45:39 +0000684 return new PTHStatCache(*((PTHFileLookup*) FileLookup));
Ted Kremenek337edcd2009-02-12 03:26:59 +0000685}