PTHLexer.cpp revision 6b1c9708c8fca3786c766b6d1869721656b31322
1274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//===--- PTHLexer.cpp - Lex from a token stream ---------------------------===//
2274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//
3274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//                     The LLVM Compiler Infrastructure
4274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//
5274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek// This file is distributed under the University of Illinois Open Source
6274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek// License. See LICENSE.TXT for details.
7274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//
8274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//===----------------------------------------------------------------------===//
9274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//
10274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek// This file implements the PTHLexer interface.
11274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//
12274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek//===----------------------------------------------------------------------===//
13274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
140c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "clang/Basic/TokenKinds.h"
150c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "clang/Basic/FileManager.h"
160c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "clang/Basic/IdentifierTable.h"
17274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek#include "clang/Lex/PTHLexer.h"
18274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek#include "clang/Lex/Preprocessor.h"
190c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "clang/Lex/PTHManager.h"
200c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "clang/Lex/Token.h"
210c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "clang/Lex/Preprocessor.h"
220c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "llvm/Support/Compiler.h"
230c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "llvm/Support/MemoryBuffer.h"
240c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "llvm/ADT/StringMap.h"
250c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek#include "llvm/ADT/OwningPtr.h"
260c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
27274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekusing namespace clang;
28274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
298f174e173c1fa195151a86a8cbd7611dde5e2b1aTed Kremenek#define DISK_TOKEN_SIZE (2+4+4+2)
30268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
31e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek//===----------------------------------------------------------------------===//
32e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek// Utility methods for reading from the mmap'ed PTH file.
33e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek//===----------------------------------------------------------------------===//
34e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
35e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenekstatic inline uint8_t Read8(const char*& data) {
36e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  return (uint8_t) *(data++);
37e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek}
38e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
39e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenekstatic inline uint32_t Read32(const char*& data) {
40e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  uint32_t V = (uint32_t) Read8(data);
41e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  V |= (((uint32_t) Read8(data)) << 8);
42e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  V |= (((uint32_t) Read8(data)) << 16);
43e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  V |= (((uint32_t) Read8(data)) << 24);
44e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  return V;
45e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek}
46e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
47e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek//===----------------------------------------------------------------------===//
48e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek// PTHLexer methods.
49e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek//===----------------------------------------------------------------------===//
50e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
510c6a77bc1f52f282a969538f139ebde429076ed3Ted KremenekPTHLexer::PTHLexer(Preprocessor& pp, SourceLocation fileloc, const char* D,
52268ee7016a2811803989487c0ad3799486092c63Ted Kremenek                   const char* ppcond, PTHManager& PM)
53cd223444d1680290efe11da657faafc9a1ac14baTed Kremenek  : PreprocessorLexer(&pp, fileloc), TokBuf(D), CurPtr(D), LastHashTokPtr(0),
54e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    PPCond(ppcond), CurPPCondPtr(ppcond), PTHMgr(PM) {}
55274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
56e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenekvoid PTHLexer::Lex(Token& Tok) {
57e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted KremenekLexNextToken:
58866bdf74547efe32c320554837ffce00fcc084feTed Kremenek
59866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  //===--------------------------------------==//
60866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  // Read the raw token data.
61866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  //===--------------------------------------==//
62e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
63866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  // Shadow CurPtr into an automatic variable.
64866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  const unsigned char *CurPtrShadow = (const unsigned char*) CurPtr;
65866bdf74547efe32c320554837ffce00fcc084feTed Kremenek
66866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  // Read in the data for the token.  14 bytes in total.
67866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  tok::TokenKind k = (tok::TokenKind) CurPtrShadow[0];
68866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  Token::TokenFlags flags = (Token::TokenFlags) CurPtrShadow[1];
69866bdf74547efe32c320554837ffce00fcc084feTed Kremenek
706b1c9708c8fca3786c766b6d1869721656b31322Ted Kremenek  uint32_t perID = ((uint32_t) CurPtrShadow[2])
71866bdf74547efe32c320554837ffce00fcc084feTed Kremenek      | (((uint32_t) CurPtrShadow[3]) << 8)
72866bdf74547efe32c320554837ffce00fcc084feTed Kremenek      | (((uint32_t) CurPtrShadow[4]) << 16)
73866bdf74547efe32c320554837ffce00fcc084feTed Kremenek      | (((uint32_t) CurPtrShadow[5]) << 24);
740c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
75866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  uint32_t FileOffset = ((uint32_t) CurPtrShadow[6])
76866bdf74547efe32c320554837ffce00fcc084feTed Kremenek      | (((uint32_t) CurPtrShadow[7]) << 8)
77866bdf74547efe32c320554837ffce00fcc084feTed Kremenek      | (((uint32_t) CurPtrShadow[8]) << 16)
78866bdf74547efe32c320554837ffce00fcc084feTed Kremenek      | (((uint32_t) CurPtrShadow[9]) << 24);
79e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
80866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  uint32_t Len = ((uint32_t) CurPtrShadow[10])
818f174e173c1fa195151a86a8cbd7611dde5e2b1aTed Kremenek      | (((uint32_t) CurPtrShadow[11]) << 8);
82e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
83866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  CurPtr = (const char*) (CurPtrShadow + DISK_TOKEN_SIZE);
84e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
85866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  //===--------------------------------------==//
86866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  // Construct the token itself.
87866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  //===--------------------------------------==//
88e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
89866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  Tok.startToken();
90866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  Tok.setKind(k);
91866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  Tok.setFlag(flags);
926b1c9708c8fca3786c766b6d1869721656b31322Ted Kremenek  Tok.setIdentifierInfo(perID ? PTHMgr.GetIdentifierInfo(perID-1) : 0);
93866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  Tok.setLocation(SourceLocation::getFileLoc(FileID, FileOffset));
94866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  Tok.setLength(Len);
9589d7ee9619d2dbdfa8d956a695c612a104a92cadTed Kremenek
96866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  //===--------------------------------------==//
97866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  // Process the token.
98866bdf74547efe32c320554837ffce00fcc084feTed Kremenek  //===--------------------------------------==//
9989d7ee9619d2dbdfa8d956a695c612a104a92cadTed Kremenek
100e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  if (Tok.is(tok::eof)) {
101e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    // Save the end-of-file token.
102e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    EofToken = Tok;
103e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
104cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek    Preprocessor *PPCache = PP;
105cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek
106cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek    if (LexEndOfFile(Tok))
107d6f53dc4951aace69014619761760addac9e59ecTed Kremenek      return;
108274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
109cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek    assert(PPCache && "Raw buffer::LexEndOfFile should return a token");
110cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek    return PPCache->Lex(Tok);
111cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek  }
112e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
113e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  MIOpt.ReadToken();
114274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
115e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  if (Tok.is(tok::eom)) {
116d6f53dc4951aace69014619761760addac9e59ecTed Kremenek    ParsingPreprocessorDirective = false;
117274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek    return;
118274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek  }
119d6f53dc4951aace69014619761760addac9e59ecTed Kremenek
120e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek#if 0
121e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  SourceManager& SM = PP->getSourceManager();
122e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  SourceLocation L = Tok.getLocation();
123e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
124e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  static const char* last = 0;
125e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  const char* next = SM.getContentCacheForLoc(L)->Entry->getName();
126e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  if (next != last) {
127e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    last = next;
128e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    llvm::cerr << next << '\n';
129e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  }
130e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
131e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  llvm::cerr << "line " << SM.getLogicalLineNumber(L) << " col " <<
132e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  SM.getLogicalColumnNumber(L) << '\n';
133e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek#endif
134d6f53dc4951aace69014619761760addac9e59ecTed Kremenek
135d6f53dc4951aace69014619761760addac9e59ecTed Kremenek  if (Tok.is(tok::hash)) {
136268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    if (Tok.isAtStartOfLine()) {
137268ee7016a2811803989487c0ad3799486092c63Ted Kremenek      LastHashTokPtr = CurPtr - DISK_TOKEN_SIZE;
138268ee7016a2811803989487c0ad3799486092c63Ted Kremenek      if (!LexingRawMode) {
139268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        PP->HandleDirective(Tok);
140d6f53dc4951aace69014619761760addac9e59ecTed Kremenek
141268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        if (PP->isCurrentLexer(this))
142268ee7016a2811803989487c0ad3799486092c63Ted Kremenek          goto LexNextToken;
143268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
144268ee7016a2811803989487c0ad3799486092c63Ted Kremenek        return PP->Lex(Tok);
145268ee7016a2811803989487c0ad3799486092c63Ted Kremenek      }
146d6f53dc4951aace69014619761760addac9e59ecTed Kremenek    }
147274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek  }
148d6f53dc4951aace69014619761760addac9e59ecTed Kremenek
149d6f53dc4951aace69014619761760addac9e59ecTed Kremenek  if (Tok.is(tok::identifier)) {
150e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    if (LexingRawMode) {
151e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek      Tok.setIdentifierInfo(0);
152e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek      return;
153e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek    }
154e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
155d6f53dc4951aace69014619761760addac9e59ecTed Kremenek    return PP->HandleIdentifier(Tok);
156e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  }
157e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
158e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
159e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  assert(!Tok.is(tok::eom) || ParsingPreprocessorDirective);
160274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek}
161274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek
162e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek// FIXME: This method can just be inlined into Lex().
163cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenekbool PTHLexer::LexEndOfFile(Token &Tok) {
164e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  assert(!ParsingPreprocessorDirective);
165e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  assert(!LexingRawMode);
166cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek
167cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek  // FIXME: Issue diagnostics similar to Lexer.
168cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek  return PP->HandleEndOfFile(Tok, false);
169cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek}
170cd4e2aecde5bb7810715d5d5a88ac63ce7946f34Ted Kremenek
171e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek// FIXME: We can just grab the last token instead of storing a copy
172e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek// into EofToken.
173274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenekvoid PTHLexer::setEOF(Token& Tok) {
1740c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  assert(!EofToken.is(tok::eof));
1750c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  Tok = EofToken;
176274b20863a728cc6a31ee75c670e3733600c1531Ted Kremenek}
17717ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek
17817ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenekvoid PTHLexer::DiscardToEndOfLine() {
17917ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek  assert(ParsingPreprocessorDirective && ParsingFilename == false &&
18017ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek         "Must be in a preprocessing directive!");
1814d35da2e41941965bbee8ed7e8c30e7c21000d71Ted Kremenek
182e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  // We assume that if the preprocessor wishes to discard to the end of
183e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  // the line that it also means to end the current preprocessor directive.
184e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  ParsingPreprocessorDirective = false;
185e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
18674c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  // Skip tokens by only peeking at their token kind and the flags.
18774c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  // We don't need to actually reconstruct full tokens from the token buffer.
18874c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  // This saves some copies and it also reduces IdentifierInfo* lookup.
18974c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  const char* p = CurPtr;
19074c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  while (1) {
19174c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    // Read the token kind.  Are we at the end of the file?
19274c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    tok::TokenKind x = (tok::TokenKind) (uint8_t) *p;
19374c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    if (x == tok::eof) break;
194e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
19574c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    // Read the token flags.  Are we at the start of the next line?
19674c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    Token::TokenFlags y = (Token::TokenFlags) (uint8_t) p[1];
19780d2f3059326f99ebf7c867db1c7f106ec9485f5Ted Kremenek    if (y & Token::StartOfLine) break;
19874c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek
19974c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    // Skip to the next token.
20074c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek    p += DISK_TOKEN_SIZE;
20174c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  }
20274c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek
20374c3e6e5e95af08096aab415d1ce15f15ffff02aTed Kremenek  CurPtr = p;
20417ff58a63197b398ae52697b088dc0fb8b255519Ted Kremenek}
2050c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
206268ee7016a2811803989487c0ad3799486092c63Ted Kremenek/// SkipBlock - Used by Preprocessor to skip the current conditional block.
207268ee7016a2811803989487c0ad3799486092c63Ted Kremenekbool PTHLexer::SkipBlock() {
208268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  assert(CurPPCondPtr && "No cached PP conditional information.");
209268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  assert(LastHashTokPtr && "No known '#' token.");
210268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
21141a2660377d215d004fe413c03874bd066b5384cTed Kremenek  const char* HashEntryI = 0;
212268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  uint32_t Offset;
213268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  uint32_t TableIdx;
214268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
215268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  do {
21641a2660377d215d004fe413c03874bd066b5384cTed Kremenek    // Read the token offset from the side-table.
217268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    Offset = Read32(CurPPCondPtr);
21841a2660377d215d004fe413c03874bd066b5384cTed Kremenek
21941a2660377d215d004fe413c03874bd066b5384cTed Kremenek    // Read the target table index from the side-table.
220268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    TableIdx = Read32(CurPPCondPtr);
22141a2660377d215d004fe413c03874bd066b5384cTed Kremenek
22241a2660377d215d004fe413c03874bd066b5384cTed Kremenek    // Compute the actual memory address of the '#' token data for this entry.
22341a2660377d215d004fe413c03874bd066b5384cTed Kremenek    HashEntryI = TokBuf + Offset;
22441a2660377d215d004fe413c03874bd066b5384cTed Kremenek
22541a2660377d215d004fe413c03874bd066b5384cTed Kremenek    // Optmization: "Sibling jumping".  #if...#else...#endif blocks can
22641a2660377d215d004fe413c03874bd066b5384cTed Kremenek    //  contain nested blocks.  In the side-table we can jump over these
22741a2660377d215d004fe413c03874bd066b5384cTed Kremenek    //  nested blocks instead of doing a linear search if the next "sibling"
22841a2660377d215d004fe413c03874bd066b5384cTed Kremenek    //  entry is not at a location greater than LastHashTokPtr.
22941a2660377d215d004fe413c03874bd066b5384cTed Kremenek    if (HashEntryI < LastHashTokPtr && TableIdx) {
23041a2660377d215d004fe413c03874bd066b5384cTed Kremenek      // In the side-table we are still at an entry for a '#' token that
23141a2660377d215d004fe413c03874bd066b5384cTed Kremenek      // is earlier than the last one we saw.  Check if the location we would
23241a2660377d215d004fe413c03874bd066b5384cTed Kremenek      // stride gets us closer.
23341a2660377d215d004fe413c03874bd066b5384cTed Kremenek      const char* NextPPCondPtr = PPCond + TableIdx*(sizeof(uint32_t)*2);
23441a2660377d215d004fe413c03874bd066b5384cTed Kremenek      assert(NextPPCondPtr >= CurPPCondPtr);
23541a2660377d215d004fe413c03874bd066b5384cTed Kremenek      // Read where we should jump to.
23641a2660377d215d004fe413c03874bd066b5384cTed Kremenek      uint32_t TmpOffset = Read32(NextPPCondPtr);
23741a2660377d215d004fe413c03874bd066b5384cTed Kremenek      const char* HashEntryJ = TokBuf + TmpOffset;
23841a2660377d215d004fe413c03874bd066b5384cTed Kremenek
23941a2660377d215d004fe413c03874bd066b5384cTed Kremenek      if (HashEntryJ <= LastHashTokPtr) {
24041a2660377d215d004fe413c03874bd066b5384cTed Kremenek        // Jump directly to the next entry in the side table.
24141a2660377d215d004fe413c03874bd066b5384cTed Kremenek        HashEntryI = HashEntryJ;
24241a2660377d215d004fe413c03874bd066b5384cTed Kremenek        Offset = TmpOffset;
24341a2660377d215d004fe413c03874bd066b5384cTed Kremenek        TableIdx = Read32(NextPPCondPtr);
24441a2660377d215d004fe413c03874bd066b5384cTed Kremenek        CurPPCondPtr = NextPPCondPtr;
24541a2660377d215d004fe413c03874bd066b5384cTed Kremenek      }
24641a2660377d215d004fe413c03874bd066b5384cTed Kremenek    }
247268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  }
24841a2660377d215d004fe413c03874bd066b5384cTed Kremenek  while (HashEntryI < LastHashTokPtr);
24941a2660377d215d004fe413c03874bd066b5384cTed Kremenek  assert(HashEntryI == LastHashTokPtr && "No PP-cond entry found for '#'");
250268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  assert(TableIdx && "No jumping from #endifs.");
251268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
252268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // Update our side-table iterator.
253268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  const char* NextPPCondPtr = PPCond + TableIdx*(sizeof(uint32_t)*2);
254268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  assert(NextPPCondPtr >= CurPPCondPtr);
255268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  CurPPCondPtr = NextPPCondPtr;
256268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
257268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // Read where we should jump to.
25841a2660377d215d004fe413c03874bd066b5384cTed Kremenek  HashEntryI = TokBuf + Read32(NextPPCondPtr);
259268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  uint32_t NextIdx = Read32(NextPPCondPtr);
260268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
261268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // By construction NextIdx will be zero if this is a #endif.  This is useful
262268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // to know to obviate lexing another token.
263268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  bool isEndif = NextIdx == 0;
264268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
265268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // This case can occur when we see something like this:
266268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  //
267268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  //  #if ...
268268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  //   /* a comment or nothing */
269268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  //  #elif
270268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  //
271268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // If we are skipping the first #if block it will be the case that CurPtr
272268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // already points 'elif'.  Just return.
273268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
27441a2660377d215d004fe413c03874bd066b5384cTed Kremenek  if (CurPtr > HashEntryI) {
27541a2660377d215d004fe413c03874bd066b5384cTed Kremenek    assert(CurPtr == HashEntryI + DISK_TOKEN_SIZE);
276268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    // Did we reach a #endif?  If so, go ahead and consume that token as well.
277268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    if (isEndif)
278e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek      CurPtr += DISK_TOKEN_SIZE*2;
279268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    else
28041a2660377d215d004fe413c03874bd066b5384cTed Kremenek      LastHashTokPtr = HashEntryI;
281268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
282268ee7016a2811803989487c0ad3799486092c63Ted Kremenek    return isEndif;
283268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  }
284268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
285268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // Otherwise, we need to advance.  Update CurPtr to point to the '#' token.
28641a2660377d215d004fe413c03874bd066b5384cTed Kremenek  CurPtr = HashEntryI;
287268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
288268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // Update the location of the last observed '#'.  This is useful if we
289268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // are skipping multiple blocks.
290268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  LastHashTokPtr = CurPtr;
291268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
292e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  // Skip the '#' token.
293e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  assert(((tok::TokenKind) (unsigned char) *CurPtr) == tok::hash);
294e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  CurPtr += DISK_TOKEN_SIZE;
295e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek
296268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // Did we reach a #endif?  If so, go ahead and consume that token as well.
297e5680f3cd678014cf0872d34726dc804b0cbbdd4Ted Kremenek  if (isEndif) { CurPtr += DISK_TOKEN_SIZE*2; }
298268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
299268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  return isEndif;
300268ee7016a2811803989487c0ad3799486092c63Ted Kremenek}
301268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
30230a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed KremenekSourceLocation PTHLexer::getSourceLocation() {
30330a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  // getLocation is not on the hot path.  It is used to get the location of
30430a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  // the next token when transitioning back to this lexer when done
30530a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  // handling a #included file.  Just read the necessary data from the token
30630a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  // data buffer to construct the SourceLocation object.
30730a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  // NOTE: This is a virtual function; hence it is defined out-of-line.
30830a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  const char* p = CurPtr + (1 + 1 + 4);
30930a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  uint32_t offset =
31030a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek       ((uint32_t) ((uint8_t) p[0]))
31130a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek    | (((uint32_t) ((uint8_t) p[1])) << 8)
31230a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek    | (((uint32_t) ((uint8_t) p[2])) << 16)
31330a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek    | (((uint32_t) ((uint8_t) p[3])) << 24);
31430a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek  return SourceLocation::getFileLoc(FileID, offset);
31530a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek}
31630a12ec2a7f331d9e08acabe7cda853aaa7ba54bTed Kremenek
3170c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek//===----------------------------------------------------------------------===//
3180c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek// Internal Data Structures for PTH file lookup and resolving identifiers.
3190c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek//===----------------------------------------------------------------------===//
3200c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3210c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3220c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek/// PTHFileLookup - This internal data structure is used by the PTHManager
3230c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek///  to map from FileEntry objects managed by FileManager to offsets within
3240c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek///  the PTH file.
3250c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremeneknamespace {
3260c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenekclass VISIBILITY_HIDDEN PTHFileLookup {
3270c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenekpublic:
3280c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  class Val {
329fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    uint32_t TokenOff;
330fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    uint32_t PPCondOff;
3310c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3320c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  public:
333fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    Val() : TokenOff(~0) {}
334fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    Val(uint32_t toff, uint32_t poff) : TokenOff(toff), PPCondOff(poff) {}
3350c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
336fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    uint32_t getTokenOffset() const {
337fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek      assert(TokenOff != ~((uint32_t)0) && "PTHFileLookup entry initialized.");
338fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek      return TokenOff;
3390c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    }
3400c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
341fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    uint32_t gettPPCondOffset() const {
342fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek      assert(TokenOff != ~((uint32_t)0) && "PTHFileLookup entry initialized.");
343fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek      return PPCondOff;
344fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    }
345fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek
346fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek    bool isValid() const { return TokenOff != ~((uint32_t)0); }
3470c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  };
3480c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3490c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenekprivate:
3500c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  llvm::StringMap<Val> FileMap;
3510c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3520c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenekpublic:
3530c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  PTHFileLookup() {};
3540c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3550c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  Val Lookup(const FileEntry* FE) {
3560c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    const char* s = FE->getName();
3570c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    unsigned size = strlen(s);
3580c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return FileMap.GetOrCreateValue(s, s+size).getValue();
3590c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  }
3600c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3610c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  void ReadTable(const char* D) {
3620c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    uint32_t N = Read32(D);     // Read the length of the table.
3630c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3640c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    for ( ; N > 0; --N) {       // The rest of the data is the table itself.
3650c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek      uint32_t len = Read32(D);
3660c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek      const char* s = D;
3670c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek      D += len;
368fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek      uint32_t TokenOff = Read32(D);
369fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek      FileMap.GetOrCreateValue(s, s+len).getValue() = Val(TokenOff, Read32(D));
3700c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    }
3710c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  }
3720c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek};
3730c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek} // end anonymous namespace
3740c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3750c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek//===----------------------------------------------------------------------===//
3760c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek// PTHManager methods.
3770c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek//===----------------------------------------------------------------------===//
3780c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3790c6a77bc1f52f282a969538f139ebde429076ed3Ted KremenekPTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
380cf58e6249c6b018508e34bcb76202caa42d2451aTed Kremenek                       const char* idDataTable, IdentifierInfo** perIDCache,
3816183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek                       Preprocessor& pp)
3826183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek: Buf(buf), PerIDCache(perIDCache), FileLookup(fileLookup),
3836183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  IdDataTable(idDataTable), ITable(pp.getIdentifierTable()), PP(pp) {}
3840c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3850c6a77bc1f52f282a969538f139ebde429076ed3Ted KremenekPTHManager::~PTHManager() {
3860c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  delete Buf;
3870c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  delete (PTHFileLookup*) FileLookup;
3880e50b6e7c104d00614baa3d80df62f1630a94d9cTed Kremenek  free(PerIDCache);
3890c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek}
3900c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3910c6a77bc1f52f282a969538f139ebde429076ed3Ted KremenekPTHManager* PTHManager::Create(const std::string& file, Preprocessor& PP) {
3920c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3930c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Memory map the PTH file.
3940c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  llvm::OwningPtr<llvm::MemoryBuffer>
3950c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  File(llvm::MemoryBuffer::getFile(file.c_str()));
3960c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
3970c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  if (!File)
3980c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return 0;
3990c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4000c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Get the buffer ranges and check if there are at least three 32-bit
4010c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // words at the end of the file.
4020c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* BufBeg = File->getBufferStart();
4030c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* BufEnd = File->getBufferEnd();
4040c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4050c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  if(!(BufEnd > BufBeg + sizeof(uint32_t)*3)) {
4060c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    assert(false && "Invalid PTH file.");
4070c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return 0; // FIXME: Proper error diagnostic?
4080c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  }
4090c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4100c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Compute the address of the index table at the end of the PTH file.
4110c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // This table contains the offset of the file lookup table, the
4120c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // persistent ID -> identifer data table.
4130c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* EndTable = BufEnd - sizeof(uint32_t)*3;
4140c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4150c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Construct the file lookup table.  This will be used for mapping from
4160c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // FileEntry*'s to cached tokens.
4170c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* FileTableOffset = EndTable + sizeof(uint32_t)*2;
4180c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* FileTable = BufBeg + Read32(FileTableOffset);
4190c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4200c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  if (!(FileTable > BufBeg && FileTable < BufEnd)) {
4210c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    assert(false && "Invalid PTH file.");
4220c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return 0; // FIXME: Proper error diagnostic?
4230c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  }
4240c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4250c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  llvm::OwningPtr<PTHFileLookup> FL(new PTHFileLookup());
4260c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  FL->ReadTable(FileTable);
4270c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4280c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Get the location of the table mapping from persistent ids to the
4290c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // data needed to reconstruct identifiers.
4300c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* IDTableOffset = EndTable + sizeof(uint32_t)*1;
4310c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* IData = BufBeg + Read32(IDTableOffset);
4320c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  if (!(IData > BufBeg && IData < BufEnd)) {
4330c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    assert(false && "Invalid PTH file.");
4340c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return 0; // FIXME: Proper error diagnostic?
4350c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  }
4360c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4376183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  // Get the number of IdentifierInfos and pre-allocate the identifier cache.
4386183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  uint32_t NumIds = Read32(IData);
4396183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek
4406183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  // Pre-allocate the peristent ID -> IdentifierInfo* cache.  We use calloc()
4416183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  // so that we in the best case only zero out memory once when the OS returns
4426183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  // us new pages.
4436183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  IdentifierInfo** PerIDCache =
4446183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek    (IdentifierInfo**) calloc(NumIds, sizeof(*PerIDCache));
4456183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek
4466183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  if (!PerIDCache) {
4476183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek    assert(false && "Could not allocate Persistent ID cache.");
4486183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek    return 0;
4496183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  }
4506183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek
4516183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  // Create the new lexer.
4526183e4815a4019e97ad01bd880f12355599b75fdTed Kremenek  return new PTHManager(File.take(), FL.take(), IData, PerIDCache, PP);
4530c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek}
4540c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
455866bdf74547efe32c320554837ffce00fcc084feTed KremenekIdentifierInfo* PTHManager::GetIdentifierInfo(unsigned persistentID) {
456866bdf74547efe32c320554837ffce00fcc084feTed Kremenek
4570c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Check if the IdentifierInfo has already been resolved.
458cf58e6249c6b018508e34bcb76202caa42d2451aTed Kremenek  IdentifierInfo*& II = PerIDCache[persistentID];
4590c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  if (II) return II;
4600c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4610c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Look in the PTH file for the string data for the IdentifierInfo object.
4620c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* TableEntry = IdDataTable + sizeof(uint32_t) * persistentID;
4630c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  const char* IDData = Buf->getBufferStart() + Read32(TableEntry);
4640c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  assert(IDData < Buf->getBufferEnd());
4650c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4660c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Read the length of the string.
4670c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  uint32_t len = Read32(IDData);
4680c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4690c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Get the IdentifierInfo* with the specified string.
4700c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  II = &ITable.get(IDData, IDData+len);
4710c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  return II;
4720c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek}
4730c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4740c6a77bc1f52f282a969538f139ebde429076ed3Ted KremenekPTHLexer* PTHManager::CreateLexer(unsigned FileID, const FileEntry* FE) {
4750c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4760c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  if (!FE)
4770c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return 0;
4780c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4790c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Lookup the FileEntry object in our file lookup data structure.  It will
4800c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // return a variant that indicates whether or not there is an offset within
4810c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // the PTH file that contains cached tokens.
482fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek  PTHFileLookup::Val FileData = ((PTHFileLookup*) FileLookup)->Lookup(FE);
4830c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
484fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek  if (!FileData.isValid()) // No tokens available.
4850c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek    return 0;
4860c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek
4870c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  // Compute the offset of the token data within the buffer.
488fb645b6547b75ddc2e3c7ab2126ad8beeefca62dTed Kremenek  const char* data = Buf->getBufferStart() + FileData.getTokenOffset();
489268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
490268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  // Get the location of pp-conditional table.
491268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  const char* ppcond = Buf->getBufferStart() + FileData.gettPPCondOffset();
492268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  uint32_t len = Read32(ppcond);
493268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  if (len == 0) ppcond = 0;
494268ee7016a2811803989487c0ad3799486092c63Ted Kremenek
4950c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek  assert(data < Buf->getBufferEnd());
496268ee7016a2811803989487c0ad3799486092c63Ted Kremenek  return new PTHLexer(PP, SourceLocation::getFileLoc(FileID, 0), data, ppcond,
497268ee7016a2811803989487c0ad3799486092c63Ted Kremenek                      *this);
4980c6a77bc1f52f282a969538f139ebde429076ed3Ted Kremenek}
499