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