| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 1 | //===--- CacheTokens.cpp - Caching of lexer tokens for PTH support --------===// | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 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 | // | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 10 | // This provides a possible implementation of PTH support for Clang that is | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 11 | // based on caching lexed tokens and identifiers. | 
|  | 12 | // | 
|  | 13 | //===----------------------------------------------------------------------===// | 
|  | 14 |  | 
|  | 15 | #include "clang.h" | 
|  | 16 | #include "clang/Basic/FileManager.h" | 
|  | 17 | #include "clang/Basic/SourceManager.h" | 
|  | 18 | #include "clang/Basic/IdentifierTable.h" | 
|  | 19 | #include "clang/Basic/Diagnostic.h" | 
|  | 20 | #include "clang/Lex/Lexer.h" | 
|  | 21 | #include "clang/Lex/Preprocessor.h" | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 22 | #include "llvm/ADT/StringMap.h" | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 23 | #include "llvm/Support/MemoryBuffer.h" | 
|  | 24 | #include "llvm/Support/raw_ostream.h" | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 25 | #include "llvm/System/Path.h" | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 26 | #include "llvm/Support/Compiler.h" | 
| Ted Kremenek | 72b1b15 | 2009-01-15 18:47:46 +0000 | [diff] [blame] | 27 | #include "llvm/Support/Streams.h" | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 28 |  | 
| Cedric Venet | ea684e6 | 2009-02-14 16:15:20 +0000 | [diff] [blame] | 29 | // FIXME: put this somewhere else? | 
|  | 30 | #ifndef S_ISDIR | 
|  | 31 | #define S_ISDIR(x) (((x)&_S_IFDIR)!=0) | 
|  | 32 | #endif | 
|  | 33 |  | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 34 | using namespace clang; | 
|  | 35 |  | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 36 | typedef uint32_t Offset; | 
|  | 37 |  | 
| Ted Kremenek | e0ea5dc | 2009-02-10 01:06:17 +0000 | [diff] [blame] | 38 | static void Emit8(llvm::raw_ostream& Out, uint32_t V) { | 
|  | 39 | Out << (unsigned char)(V); | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | static void Emit16(llvm::raw_ostream& Out, uint32_t V) { | 
|  | 43 | Out << (unsigned char)(V); | 
|  | 44 | Out << (unsigned char)(V >>  8); | 
|  | 45 | assert((V >> 16) == 0); | 
|  | 46 | } | 
|  | 47 |  | 
|  | 48 | static void Emit32(llvm::raw_ostream& Out, uint32_t V) { | 
|  | 49 | Out << (unsigned char)(V); | 
|  | 50 | Out << (unsigned char)(V >>  8); | 
|  | 51 | Out << (unsigned char)(V >> 16); | 
|  | 52 | Out << (unsigned char)(V >> 24); | 
|  | 53 | } | 
|  | 54 |  | 
| Ted Kremenek | 337edcd | 2009-02-12 03:26:59 +0000 | [diff] [blame] | 55 | static void Emit64(llvm::raw_ostream& Out, uint64_t V) { | 
|  | 56 | Out << (unsigned char)(V); | 
|  | 57 | Out << (unsigned char)(V >>  8); | 
|  | 58 | Out << (unsigned char)(V >> 16); | 
|  | 59 | Out << (unsigned char)(V >> 24); | 
|  | 60 | Out << (unsigned char)(V >> 32); | 
|  | 61 | Out << (unsigned char)(V >> 40); | 
|  | 62 | Out << (unsigned char)(V >> 48); | 
|  | 63 | Out << (unsigned char)(V >> 56); | 
|  | 64 | } | 
|  | 65 |  | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 66 | static void Pad(llvm::raw_fd_ostream& Out, unsigned A) { | 
|  | 67 | Offset off = (Offset) Out.tell(); | 
|  | 68 | uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off; | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 69 | for (; n ; --n) | 
|  | 70 | Emit8(Out, 0); | 
| Ted Kremenek | e0ea5dc | 2009-02-10 01:06:17 +0000 | [diff] [blame] | 71 | } | 
|  | 72 |  | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 73 | // Bernstein hash function: | 
|  | 74 | // This is basically copy-and-paste from StringMap.  This likely won't | 
|  | 75 | // stay here, which is why I didn't both to expose this function from | 
|  | 76 | // String Map. | 
|  | 77 | static unsigned BernsteinHash(const char* x) { | 
|  | 78 | unsigned int R = 0; | 
|  | 79 | for ( ; *x != '\0' ; ++x) R = R * 33 + *x; | 
|  | 80 | return R + (R >> 5); | 
|  | 81 | } | 
|  | 82 |  | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 83 | //===----------------------------------------------------------------------===// | 
|  | 84 | // On Disk Hashtable Logic.  This will eventually get refactored and put | 
|  | 85 | // elsewhere. | 
|  | 86 | //===----------------------------------------------------------------------===// | 
|  | 87 |  | 
|  | 88 | template<typename Info> | 
|  | 89 | class OnDiskChainedHashTableGenerator { | 
|  | 90 | unsigned NumBuckets; | 
|  | 91 | unsigned NumEntries; | 
|  | 92 | llvm::BumpPtrAllocator BA; | 
|  | 93 |  | 
|  | 94 | class Item { | 
|  | 95 | public: | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 96 | typename Info::key_type key; | 
|  | 97 | typename Info::data_type data; | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 98 | Item *next; | 
|  | 99 | const uint32_t hash; | 
|  | 100 |  | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 101 | Item(typename Info::key_type_ref k, typename Info::data_type_ref d) | 
|  | 102 | : key(k), data(d), next(0), hash(Info::ComputeHash(k)) {} | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 103 | }; | 
|  | 104 |  | 
|  | 105 | class Bucket { | 
|  | 106 | public: | 
|  | 107 | Offset off; | 
|  | 108 | Item*  head; | 
|  | 109 | unsigned length; | 
|  | 110 |  | 
|  | 111 | Bucket() {} | 
|  | 112 | }; | 
|  | 113 |  | 
|  | 114 | Bucket* Buckets; | 
|  | 115 |  | 
|  | 116 | private: | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 117 | void insert(Bucket* b, size_t size, Item* E) { | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 118 | unsigned idx = E->hash & (size - 1); | 
|  | 119 | Bucket& B = b[idx]; | 
|  | 120 | E->next = B.head; | 
|  | 121 | ++B.length; | 
|  | 122 | B.head = E; | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | void resize(size_t newsize) { | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 126 | Bucket* newBuckets = (Bucket*) calloc(newsize, sizeof(Bucket)); | 
|  | 127 | // Populate newBuckets with the old entries. | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 128 | for (unsigned i = 0; i < NumBuckets; ++i) | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 129 | for (Item* E = Buckets[i].head; E ; ) { | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 130 | Item* N = E->next; | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 131 | E->next = 0; | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 132 | insert(newBuckets, newsize, E); | 
|  | 133 | E = N; | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | free(Buckets); | 
|  | 137 | NumBuckets = newsize; | 
|  | 138 | Buckets = newBuckets; | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | public: | 
|  | 142 |  | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 143 | void insert(typename Info::key_type_ref key, | 
|  | 144 | typename Info::data_type_ref data) { | 
|  | 145 |  | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 146 | ++NumEntries; | 
|  | 147 | if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2); | 
|  | 148 | insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data)); | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | Offset Emit(llvm::raw_fd_ostream& out) { | 
|  | 152 | // Emit the payload of the table. | 
|  | 153 | for (unsigned i = 0; i < NumBuckets; ++i) { | 
|  | 154 | Bucket& B = Buckets[i]; | 
|  | 155 | if (!B.head) continue; | 
|  | 156 |  | 
|  | 157 | // Store the offset for the data of this bucket. | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 158 | B.off = out.tell(); | 
|  | 159 |  | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 160 | // Write out the number of items in the bucket. | 
|  | 161 | Emit16(out, B.length); | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 162 |  | 
|  | 163 | // Write out the entries in the bucket. | 
|  | 164 | for (Item *I = B.head; I ; I = I->next) { | 
|  | 165 | Emit32(out, I->hash); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 166 | const std::pair<unsigned, unsigned>& Len = | 
|  | 167 | Info::EmitKeyDataLength(out, I->key, I->data); | 
|  | 168 | Info::EmitKey(out, I->key, Len.first); | 
| Ted Kremenek | 337edcd | 2009-02-12 03:26:59 +0000 | [diff] [blame] | 169 | Info::EmitData(out, I->key, I->data, Len.second); | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 170 | } | 
|  | 171 | } | 
|  | 172 |  | 
|  | 173 | // Emit the hashtable itself. | 
|  | 174 | Pad(out, 4); | 
|  | 175 | Offset TableOff = out.tell(); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 176 | Emit32(out, NumBuckets); | 
|  | 177 | Emit32(out, NumEntries); | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 178 | for (unsigned i = 0; i < NumBuckets; ++i) Emit32(out, Buckets[i].off); | 
|  | 179 |  | 
|  | 180 | return TableOff; | 
|  | 181 | } | 
|  | 182 |  | 
|  | 183 | OnDiskChainedHashTableGenerator() { | 
|  | 184 | NumEntries = 0; | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 185 | NumBuckets = 64; | 
|  | 186 | // Note that we do not need to run the constructors of the individual | 
|  | 187 | // Bucket objects since 'calloc' returns bytes that are all 0. | 
|  | 188 | Buckets = (Bucket*) calloc(NumBuckets, sizeof(Bucket)); | 
| Ted Kremenek | f0e1f79 | 2009-02-10 01:14:45 +0000 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
|  | 191 | ~OnDiskChainedHashTableGenerator() { | 
|  | 192 | free(Buckets); | 
|  | 193 | } | 
|  | 194 | }; | 
|  | 195 |  | 
|  | 196 | //===----------------------------------------------------------------------===// | 
|  | 197 | // PTH-specific stuff. | 
|  | 198 | //===----------------------------------------------------------------------===// | 
|  | 199 |  | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 200 | namespace { | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 201 | class VISIBILITY_HIDDEN PTHEntry { | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 202 | Offset TokenData, PPCondData; | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 203 |  | 
|  | 204 | public: | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 205 | PTHEntry() {} | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 206 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 207 | PTHEntry(Offset td, Offset ppcd) | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 208 | : TokenData(td), PPCondData(ppcd) {} | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 209 |  | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 210 | Offset getTokenOffset() const { return TokenData; } | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 211 | Offset getPPCondTableOffset() const { return PPCondData; } | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 212 | }; | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 213 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 214 |  | 
|  | 215 | class VISIBILITY_HIDDEN PTHEntryKeyVariant { | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 216 | union { const FileEntry* FE; const char* Path; }; | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 217 | enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind; | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 218 | struct stat *StatBuf; | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 219 | public: | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 220 | PTHEntryKeyVariant(const FileEntry *fe) | 
|  | 221 | : FE(fe), Kind(IsFE), StatBuf(0) {} | 
|  | 222 |  | 
|  | 223 | PTHEntryKeyVariant(struct stat* statbuf, const char* path) | 
|  | 224 | : Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {} | 
|  | 225 |  | 
|  | 226 | PTHEntryKeyVariant(const char* path) | 
|  | 227 | : Path(path), Kind(IsNoExist), StatBuf(0) {} | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 228 |  | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 229 | bool isFile() const { return Kind == IsFE; } | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 230 |  | 
|  | 231 | const char* getCString() const { | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 232 | return Kind == IsFE ? FE->getName() : Path; | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 233 | } | 
|  | 234 |  | 
|  | 235 | unsigned getKind() const { return (unsigned) Kind; } | 
|  | 236 |  | 
|  | 237 | void EmitData(llvm::raw_ostream& Out) { | 
|  | 238 | switch (Kind) { | 
|  | 239 | case IsFE: | 
|  | 240 | // Emit stat information. | 
|  | 241 | ::Emit32(Out, FE->getInode()); | 
|  | 242 | ::Emit32(Out, FE->getDevice()); | 
|  | 243 | ::Emit16(Out, FE->getFileMode()); | 
|  | 244 | ::Emit64(Out, FE->getModificationTime()); | 
|  | 245 | ::Emit64(Out, FE->getSize()); | 
|  | 246 | break; | 
|  | 247 | case IsDE: | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 248 | // Emit stat information. | 
|  | 249 | ::Emit32(Out, (uint32_t) StatBuf->st_ino); | 
|  | 250 | ::Emit32(Out, (uint32_t) StatBuf->st_dev); | 
|  | 251 | ::Emit16(Out, (uint16_t) StatBuf->st_mode); | 
|  | 252 | ::Emit64(Out, (uint64_t) StatBuf->st_mtime); | 
|  | 253 | ::Emit64(Out, (uint64_t) StatBuf->st_size); | 
|  | 254 | delete StatBuf; | 
|  | 255 | break; | 
|  | 256 | default: | 
|  | 257 | break; | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 258 | } | 
|  | 259 | } | 
|  | 260 |  | 
|  | 261 | unsigned getRepresentationLength() const { | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 262 | return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8; | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 263 | } | 
|  | 264 | }; | 
|  | 265 |  | 
|  | 266 | class VISIBILITY_HIDDEN FileEntryPTHEntryInfo { | 
|  | 267 | public: | 
|  | 268 | typedef PTHEntryKeyVariant key_type; | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 269 | typedef key_type key_type_ref; | 
|  | 270 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 271 | typedef PTHEntry data_type; | 
|  | 272 | typedef const PTHEntry& data_type_ref; | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 273 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 274 | static unsigned ComputeHash(PTHEntryKeyVariant V) { | 
|  | 275 | return BernsteinHash(V.getCString()); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 276 | } | 
|  | 277 |  | 
|  | 278 | static std::pair<unsigned,unsigned> | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 279 | EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V, | 
|  | 280 | const PTHEntry& E) { | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 281 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 282 | unsigned n = strlen(V.getCString()) + 1 + 1; | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 283 | ::Emit16(Out, n); | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 284 |  | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 285 | unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0); | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 286 | ::Emit8(Out, m); | 
|  | 287 |  | 
|  | 288 | return std::make_pair(n, m); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 289 | } | 
|  | 290 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 291 | static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ | 
|  | 292 | // Emit the entry kind. | 
|  | 293 | ::Emit8(Out, (unsigned) V.getKind()); | 
|  | 294 | // Emit the string. | 
|  | 295 | Out.write(V.getCString(), n - 1); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 296 | } | 
|  | 297 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 298 | static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V, | 
|  | 299 | const PTHEntry& E, unsigned) { | 
|  | 300 |  | 
|  | 301 |  | 
|  | 302 | // For file entries emit the offsets into the PTH file for token data | 
|  | 303 | // and the preprocessor blocks table. | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 304 | if (V.isFile()) { | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 305 | ::Emit32(Out, E.getTokenOffset()); | 
|  | 306 | ::Emit32(Out, E.getPPCondTableOffset()); | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | // Emit any other data associated with the key (i.e., stat information). | 
|  | 310 | V.EmitData(Out); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 311 | } | 
|  | 312 | }; | 
|  | 313 |  | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 314 | class OffsetOpt { | 
|  | 315 | bool valid; | 
|  | 316 | Offset off; | 
|  | 317 | public: | 
|  | 318 | OffsetOpt() : valid(false) {} | 
|  | 319 | bool hasOffset() const { return valid; } | 
|  | 320 | Offset getOffset() const { assert(valid); return off; } | 
|  | 321 | void setOffset(Offset o) { off = o; valid = true; } | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 322 | }; | 
|  | 323 | } // end anonymous namespace | 
|  | 324 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 325 | typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap; | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 326 | typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap; | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 327 | typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy; | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 328 |  | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 329 | namespace { | 
|  | 330 | class VISIBILITY_HIDDEN PTHWriter { | 
|  | 331 | IDMap IM; | 
|  | 332 | llvm::raw_fd_ostream& Out; | 
|  | 333 | Preprocessor& PP; | 
|  | 334 | uint32_t idcount; | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 335 | PTHMap PM; | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 336 | CachedStrsTy CachedStrs; | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 337 | Offset CurStrOffset; | 
|  | 338 | std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries; | 
| Ted Kremenek | 8f174e1 | 2008-12-23 02:52:12 +0000 | [diff] [blame] | 339 |  | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 340 | //// Get the persistent id for the given IdentifierInfo*. | 
|  | 341 | uint32_t ResolveID(const IdentifierInfo* II); | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 342 |  | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 343 | /// Emit a token to the PTH file. | 
|  | 344 | void EmitToken(const Token& T); | 
|  | 345 |  | 
|  | 346 | void Emit8(uint32_t V) { | 
|  | 347 | Out << (unsigned char)(V); | 
|  | 348 | } | 
|  | 349 |  | 
| Ted Kremenek | e0ea5dc | 2009-02-10 01:06:17 +0000 | [diff] [blame] | 350 | void Emit16(uint32_t V) { ::Emit16(Out, V); } | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 351 |  | 
|  | 352 | void Emit24(uint32_t V) { | 
|  | 353 | Out << (unsigned char)(V); | 
|  | 354 | Out << (unsigned char)(V >>  8); | 
|  | 355 | Out << (unsigned char)(V >> 16); | 
|  | 356 | assert((V >> 24) == 0); | 
|  | 357 | } | 
|  | 358 |  | 
| Ted Kremenek | e0ea5dc | 2009-02-10 01:06:17 +0000 | [diff] [blame] | 359 | void Emit32(uint32_t V) { ::Emit32(Out, V); } | 
|  | 360 |  | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 361 | void EmitBuf(const char *Ptr, unsigned NumBytes) { | 
|  | 362 | Out.write(Ptr, NumBytes); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 363 | } | 
|  | 364 |  | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 365 | /// EmitIdentifierTable - Emits two tables to the PTH file.  The first is | 
|  | 366 | ///  a hashtable mapping from identifier strings to persistent IDs. | 
|  | 367 | ///  The second is a straight table mapping from persistent IDs to string data | 
|  | 368 | ///  (the keys of the first table). | 
| Ted Kremenek | f1de464 | 2009-02-11 16:06:55 +0000 | [diff] [blame] | 369 | std::pair<Offset, Offset> EmitIdentifierTable(); | 
|  | 370 |  | 
|  | 371 | /// EmitFileTable - Emit a table mapping from file name strings to PTH | 
|  | 372 | /// token data. | 
|  | 373 | Offset EmitFileTable() { return PM.Emit(Out); } | 
|  | 374 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 375 | PTHEntry LexTokens(Lexer& L); | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 376 | Offset EmitCachedSpellings(); | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 377 |  | 
|  | 378 | /// StatListener - A simple "interpose" object used to monitor stat calls | 
|  | 379 | /// invoked by FileManager while processing the original sources used | 
|  | 380 | /// as input to PTH generation.  StatListener populates the PTHWriter's | 
|  | 381 | /// file map with stat information for directories as well as negative stats. | 
|  | 382 | /// Stat information for files are populated elsewhere. | 
|  | 383 | class StatListener : public StatSysCallCache { | 
|  | 384 | PTHMap& PM; | 
|  | 385 | public: | 
|  | 386 | StatListener(PTHMap& pm) : PM(pm) {} | 
|  | 387 | ~StatListener() {} | 
|  | 388 |  | 
|  | 389 | int stat(const char *path, struct stat *buf) { | 
|  | 390 | int result = ::stat(path, buf); | 
|  | 391 |  | 
|  | 392 | if (result != 0) // Failed 'stat'. | 
|  | 393 | PM.insert(path, PTHEntry()); | 
|  | 394 | else if (S_ISDIR(buf->st_mode)) { | 
|  | 395 | // Only cache directories with absolute paths. | 
|  | 396 | if (!llvm::sys::Path(path).isAbsolute()) | 
|  | 397 | return result; | 
|  | 398 |  | 
|  | 399 | PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry()); | 
|  | 400 | } | 
|  | 401 |  | 
|  | 402 | return result; | 
|  | 403 | } | 
|  | 404 | }; | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 405 |  | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 406 | public: | 
|  | 407 | PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp) | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 408 | : Out(out), PP(pp), idcount(0), CurStrOffset(0) {} | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 409 |  | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 410 | void GeneratePTH(const std::string *MainFile = 0); | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 411 |  | 
|  | 412 | StatSysCallCache *createStatListener() { | 
|  | 413 | return new StatListener(PM); | 
|  | 414 | } | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 415 | }; | 
|  | 416 | } // end anonymous namespace | 
|  | 417 |  | 
|  | 418 | uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) { | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 419 | // Null IdentifierInfo's map to the persistent ID 0. | 
|  | 420 | if (!II) | 
|  | 421 | return 0; | 
|  | 422 |  | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 423 | IDMap::iterator I = IM.find(II); | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 424 | if (I != IM.end()) | 
|  | 425 | return I->second; // We've already added 1. | 
|  | 426 |  | 
|  | 427 | IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL. | 
|  | 428 | return idcount; | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 429 | } | 
|  | 430 |  | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 431 | void PTHWriter::EmitToken(const Token& T) { | 
| Ted Kremenek | f2a223f | 2009-02-24 01:26:56 +0000 | [diff] [blame] | 432 | // Emit the token kind, flags, and length. | 
|  | 433 | Emit32(((uint32_t) T.getKind()) | ((((uint32_t) T.getFlags())) << 8)| | 
|  | 434 | (((uint32_t) T.getLength()) << 16)); | 
|  | 435 |  | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 436 | if (!T.isLiteral()) { | 
|  | 437 | Emit32(ResolveID(T.getIdentifierInfo())); | 
|  | 438 | } else { | 
| Ted Kremenek | f2a223f | 2009-02-24 01:26:56 +0000 | [diff] [blame] | 439 | // We cache *un-cleaned* spellings. This gives us 100% fidelity with the | 
|  | 440 | // source code. | 
|  | 441 | const char* s = T.getLiteralData(); | 
|  | 442 | unsigned len = T.getLength(); | 
| Ted Kremenek | 25cbd9f | 2009-02-24 00:30:21 +0000 | [diff] [blame] | 443 |  | 
| Chris Lattner | 47246be | 2009-01-26 19:29:26 +0000 | [diff] [blame] | 444 | // Get the string entry. | 
| Ted Kremenek | f2a223f | 2009-02-24 01:26:56 +0000 | [diff] [blame] | 445 | llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s, s+len); | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 446 |  | 
| Ted Kremenek | f2a223f | 2009-02-24 01:26:56 +0000 | [diff] [blame] | 447 | // If this is a new string entry, bump the PTH offset. | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 448 | if (!E->getValue().hasOffset()) { | 
|  | 449 | E->getValue().setOffset(CurStrOffset); | 
|  | 450 | StrEntries.push_back(E); | 
| Ted Kremenek | f2a223f | 2009-02-24 01:26:56 +0000 | [diff] [blame] | 451 | CurStrOffset += len + 1; | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 452 | } | 
|  | 453 |  | 
| Ted Kremenek | 25cbd9f | 2009-02-24 00:30:21 +0000 | [diff] [blame] | 454 | // Emit the relative offset into the PTH file for the spelling string. | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 455 | Emit32(E->getValue().getOffset()); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 456 | } | 
| Ted Kremenek | 25cbd9f | 2009-02-24 00:30:21 +0000 | [diff] [blame] | 457 |  | 
|  | 458 | // Emit the offset into the original source file of this token so that we | 
|  | 459 | // can reconstruct its SourceLocation. | 
| Chris Lattner | 52c2908 | 2009-01-27 06:27:13 +0000 | [diff] [blame] | 460 | Emit32(PP.getSourceManager().getFileOffset(T.getLocation())); | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 461 | } | 
|  | 462 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 463 | PTHEntry PTHWriter::LexTokens(Lexer& L) { | 
| Ted Kremenek | 7b78b7c | 2009-01-19 23:13:15 +0000 | [diff] [blame] | 464 | // Pad 0's so that we emit tokens to a 4-byte alignment. | 
|  | 465 | // This speed up reading them back in. | 
| Ted Kremenek | e0ea5dc | 2009-02-10 01:06:17 +0000 | [diff] [blame] | 466 | Pad(Out, 4); | 
|  | 467 | Offset off = (Offset) Out.tell(); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 468 |  | 
|  | 469 | // Keep track of matching '#if' ... '#endif'. | 
|  | 470 | typedef std::vector<std::pair<Offset, unsigned> > PPCondTable; | 
|  | 471 | PPCondTable PPCond; | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 472 | std::vector<unsigned> PPStartCond; | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 473 | bool ParsingPreprocessorDirective = false; | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 474 | Token Tok; | 
|  | 475 |  | 
|  | 476 | do { | 
|  | 477 | L.LexFromRawLexer(Tok); | 
| Ted Kremenek | 726080d | 2009-02-10 22:43:16 +0000 | [diff] [blame] | 478 | NextToken: | 
|  | 479 |  | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 480 | if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) && | 
|  | 481 | ParsingPreprocessorDirective) { | 
|  | 482 | // Insert an eom token into the token cache.  It has the same | 
|  | 483 | // position as the next token that is not on the same line as the | 
|  | 484 | // preprocessor directive.  Observe that we continue processing | 
|  | 485 | // 'Tok' when we exit this branch. | 
|  | 486 | Token Tmp = Tok; | 
|  | 487 | Tmp.setKind(tok::eom); | 
|  | 488 | Tmp.clearFlag(Token::StartOfLine); | 
|  | 489 | Tmp.setIdentifierInfo(0); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 490 | EmitToken(Tmp); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 491 | ParsingPreprocessorDirective = false; | 
|  | 492 | } | 
|  | 493 |  | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 494 | if (Tok.is(tok::identifier)) { | 
|  | 495 | Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok)); | 
| Ted Kremenek | e4f6b1e | 2009-02-10 22:27:09 +0000 | [diff] [blame] | 496 | EmitToken(Tok); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 497 | continue; | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 498 | } | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 499 |  | 
|  | 500 | if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 501 | // Special processing for #include.  Store the '#' token and lex | 
|  | 502 | // the next token. | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 503 | assert(!ParsingPreprocessorDirective); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 504 | Offset HashOff = (Offset) Out.tell(); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 505 | EmitToken(Tok); | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 506 |  | 
|  | 507 | // Get the next token. | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 508 | L.LexFromRawLexer(Tok); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 509 |  | 
|  | 510 | assert(!Tok.isAtStartOfLine()); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 511 |  | 
|  | 512 | // Did we see 'include'/'import'/'include_next'? | 
| Ted Kremenek | e4f6b1e | 2009-02-10 22:27:09 +0000 | [diff] [blame] | 513 | if (!Tok.is(tok::identifier)) { | 
|  | 514 | EmitToken(Tok); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 515 | continue; | 
| Ted Kremenek | e4f6b1e | 2009-02-10 22:27:09 +0000 | [diff] [blame] | 516 | } | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 517 |  | 
|  | 518 | IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok); | 
|  | 519 | Tok.setIdentifierInfo(II); | 
|  | 520 | tok::PPKeywordKind K = II->getPPKeywordID(); | 
|  | 521 |  | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 522 | assert(K != tok::pp_not_keyword); | 
|  | 523 | ParsingPreprocessorDirective = true; | 
|  | 524 |  | 
|  | 525 | switch (K) { | 
|  | 526 | default: | 
|  | 527 | break; | 
|  | 528 | case tok::pp_include: | 
|  | 529 | case tok::pp_import: | 
|  | 530 | case tok::pp_include_next: { | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 531 | // Save the 'include' token. | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 532 | EmitToken(Tok); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 533 | // Lex the next token as an include string. | 
|  | 534 | L.setParsingPreprocessorDirective(true); | 
|  | 535 | L.LexIncludeFilename(Tok); | 
|  | 536 | L.setParsingPreprocessorDirective(false); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 537 | assert(!Tok.isAtStartOfLine()); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 538 | if (Tok.is(tok::identifier)) | 
|  | 539 | Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok)); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 540 |  | 
|  | 541 | break; | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 542 | } | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 543 | case tok::pp_if: | 
|  | 544 | case tok::pp_ifdef: | 
|  | 545 | case tok::pp_ifndef: { | 
| Ted Kremenek | e4f6b1e | 2009-02-10 22:27:09 +0000 | [diff] [blame] | 546 | // Add an entry for '#if' and friends.  We initially set the target | 
|  | 547 | // index to 0.  This will get backpatched when we hit #endif. | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 548 | PPStartCond.push_back(PPCond.size()); | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 549 | PPCond.push_back(std::make_pair(HashOff, 0U)); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 550 | break; | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 551 | } | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 552 | case tok::pp_endif: { | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 553 | // Add an entry for '#endif'.  We set the target table index to itself. | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 554 | // This will later be set to zero when emitting to the PTH file.  We | 
|  | 555 | // use 0 for uninitialized indices because that is easier to debug. | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 556 | unsigned index = PPCond.size(); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 557 | // Backpatch the opening '#if' entry. | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 558 | assert(!PPStartCond.empty()); | 
|  | 559 | assert(PPCond.size() > PPStartCond.back()); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 560 | assert(PPCond[PPStartCond.back()].second == 0); | 
|  | 561 | PPCond[PPStartCond.back()].second = index; | 
|  | 562 | PPStartCond.pop_back(); | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 563 | // Add the new entry to PPCond. | 
|  | 564 | PPCond.push_back(std::make_pair(HashOff, index)); | 
| Ted Kremenek | 726080d | 2009-02-10 22:43:16 +0000 | [diff] [blame] | 565 | EmitToken(Tok); | 
|  | 566 |  | 
|  | 567 | // Some files have gibberish on the same line as '#endif'. | 
|  | 568 | // Discard these tokens. | 
|  | 569 | do L.LexFromRawLexer(Tok); while (!Tok.is(tok::eof) && | 
|  | 570 | !Tok.isAtStartOfLine()); | 
|  | 571 | // We have the next token in hand. | 
|  | 572 | // Don't immediately lex the next one. | 
|  | 573 | goto NextToken; | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 574 | } | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 575 | case tok::pp_elif: | 
|  | 576 | case tok::pp_else: { | 
|  | 577 | // Add an entry for #elif or #else. | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 578 | // This serves as both a closing and opening of a conditional block. | 
|  | 579 | // This means that its entry will get backpatched later. | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 580 | unsigned index = PPCond.size(); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 581 | // Backpatch the previous '#if' entry. | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 582 | assert(!PPStartCond.empty()); | 
|  | 583 | assert(PPCond.size() > PPStartCond.back()); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 584 | assert(PPCond[PPStartCond.back()].second == 0); | 
|  | 585 | PPCond[PPStartCond.back()].second = index; | 
|  | 586 | PPStartCond.pop_back(); | 
|  | 587 | // Now add '#elif' as a new block opening. | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 588 | PPCond.push_back(std::make_pair(HashOff, 0U)); | 
|  | 589 | PPStartCond.push_back(index); | 
| Ted Kremenek | e5680f3 | 2008-12-23 01:30:52 +0000 | [diff] [blame] | 590 | break; | 
|  | 591 | } | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 592 | } | 
| Ted Kremenek | e4f6b1e | 2009-02-10 22:27:09 +0000 | [diff] [blame] | 593 | } | 
|  | 594 |  | 
|  | 595 | EmitToken(Tok); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 596 | } | 
| Ted Kremenek | e4f6b1e | 2009-02-10 22:27:09 +0000 | [diff] [blame] | 597 | while (Tok.isNot(tok::eof)); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 598 |  | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 599 | assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals."); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 600 |  | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 601 | // Next write out PPCond. | 
|  | 602 | Offset PPCondOff = (Offset) Out.tell(); | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 603 |  | 
|  | 604 | // Write out the size of PPCond so that clients can identifer empty tables. | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 605 | Emit32(PPCond.size()); | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 606 |  | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 607 | for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) { | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 608 | Emit32(PPCond[i].first - off); | 
| Ted Kremenek | dad7b34 | 2008-12-12 18:31:09 +0000 | [diff] [blame] | 609 | uint32_t x = PPCond[i].second; | 
|  | 610 | assert(x != 0 && "PPCond entry not backpatched."); | 
|  | 611 | // Emit zero for #endifs.  This allows us to do checking when | 
|  | 612 | // we read the PTH file back in. | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 613 | Emit32(x == i ? 0 : x); | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 614 | } | 
|  | 615 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 616 | return PTHEntry(off, PPCondOff); | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 617 | } | 
|  | 618 |  | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 619 | Offset PTHWriter::EmitCachedSpellings() { | 
|  | 620 | // Write each cached strings to the PTH file. | 
|  | 621 | Offset SpellingsOff = Out.tell(); | 
|  | 622 |  | 
|  | 623 | for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 624 | I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I) | 
|  | 625 | EmitBuf((*I)->getKeyData(), (*I)->getKeyLength()+1 /*nul included*/); | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 626 |  | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 627 | return SpellingsOff; | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 628 | } | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 629 |  | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 630 | void PTHWriter::GeneratePTH(const std::string *MainFile) { | 
| Ted Kremenek | e1b6498 | 2009-01-26 21:43:14 +0000 | [diff] [blame] | 631 | // Generate the prologue. | 
|  | 632 | Out << "cfe-pth"; | 
| Ted Kremenek | 67d1505 | 2009-01-26 21:50:21 +0000 | [diff] [blame] | 633 | Emit32(PTHManager::Version); | 
| Ted Kremenek | a4bd8eb | 2009-02-11 23:34:32 +0000 | [diff] [blame] | 634 |  | 
|  | 635 | // Leave 4 words for the prologue. | 
|  | 636 | Offset PrologueOffset = Out.tell(); | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 637 | for (unsigned i = 0; i < 4; ++i) | 
|  | 638 | Emit32(0); | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 639 |  | 
|  | 640 | // Write the name of the MainFile. | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 641 | if (MainFile && !MainFile->empty()) { | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 642 | Emit16(MainFile->length()); | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 643 | EmitBuf(MainFile->data(), MainFile->length()); | 
|  | 644 | } else { | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 645 | // String with 0 bytes. | 
|  | 646 | Emit16(0); | 
|  | 647 | } | 
|  | 648 | Emit8(0); | 
| Ted Kremenek | e1b6498 | 2009-01-26 21:43:14 +0000 | [diff] [blame] | 649 |  | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 650 | // Iterate over all the files in SourceManager.  Create a lexer | 
|  | 651 | // for each file and cache the tokens. | 
| Chris Lattner | c6fe32a | 2009-01-17 03:48:08 +0000 | [diff] [blame] | 652 | SourceManager &SM = PP.getSourceManager(); | 
|  | 653 | const LangOptions &LOpts = PP.getLangOptions(); | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 654 |  | 
| Chris Lattner | c6fe32a | 2009-01-17 03:48:08 +0000 | [diff] [blame] | 655 | for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(), | 
|  | 656 | E = SM.fileinfo_end(); I != E; ++I) { | 
| Chris Lattner | 0d0bf8c | 2009-02-03 07:30:45 +0000 | [diff] [blame] | 657 | const SrcMgr::ContentCache &C = *I->second; | 
| Chris Lattner | c6fe32a | 2009-01-17 03:48:08 +0000 | [diff] [blame] | 658 | const FileEntry *FE = C.Entry; | 
| Ted Kremenek | fc7e2ea | 2008-12-02 19:44:08 +0000 | [diff] [blame] | 659 |  | 
|  | 660 | // FIXME: Handle files with non-absolute paths. | 
|  | 661 | llvm::sys::Path P(FE->getName()); | 
|  | 662 | if (!P.isAbsolute()) | 
|  | 663 | continue; | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 664 |  | 
| Chris Lattner | c6fe32a | 2009-01-17 03:48:08 +0000 | [diff] [blame] | 665 | const llvm::MemoryBuffer *B = C.getBuffer(); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 666 | if (!B) continue; | 
| Ted Kremenek | fb645b6 | 2008-12-11 23:36:38 +0000 | [diff] [blame] | 667 |  | 
| Chris Lattner | 2b2453a | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 668 | FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); | 
| Chris Lattner | 025c3a6 | 2009-01-17 07:35:14 +0000 | [diff] [blame] | 669 | Lexer L(FID, SM, LOpts); | 
| Ted Kremenek | d8c0292 | 2009-02-10 22:16:22 +0000 | [diff] [blame] | 670 | PM.insert(FE, LexTokens(L)); | 
| Daniel Dunbar | 31309ab | 2008-11-26 02:18:33 +0000 | [diff] [blame] | 671 | } | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 672 |  | 
|  | 673 | // Write out the identifier table. | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 674 | const std::pair<Offset,Offset> &IdTableOff = EmitIdentifierTable(); | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 675 |  | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 676 | // Write out the cached strings table. | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 677 | Offset SpellingOff = EmitCachedSpellings(); | 
| Ted Kremenek | be29533 | 2009-01-08 02:44:06 +0000 | [diff] [blame] | 678 |  | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 679 | // Write out the file table. | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 680 | Offset FileTableOff = EmitFileTable(); | 
| Ted Kremenek | a3d764c | 2008-11-26 03:36:26 +0000 | [diff] [blame] | 681 |  | 
| Ted Kremenek | a4bd8eb | 2009-02-11 23:34:32 +0000 | [diff] [blame] | 682 | // Finally, write the prologue. | 
|  | 683 | Out.seek(PrologueOffset); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 684 | Emit32(IdTableOff.first); | 
| Ted Kremenek | f1de464 | 2009-02-11 16:06:55 +0000 | [diff] [blame] | 685 | Emit32(IdTableOff.second); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 686 | Emit32(FileTableOff); | 
| Ted Kremenek | 277faca | 2009-01-27 00:01:05 +0000 | [diff] [blame] | 687 | Emit32(SpellingOff); | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 688 | } | 
|  | 689 |  | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 690 | void clang::CacheTokens(Preprocessor &PP, const std::string &OutFile) { | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 691 | // Open up the PTH file. | 
|  | 692 | std::string ErrMsg; | 
|  | 693 | llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg); | 
|  | 694 |  | 
|  | 695 | if (!ErrMsg.empty()) { | 
|  | 696 | llvm::errs() << "PTH error: " << ErrMsg << "\n"; | 
|  | 697 | return; | 
|  | 698 | } | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 699 |  | 
|  | 700 | // Get the name of the main file. | 
|  | 701 | const SourceManager &SrcMgr = PP.getSourceManager(); | 
|  | 702 | const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID()); | 
|  | 703 | llvm::sys::Path MainFilePath(MainFile->getName()); | 
|  | 704 | std::string MainFileName; | 
|  | 705 |  | 
|  | 706 | if (!MainFilePath.isAbsolute()) { | 
|  | 707 | llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory(); | 
|  | 708 | P.appendComponent(MainFilePath.toString()); | 
|  | 709 | MainFileName = P.toString(); | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 710 | } else { | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 711 | MainFileName = MainFilePath.toString(); | 
|  | 712 | } | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 713 |  | 
|  | 714 | // Create the PTHWriter. | 
| Ted Kremenek | b978c66 | 2009-01-08 01:17:37 +0000 | [diff] [blame] | 715 | PTHWriter PW(Out, PP); | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 716 |  | 
|  | 717 | // Install the 'stat' system call listener in the FileManager. | 
|  | 718 | PP.getFileManager().setStatCache(PW.createStatListener()); | 
|  | 719 |  | 
|  | 720 | // Lex through the entire file.  This will populate SourceManager with | 
|  | 721 | // all of the header information. | 
|  | 722 | Token Tok; | 
|  | 723 | PP.EnterMainSourceFile(); | 
|  | 724 | do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); | 
|  | 725 |  | 
| Ted Kremenek | ad6ce5c | 2009-02-13 22:07:44 +0000 | [diff] [blame] | 726 | // Generate the PTH file. | 
|  | 727 | PP.getFileManager().setStatCache(0); | 
| Ted Kremenek | d5cded4 | 2009-03-19 22:10:38 +0000 | [diff] [blame] | 728 | PW.GeneratePTH(&MainFileName); | 
| Ted Kremenek | 8588896 | 2008-10-21 00:54:44 +0000 | [diff] [blame] | 729 | } | 
| Ted Kremenek | e0ea5dc | 2009-02-10 01:06:17 +0000 | [diff] [blame] | 730 |  | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 731 | //===----------------------------------------------------------------------===// | 
|  | 732 |  | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 733 | class PTHIdKey { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 734 | public: | 
|  | 735 | const IdentifierInfo* II; | 
|  | 736 | uint32_t FileOffset; | 
|  | 737 | }; | 
|  | 738 |  | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 739 | namespace { | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 740 | class VISIBILITY_HIDDEN PTHIdentifierTableTrait { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 741 | public: | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 742 | typedef PTHIdKey* key_type; | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 743 | typedef key_type  key_type_ref; | 
|  | 744 |  | 
|  | 745 | typedef uint32_t  data_type; | 
|  | 746 | typedef data_type data_type_ref; | 
|  | 747 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 748 | static unsigned ComputeHash(PTHIdKey* key) { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 749 | return BernsteinHash(key->II->getName()); | 
|  | 750 | } | 
|  | 751 |  | 
|  | 752 | static std::pair<unsigned,unsigned> | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 753 | EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 754 | unsigned n = strlen(key->II->getName()) + 1; | 
|  | 755 | ::Emit16(Out, n); | 
|  | 756 | return std::make_pair(n, sizeof(uint32_t)); | 
|  | 757 | } | 
|  | 758 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 759 | static void EmitKey(llvm::raw_fd_ostream& Out, PTHIdKey* key, unsigned n) { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 760 | // Record the location of the key data.  This is used when generating | 
|  | 761 | // the mapping from persistent IDs to strings. | 
|  | 762 | key->FileOffset = Out.tell(); | 
|  | 763 | Out.write(key->II->getName(), n); | 
|  | 764 | } | 
|  | 765 |  | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 766 | static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID, | 
| Ted Kremenek | 337edcd | 2009-02-12 03:26:59 +0000 | [diff] [blame] | 767 | unsigned) { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 768 | ::Emit32(Out, pID); | 
|  | 769 | } | 
|  | 770 | }; | 
|  | 771 | } // end anonymous namespace | 
|  | 772 |  | 
|  | 773 | /// EmitIdentifierTable - Emits two tables to the PTH file.  The first is | 
|  | 774 | ///  a hashtable mapping from identifier strings to persistent IDs.  The second | 
|  | 775 | ///  is a straight table mapping from persistent IDs to string data (the | 
|  | 776 | ///  keys of the first table). | 
|  | 777 | /// | 
|  | 778 | std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() { | 
|  | 779 | // Build two maps: | 
|  | 780 | //  (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset) | 
|  | 781 | //  (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs | 
|  | 782 |  | 
|  | 783 | // Note that we use 'calloc', so all the bytes are 0. | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 784 | PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey)); | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 785 |  | 
|  | 786 | // Create the hashtable. | 
| Ted Kremenek | a4b44dd | 2009-02-13 19:13:46 +0000 | [diff] [blame] | 787 | OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap; | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 788 |  | 
|  | 789 | // Generate mapping from persistent IDs -> IdentifierInfo*. | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 790 | for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) { | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 791 | // Decrement by 1 because we are using a vector for the lookup and | 
|  | 792 | // 0 is reserved for NULL. | 
|  | 793 | assert(I->second > 0); | 
|  | 794 | assert(I->second-1 < idcount); | 
|  | 795 | unsigned idx = I->second-1; | 
|  | 796 |  | 
|  | 797 | // Store the mapping from persistent ID to IdentifierInfo* | 
|  | 798 | IIDMap[idx].II = I->first; | 
|  | 799 |  | 
|  | 800 | // Store the reverse mapping in a hashtable. | 
|  | 801 | IIOffMap.insert(&IIDMap[idx], I->second); | 
|  | 802 | } | 
|  | 803 |  | 
|  | 804 | // Write out the inverse map first.  This causes the PCIDKey entries to | 
|  | 805 | // record PTH file offsets for the string data.  This is used to write | 
|  | 806 | // the second table. | 
|  | 807 | Offset StringTableOffset = IIOffMap.Emit(Out); | 
|  | 808 |  | 
|  | 809 | // Now emit the table mapping from persistent IDs to PTH file offsets. | 
|  | 810 | Offset IDOff = Out.tell(); | 
|  | 811 | Emit32(idcount);  // Emit the number of identifiers. | 
| Chris Lattner | f239036 | 2009-03-28 00:16:20 +0000 | [diff] [blame^] | 812 | for (unsigned i = 0 ; i < idcount; ++i) | 
|  | 813 | Emit32(IIDMap[i].FileOffset); | 
| Ted Kremenek | 7e3a004 | 2009-02-11 21:29:16 +0000 | [diff] [blame] | 814 |  | 
|  | 815 | // Finally, release the inverse map. | 
|  | 816 | free(IIDMap); | 
|  | 817 |  | 
|  | 818 | return std::make_pair(IDOff, StringTableOffset); | 
|  | 819 | } |