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