blob: 594f55d454df0054bd15e1a0426d0fc95fc2f7b2 [file] [log] [blame]
Ted Kremenekbe1ee792008-12-02 19:45:05 +00001//===--- PTHManager.cpp - Manager object for PTH processing -----*- C++ -*-===//
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 defines the PTHManager interface.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Lex/PTHManager.h"
15#include "clang/Lex/Token.h"
16#include "clang/Lex/Preprocessor.h"
17#include "clang/Basic/FileManager.h"
18#include "clang/Basic/IdentifierTable.h"
19#include "llvm/Support/Compiler.h"
20#include "llvm/Support/MemoryBuffer.h"
21#include "llvm/ADT/StringMap.h"
22#include "llvm/ADT/OwningPtr.h"
23#include "llvm/ADT/DenseMap.h"
24
25using namespace clang;
26
27//===----------------------------------------------------------------------===//
28// Utility methods for reading from the mmap'ed PTH file.
29//===----------------------------------------------------------------------===//
30
31static uint8_t Read8(const char*& data) {
32 return (uint8_t) *(data++);
33}
34
35static uint32_t Read32(const char*& data) {
36 uint32_t V = (uint32_t) Read8(data);
37 V |= (((uint32_t) Read8(data)) << 8);
38 V |= (((uint32_t) Read8(data)) << 16);
39 V |= (((uint32_t) Read8(data)) << 24);
40 return V;
41}
42
43//===----------------------------------------------------------------------===//
44// Internal Data Structures.
45//===----------------------------------------------------------------------===//
46
47typedef llvm::DenseMap<uint32_t, IdentifierInfo*> IDCache;
48
49/// PTHFileLookup - This internal data structure is used by the PTHManager
50/// to map from FileEntry objects managed by FileManager to offsets within
51/// the PTH file.
52namespace {
53class VISIBILITY_HIDDEN PTHFileLookup {
54public:
55 class Val {
56 uint32_t v;
57
58 public:
59 Val() : v(~0) {}
60 Val(uint32_t x) : v(x) {}
61
62 operator uint32_t() const {
63 assert(v != ~((uint32_t)0) && "PTHFileLookup entry initialized.");
64 return v;
65 }
66
67 Val& operator=(uint32_t x) { v = x; return *this; }
68 bool isValid() const { return v != ~((uint32_t)0); }
69 };
70
71private:
72 llvm::StringMap<Val> FileMap;
73
74public:
75 PTHFileLookup() {};
76
77 Val Lookup(const FileEntry* FE) {
78 const char* s = FE->getName();
79 unsigned size = strlen(s);
80 return FileMap.GetOrCreateValue(s, s+size).getValue();
81 }
82
83 void ReadTable(const char* D) {
84 uint32_t N = Read32(D); // Read the length of the table.
85
86 for ( ; N > 0; --N) { // The rest of the data is the table itself.
87 uint32_t len = Read32(D);
88 const char* s = D;
89 D += len;
90 FileMap.GetOrCreateValue(s, s+len).getValue() = Read32(D);
91 }
92 }
93};
94} // end anonymous namespace
95
96//===----------------------------------------------------------------------===//
97// PTHManager methods.
98//===----------------------------------------------------------------------===//
99
100PTHManager::PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup,
101 const char* idDataTable, Preprocessor& pp)
102 : Buf(buf), PersistentIDCache(0), FileLookup(fileLookup),
103 IdDataTable(idDataTable), ITable(pp.getIdentifierTable()), PP(pp) {}
104
105PTHManager::~PTHManager() {
106 delete Buf;
107 delete (PTHFileLookup*) FileLookup;
108 delete (IDCache*) PersistentIDCache;
109}
110
111PTHManager* PTHManager::Create(const std::string& file, Preprocessor& PP) {
112
113 // Memory map the PTH file.
114 llvm::OwningPtr<llvm::MemoryBuffer>
115 File(llvm::MemoryBuffer::getFile(file.c_str()));
116
117 if (!File)
118 return 0;
119
120 // Get the buffer ranges and check if there are at least three 32-bit
121 // words at the end of the file.
122 const char* BufBeg = File->getBufferStart();
123 const char* BufEnd = File->getBufferEnd();
124
125 if(!(BufEnd > BufBeg + sizeof(uint32_t)*3)) {
126 assert(false && "Invalid PTH file.");
127 return 0; // FIXME: Proper error diagnostic?
128 }
129
130 // Compute the address of the index table at the end of the PTH file.
131 // This table contains the offset of the file lookup table, the
132 // persistent ID -> identifer data table.
133 const char* EndTable = BufEnd - sizeof(uint32_t)*3;
134
135 // Construct the file lookup table. This will be used for mapping from
136 // FileEntry*'s to cached tokens.
137 const char* FileTableOffset = EndTable + sizeof(uint32_t)*2;
138 const char* FileTable = BufBeg + Read32(FileTableOffset);
139
140 if (!(FileTable > BufBeg && FileTable < BufEnd)) {
141 assert(false && "Invalid PTH file.");
142 return 0; // FIXME: Proper error diagnostic?
143 }
144
145 llvm::OwningPtr<PTHFileLookup> FL(new PTHFileLookup());
146 FL->ReadTable(FileTable);
147
148 // Get the location of the table mapping from persistent ids to the
149 // data needed to reconstruct identifiers.
150 const char* IDTableOffset = EndTable + sizeof(uint32_t)*1;
151 const char* IData = BufBeg + Read32(IDTableOffset);
152 if (!(IData > BufBeg && IData < BufEnd)) {
153 assert(false && "Invalid PTH file.");
154 return 0; // FIXME: Proper error diagnostic?
155 }
156
157 return new PTHManager(File.take(), FL.take(), IData, PP);
158}
159
160IdentifierInfo* PTHManager::ReadIdentifierInfo(const char*& D) {
161 // Read the persistent ID from the PTH file.
162 uint32_t persistentID = Read32(D);
163
164 // A persistent ID of '0' always maps to NULL.
165 if (!persistentID)
166 return 0;
167
168 // Adjust the persistent ID by subtracting '1' so that it can be used
169 // as an index within a table in the PTH file.
170 --persistentID;
171
172 // Check if the IdentifierInfo has already been resolved.
173 if (!PersistentIDCache)
174 PersistentIDCache = new IDCache();
175
176 // FIXME: We can make this an array, but what is the performance tradeoff?
177 IdentifierInfo*& II = (*((IDCache*) PersistentIDCache))[persistentID];
178 if (II) return II;
179
180 // Look in the PTH file for the string data for the IdentifierInfo object.
181 const char* TableEntry = IdDataTable + sizeof(uint32_t) * persistentID;
182 const char* IDData = Buf->getBufferStart() + Read32(TableEntry);
183 assert(IDData < Buf->getBufferEnd());
184
185 // Read the length of the string.
186 uint32_t len = Read32(IDData);
187
188 // Get the IdentifierInfo* with the specified string.
189 II = &ITable.get(IDData, IDData+len);
190 return II;
191}
192
193void PTHManager::ReadToken(const char*& D, unsigned FileID, Token& T) {
194 // Clear the token.
195 // FIXME: Setting the flags directly should obviate this step.
196 T.startToken();
197
198 // Read the type of the token.
199 T.setKind((tok::TokenKind) Read8(D));
200
201 // Set flags. This is gross, since we are really setting multiple flags.
202 T.setFlag((Token::TokenFlags) Read8(D));
203
204 // Set the IdentifierInfo* (if any).
205 T.setIdentifierInfo(ReadIdentifierInfo(D));
206
207 // Set the SourceLocation. Since all tokens are constructed using a
208 // raw lexer, they will all be offseted from the same FileID.
209 T.setLocation(SourceLocation::getFileLoc(FileID, Read32(D)));
210
211 // Finally, read and set the length of the token.
212 T.setLength(Read32(D));
213}
214
215PTHLexer* PTHManager::CreateLexer(unsigned FileID, const FileEntry* FE) {
216
217 if (!FE)
218 return 0;
219
220 // Lookup the FileEntry object in our file lookup data structure. It will
221 // return a variant that indicates whether or not there is an offset within
222 // the PTH file that contains cached tokens.
223 PTHFileLookup::Val Off = ((PTHFileLookup*) FileLookup)->Lookup(FE);
224
225 if (!Off.isValid()) // No tokens available.
226 return 0;
227
228 // Compute the offset of the token data within the buffer.
229 const char* data = Buf->getBufferStart() + Off;
230 assert(data < Buf->getBufferEnd());
231
232 // First cut: read the tokens from the file into a vector.
233 // Later, stream them.
234 SourceLocation Loc = SourceLocation::getFileLoc(FileID, 0);
235 llvm::OwningPtr<PTHLexer> L(new PTHLexer(PP, Loc));
236 std::vector<Token>& Tokens = L->getTokens();
237
238 Token T;
239 do {
240 ReadToken(data, FileID, T);
241 Tokens.push_back(T);
242 }
243 while (T.isNot(tok::eof));
244
245 // Return the lexer to the client. The client assumes ownership of this
246 // PTHLexer object.
247 return L.take();
248}