 |
|
 |
|
| 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 |
| |
 |
|
 |
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