blob: 5aeb1a6da36c7e700bcb10aefcffe8f085cc697f [file] [log] [blame]
Ted Kremenek85888962008-10-21 00:54:44 +00001//===--- CacheTokens.cpp - Caching of lexer tokens for PCH support --------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This provides a possible implementation of PCH support for Clang that is
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"
22#include "llvm/Support/MemoryBuffer.h"
23#include "llvm/Support/raw_ostream.h"
24
25using namespace clang;
26
27typedef llvm::DenseMap<const FileEntry*,uint64_t> PCHMap;
28typedef llvm::DenseMap<const IdentifierInfo*,uint64_t> IDMap;
29
30static void Emit32(llvm::raw_ostream& Out, uint32_t V) {
31 Out << (unsigned char)(V);
32 Out << (unsigned char)(V >> 8);
33 Out << (unsigned char)(V >> 16);
34 Out << (unsigned char)(V >> 24);
35}
36
37static void Emit8(llvm::raw_ostream& Out, uint32_t V) {
38 Out << (unsigned char)(V);
39}
40
41static void EmitBuf(llvm::raw_ostream& Out, const char* I, const char* E) {
42 for ( ; I != E ; ++I) Out << *I;
43}
44
45static uint32_t ResolveID(IDMap& IM, uint32_t& idx, const IdentifierInfo* II) {
46 IDMap::iterator I = IM.find(II);
47
48 if (I == IM.end()) {
49 IM[II] = idx;
50 return idx++;
51 }
52
53 return I->second;
54}
55
56static void EmitToken(llvm::raw_ostream& Out, const Token& T,
57 uint32_t& idcount, IDMap& IM) {
58 Emit8(Out, T.getKind());
59 Emit8(Out, T.getFlags());
60 Emit32(Out, ResolveID(IM, idcount, T.getIdentifierInfo()));
61 Emit32(Out, T.getLocation().getRawEncoding());
62 Emit32(Out, T.getLength());
63}
64
65
66static void EmitIdentifier(llvm::raw_ostream& Out, const IdentifierInfo& II) {
67 uint32_t X = (uint32_t) II.getTokenID() << 19;
68 X |= (uint32_t) II.getBuiltinID() << 9;
69 X |= (uint32_t) II.getObjCKeywordID() << 4;
70 if (II.hasMacroDefinition()) X |= 0x8;
71 if (II.isExtensionToken()) X |= 0x4;
72 if (II.isPoisoned()) X |= 0x2;
73 if (II.isCPlusPlusOperatorKeyword()) X |= 0x1;
74
75 Emit32(Out, X);
76}
77
78static void EmitIdentifierTable(llvm::raw_ostream& Out,
79 const IdentifierTable& T, const IDMap& IM) {
80
81 for (IdentifierTable::const_iterator I=T.begin(), E=T.end(); I!=E; ++I) {
82 const IdentifierInfo& II = I->getValue();
83
84 // Write out the persistent identifier.
85 IDMap::const_iterator IItr = IM.find(&II);
86 if (IItr == IM.end()) continue;
87 Emit32(Out, IItr->second);
88 EmitIdentifier(Out, II);
89
90 // Write out the keyword.
91 unsigned len = I->getKeyLength();
92 Emit32(Out, len);
93 const char* buf = I->getKeyData();
94 EmitBuf(Out, buf, buf+len);
95 }
96}
97
98
99void clang::CacheTokens(Preprocessor& PP, const std::string& OutFile) {
100 // Lex through the entire file. This will populate SourceManager with
101 // all of the header information.
102 Token Tok;
103 PP.EnterMainSourceFile();
104 do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
105
106 // Iterate over all the files in SourceManager. Create a lexer
107 // for each file and cache the tokens.
108 SourceManager& SM = PP.getSourceManager();
109 const LangOptions& LOpts = PP.getLangOptions();
110 llvm::raw_ostream& os = llvm::errs();
111
112 PCHMap PM;
113 IDMap IM;
114 uint64_t tokIdx = 0;
115 uint32_t idcount = 0;
116
117 std::string ErrMsg;
118 llvm::raw_fd_ostream Out(OutFile.c_str(), ErrMsg);
119
120 if (!ErrMsg.empty()) {
121 os << "PCH error: " << ErrMsg << "\n";
122 return;
123 }
124
125 for (SourceManager::fileid_iterator I=SM.fileid_begin(), E=SM.fileid_end();
126 I!=E; ++I) {
127
128 const SrcMgr::ContentCache* C = I.getFileIDInfo().getContentCache();
129
130 if (!C)
131 continue;
132
133 const FileEntry* FE = C->Entry;
134
135 if (!FE)
136 continue;
137
138 PCHMap::iterator PI = PM.find(FE);
139 if (PI != PM.end()) continue;
140 PM[FE] = tokIdx;
141
142 // os << "Processing: " << FE->getName() << " : " << tokIdx << "\n";
143
144 const llvm::MemoryBuffer* B = C->Buffer;
145
146 if (!B)
147 continue;
148
149 // Create a raw lexer.
150 Lexer L(SourceLocation::getFileLoc(I.getFileID(), 0), LOpts,
151 B->getBufferStart(), B->getBufferEnd(), B);
152
153 // Ignore whitespace.
154 L.SetKeepWhitespaceMode(false);
155 L.SetCommentRetentionState(false);
156
157 // Lex the file, populating our data structures.
158 Token Tok;
159 L.LexFromRawLexer(Tok);
160
161 while (Tok.isNot(tok::eof)) {
162 ++tokIdx;
163
164 if (Tok.is(tok::identifier))
165 Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok));
166
167 // Write the token to disk.
168 EmitToken(Out, Tok, idcount, IM);
169
170 // Lex the next token.
171 L.LexFromRawLexer(Tok);
172 }
173 }
174
175 // Now, write out the identifier table.
176 EmitIdentifierTable(Out, PP.getIdentifierTable(), IM);
177}