blob: b1923982803d2e0843989892b407a8c2353bcb3d [file] [log] [blame]
Douglas Gregora6b00fc2013-01-23 22:38:11 +00001//===--- GlobalModuleIndex.cpp - Global Module Index ------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the GlobalModuleIndex class.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTReaderInternals.h"
15#include "clang/Basic/FileManager.h"
16#include "clang/Basic/OnDiskHashTable.h"
17#include "clang/Serialization/ASTBitCodes.h"
18#include "clang/Serialization/GlobalModuleIndex.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/MapVector.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Bitcode/BitstreamReader.h"
24#include "llvm/Bitcode/BitstreamWriter.h"
Douglas Gregor51001352013-01-23 22:45:24 +000025#include "llvm/Support/FileSystem.h"
Douglas Gregora6b00fc2013-01-23 22:38:11 +000026#include "llvm/Support/LockFileManager.h"
27#include "llvm/Support/MemoryBuffer.h"
28#include "llvm/Support/PathV2.h"
NAKAMURA Takumi1d321332013-01-25 01:47:07 +000029#include <cstdio>
Douglas Gregora6b00fc2013-01-23 22:38:11 +000030using namespace clang;
31using namespace serialization;
32
33//----------------------------------------------------------------------------//
34// Shared constants
35//----------------------------------------------------------------------------//
36namespace {
37 enum {
38 /// \brief The block containing the index.
39 GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
40 };
41
42 /// \brief Describes the record types in the index.
43 enum IndexRecordTypes {
44 /// \brief Contains version information and potentially other metadata,
45 /// used to determine if we can read this global index file.
Douglas Gregor1a49d972013-01-25 01:03:03 +000046 INDEX_METADATA,
Douglas Gregora6b00fc2013-01-23 22:38:11 +000047 /// \brief Describes a module, including its file name and dependencies.
48 MODULE,
49 /// \brief The index for identifiers.
50 IDENTIFIER_INDEX
51 };
52}
53
54/// \brief The name of the global index file.
55static const char * const IndexFileName = "modules.idx";
56
57/// \brief The global index file version.
58static const unsigned CurrentVersion = 1;
59
60//----------------------------------------------------------------------------//
Douglas Gregor1a49d972013-01-25 01:03:03 +000061// Global module index reader.
62//----------------------------------------------------------------------------//
63
64namespace {
65
66/// \brief Trait used to read the identifier index from the on-disk hash
67/// table.
68class IdentifierIndexReaderTrait {
69public:
70 typedef StringRef external_key_type;
71 typedef StringRef internal_key_type;
72 typedef SmallVector<unsigned, 2> data_type;
73
74 static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
75 return a == b;
76 }
77
78 static unsigned ComputeHash(const internal_key_type& a) {
79 return llvm::HashString(a);
80 }
81
82 static std::pair<unsigned, unsigned>
83 ReadKeyDataLength(const unsigned char*& d) {
84 using namespace clang::io;
85 unsigned KeyLen = ReadUnalignedLE16(d);
86 unsigned DataLen = ReadUnalignedLE16(d);
87 return std::make_pair(KeyLen, DataLen);
88 }
89
90 static const internal_key_type&
91 GetInternalKey(const external_key_type& x) { return x; }
92
93 static const external_key_type&
94 GetExternalKey(const internal_key_type& x) { return x; }
95
96 static internal_key_type ReadKey(const unsigned char* d, unsigned n) {
97 return StringRef((const char *)d, n);
98 }
99
100 static data_type ReadData(const internal_key_type& k,
101 const unsigned char* d,
102 unsigned DataLen) {
103 using namespace clang::io;
104
105 data_type Result;
106 while (DataLen > 0) {
107 unsigned ID = ReadUnalignedLE32(d);
108 Result.push_back(ID);
109 DataLen -= 4;
110 }
111
112 return Result;
113 }
114};
115
116typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable;
117
118/// \brief Module information as it was loaded from the index file.
119struct LoadedModuleInfo {
120 const FileEntry *File;
121 SmallVector<unsigned, 2> Dependencies;
122 SmallVector<unsigned, 2> ImportedBy;
123};
124
125}
126
127GlobalModuleIndex::GlobalModuleIndex(FileManager &FileMgr,
128 llvm::MemoryBuffer *Buffer,
129 llvm::BitstreamCursor Cursor)
130 : Buffer(Buffer), IdentifierIndex()
131{
132 typedef llvm::DenseMap<unsigned, LoadedModuleInfo> LoadedModulesMap;
133 LoadedModulesMap LoadedModules;
134
135 // Read the global index.
136 unsigned LargestID = 0;
137 bool InGlobalIndexBlock = false;
138 bool Done = false;
139 bool AnyOutOfDate = false;
140 while (!Done) {
141 llvm::BitstreamEntry Entry = Cursor.advance();
142
143 switch (Entry.Kind) {
144 case llvm::BitstreamEntry::Error:
145 return;
146
147 case llvm::BitstreamEntry::EndBlock:
148 if (InGlobalIndexBlock) {
149 InGlobalIndexBlock = false;
150 Done = true;
151 continue;
152 }
153 return;
154
155
156 case llvm::BitstreamEntry::Record:
157 // Entries in the global index block are handled below.
158 if (InGlobalIndexBlock)
159 break;
160
161 return;
162
163 case llvm::BitstreamEntry::SubBlock:
164 if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
165 if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
166 return;
167
168 InGlobalIndexBlock = true;
169 } else if (Cursor.SkipBlock()) {
170 return;
171 }
172 continue;
173 }
174
175 SmallVector<uint64_t, 64> Record;
176 StringRef Blob;
177 switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) {
178 case INDEX_METADATA:
179 // Make sure that the version matches.
180 if (Record.size() < 1 || Record[0] != CurrentVersion)
181 return;
182 break;
183
184 case MODULE: {
185 unsigned Idx = 0;
186 unsigned ID = Record[Idx++];
187 if (ID > LargestID)
188 LargestID = ID;
189
190 off_t Size = Record[Idx++];
191 time_t ModTime = Record[Idx++];
192
193 // File name.
194 unsigned NameLen = Record[Idx++];
195 llvm::SmallString<64> FileName(Record.begin() + Idx,
196 Record.begin() + Idx + NameLen);
197 Idx += NameLen;
198
199 // Dependencies
200 unsigned NumDeps = Record[Idx++];
201 llvm::SmallVector<unsigned, 2>
202 Dependencies(Record.begin() + Idx, Record.begin() + Idx + NumDeps);
203
204 // Find the file. If we can't find it, ignore it.
205 const FileEntry *File = FileMgr.getFile(FileName);
206 if (!File) {
207 AnyOutOfDate = true;
208 break;
209 }
210
211 // If the module file is newer than the index, ignore it.
212 if (File->getSize() != Size || File->getModificationTime() != ModTime) {
213 AnyOutOfDate = true;
214 break;
215 }
216
217 // Record this module. The dependencies will be resolved later.
218 LoadedModuleInfo &Info = LoadedModules[ID];
219 Info.File = File;
220 Info.Dependencies.swap(Dependencies);
221 break;
222 }
223
224 case IDENTIFIER_INDEX:
225 // Wire up the identifier index.
226 if (Record[0]) {
227 IdentifierIndex = IdentifierIndexTable::Create(
228 (const unsigned char *)Blob.data() + Record[0],
229 (const unsigned char *)Blob.data(),
230 IdentifierIndexReaderTrait());
231 }
232 break;
233 }
234 }
235
236 // If there are any modules that have gone out-of-date, prune out any modules
237 // that depend on them.
238 if (AnyOutOfDate) {
239 // First, build back links in the module dependency graph.
240 SmallVector<unsigned, 4> Stack;
241 for (LoadedModulesMap::iterator LM = LoadedModules.begin(),
242 LMEnd = LoadedModules.end();
243 LM != LMEnd; ++LM) {
244 unsigned ID = LM->first;
245
246 // If this module is out-of-date, push it onto the stack.
247 if (LM->second.File == 0)
248 Stack.push_back(ID);
249
250 for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) {
251 unsigned DepID = LM->second.Dependencies[I];
252 LoadedModulesMap::iterator Known = LoadedModules.find(DepID);
253 if (Known == LoadedModules.end() || !Known->second.File) {
254 // The dependency was out-of-date, so mark us as out of date.
255 // This is just an optimization.
256 if (LM->second.File)
257 Stack.push_back(ID);
258
259 LM->second.File = 0;
260 continue;
261 }
262
263 // Record this reverse dependency.
264 Known->second.ImportedBy.push_back(ID);
265 }
266 }
267
268 // Second, walk the back links from out-of-date modules to those modules
269 // that depend on them, making those modules out-of-date as well.
270 while (!Stack.empty()) {
271 unsigned ID = Stack.back();
272 Stack.pop_back();
273
274 LoadedModuleInfo &Info = LoadedModules[ID];
275 for (unsigned I = 0, N = Info.ImportedBy.size(); I != N; ++I) {
276 unsigned FromID = Info.ImportedBy[I];
277 if (LoadedModules[FromID].File) {
278 LoadedModules[FromID].File = 0;
279 Stack.push_back(FromID);
280 }
281 }
282 }
283 }
284
285 // Allocate the vector containing information about all of the modules.
286 Modules.resize(LargestID + 1);
287 for (LoadedModulesMap::iterator LM = LoadedModules.begin(),
288 LMEnd = LoadedModules.end();
289 LM != LMEnd; ++LM) {
290 if (!LM->second.File)
291 continue;
292
293 Modules[LM->first].File = LM->second.File;
294
295 // Resolve dependencies. Drop any we can't resolve due to out-of-date
296 // module files.
297 for (unsigned I = 0, N = LM->second.Dependencies.size(); I != N; ++I) {
298 unsigned DepID = LM->second.Dependencies[I];
299 LoadedModulesMap::iterator Known = LoadedModules.find(DepID);
300 if (Known == LoadedModules.end() || !Known->second.File)
301 continue;
302
303 Modules[LM->first].Dependencies.push_back(Known->second.File);
304 }
305 }
306}
307
308GlobalModuleIndex::~GlobalModuleIndex() { }
309
310std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode>
311GlobalModuleIndex::readIndex(FileManager &FileMgr, StringRef Path) {
312 // Load the index file, if it's there.
313 llvm::SmallString<128> IndexPath;
314 IndexPath += Path;
315 llvm::sys::path::append(IndexPath, IndexFileName);
316
317 llvm::OwningPtr<llvm::MemoryBuffer> Buffer(
318 FileMgr.getBufferForFile(IndexPath));
319 if (!Buffer)
320 return std::make_pair((GlobalModuleIndex *)0, EC_NotFound);
321
322 /// \brief The bitstream reader from which we'll read the AST file.
323 llvm::BitstreamReader Reader((const unsigned char *)Buffer->getBufferStart(),
324 (const unsigned char *)Buffer->getBufferEnd());
325
326 /// \brief The main bitstream cursor for the main block.
327 llvm::BitstreamCursor Cursor(Reader);
328
329 // Sniff for the signature.
330 if (Cursor.Read(8) != 'B' ||
331 Cursor.Read(8) != 'C' ||
332 Cursor.Read(8) != 'G' ||
333 Cursor.Read(8) != 'I') {
334 return std::make_pair((GlobalModuleIndex *)0, EC_IOError);
335 }
336
337 return std::make_pair(new GlobalModuleIndex(FileMgr, Buffer.take(), Cursor),
338 EC_None);
339}
340
341void GlobalModuleIndex::getKnownModules(
342 SmallVectorImpl<const FileEntry *> &ModuleFiles) {
343 ModuleFiles.clear();
344 for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
345 if (Modules[I].File)
346 ModuleFiles.push_back(Modules[I].File);
347 }
348}
349
350void GlobalModuleIndex::getModuleDependencies(
351 const clang::FileEntry *ModuleFile,
352 SmallVectorImpl<const clang::FileEntry *> &Dependencies) {
353 // If the file -> index mapping is empty, populate it now.
354 if (ModulesByFile.empty()) {
355 for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
356 if (Modules[I].File)
357 ModulesByFile[Modules[I].File] = I;
358 }
359 }
360
361 // Look for information about this module file.
362 llvm::DenseMap<const FileEntry *, unsigned>::iterator Known
363 = ModulesByFile.find(ModuleFile);
364 if (Known == ModulesByFile.end())
365 return;
366
367 // Record dependencies.
368 Dependencies = Modules[Known->second].Dependencies;
369}
370
371bool GlobalModuleIndex::lookupIdentifier(
372 StringRef Name,
373 SmallVectorImpl<const FileEntry *> &ModuleFiles) {
374 ModuleFiles.clear();
375
376 // If there's no identifier index, there is nothing we can do.
377 if (!IdentifierIndex)
378 return false;
379
380 // Look into the identifier index.
381 ++NumIdentifierLookups;
382 IdentifierIndexTable &Table
383 = *static_cast<IdentifierIndexTable *>(IdentifierIndex);
384 IdentifierIndexTable::iterator Known = Table.find(Name);
385 if (Known == Table.end()) {
386 return true;
387 }
388
389 SmallVector<unsigned, 2> ModuleIDs = *Known;
390 for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {
391 unsigned ID = ModuleIDs[I];
392 if (ID >= Modules.size() || !Modules[ID].File)
393 continue;
394
395 ModuleFiles.push_back(Modules[ID].File);
396 }
397
398 ++NumIdentifierLookupHits;
399 return true;
400}
401
402GlobalModuleIndex::SkipSet
403GlobalModuleIndex::computeSkipSet(
404 const SmallVectorImpl<const FileEntry *> &ModuleFiles) {
405 llvm::SmallPtrSet<const FileEntry *, 8> Found(ModuleFiles.begin(),
406 ModuleFiles.end());
407
408 SkipSet Result;
409 for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
410 if (Modules[I].File && !Found.count(Modules[I].File))
411 Result.insert(Modules[I].File);
412 }
413
414 NumIdentifierModulesSkipped += Result.size();
415 return Result;
416}
417
418void GlobalModuleIndex::printStats() {
419 std::fprintf(stderr, "*** Global Module Index Statistics:\n");
420 if (NumIdentifierLookups) {
421 fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n",
422 NumIdentifierLookupHits, NumIdentifierLookups,
423 (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
424 }
425 if (NumIdentifierLookups && NumIdentifierModulesSkipped) {
426 fprintf(stderr, " %f modules skipped per lookup (on average)\n",
427 (double)NumIdentifierModulesSkipped/NumIdentifierLookups);
428 }
429 std::fprintf(stderr, "\n");
430}
431
432//----------------------------------------------------------------------------//
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000433// Global module index writer.
434//----------------------------------------------------------------------------//
435
436namespace {
437 /// \brief Provides information about a specific module file.
438 struct ModuleFileInfo {
439 /// \brief The numberic ID for this module file.
440 unsigned ID;
441
442 /// \brief The set of modules on which this module depends. Each entry is
443 /// a module ID.
444 SmallVector<unsigned, 4> Dependencies;
445 };
446
447 /// \brief Builder that generates the global module index file.
448 class GlobalModuleIndexBuilder {
449 FileManager &FileMgr;
450
451 /// \brief Mapping from files to module file information.
452 typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
453
454 /// \brief Information about each of the known module files.
455 ModuleFilesMap ModuleFiles;
456
457 /// \brief Mapping from identifiers to the list of module file IDs that
458 /// consider this identifier to be interesting.
459 typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
460
461 /// \brief A mapping from all interesting identifiers to the set of module
462 /// files in which those identifiers are considered interesting.
463 InterestingIdentifierMap InterestingIdentifiers;
464
465 /// \brief Write the block-info block for the global module index file.
466 void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
467
468 /// \brief Retrieve the module file information for the given file.
469 ModuleFileInfo &getModuleFileInfo(const FileEntry *File) {
470 llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known
471 = ModuleFiles.find(File);
472 if (Known != ModuleFiles.end())
473 return Known->second;
474
475 unsigned NewID = ModuleFiles.size();
476 ModuleFileInfo &Info = ModuleFiles[File];
477 Info.ID = NewID;
478 return Info;
479 }
480
481 public:
482 explicit GlobalModuleIndexBuilder(FileManager &FileMgr) : FileMgr(FileMgr){}
483
484 /// \brief Load the contents of the given module file into the builder.
485 ///
486 /// \returns true if an error occurred, false otherwise.
487 bool loadModuleFile(const FileEntry *File);
488
489 /// \brief Write the index to the given bitstream.
490 void writeIndex(llvm::BitstreamWriter &Stream);
491 };
492}
493
494static void emitBlockID(unsigned ID, const char *Name,
495 llvm::BitstreamWriter &Stream,
496 SmallVectorImpl<uint64_t> &Record) {
497 Record.clear();
498 Record.push_back(ID);
499 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
500
501 // Emit the block name if present.
502 if (Name == 0 || Name[0] == 0) return;
503 Record.clear();
504 while (*Name)
505 Record.push_back(*Name++);
506 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
507}
508
509static void emitRecordID(unsigned ID, const char *Name,
510 llvm::BitstreamWriter &Stream,
511 SmallVectorImpl<uint64_t> &Record) {
512 Record.clear();
513 Record.push_back(ID);
514 while (*Name)
515 Record.push_back(*Name++);
516 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
517}
518
519void
520GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
521 SmallVector<uint64_t, 64> Record;
522 Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
523
524#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
525#define RECORD(X) emitRecordID(X, #X, Stream, Record)
526 BLOCK(GLOBAL_INDEX_BLOCK);
Douglas Gregor1a49d972013-01-25 01:03:03 +0000527 RECORD(INDEX_METADATA);
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000528 RECORD(MODULE);
529 RECORD(IDENTIFIER_INDEX);
530#undef RECORD
531#undef BLOCK
532
533 Stream.ExitBlock();
534}
535
Douglas Gregor1a49d972013-01-25 01:03:03 +0000536namespace {
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000537 class InterestingASTIdentifierLookupTrait
538 : public serialization::reader::ASTIdentifierLookupTraitBase {
539
540 public:
541 /// \brief The identifier and whether it is "interesting".
542 typedef std::pair<StringRef, bool> data_type;
543
544 data_type ReadData(const internal_key_type& k,
545 const unsigned char* d,
546 unsigned DataLen) {
547 // The first bit indicates whether this identifier is interesting.
548 // That's all we care about.
549 using namespace clang::io;
550 unsigned RawID = ReadUnalignedLE32(d);
551 bool IsInteresting = RawID & 0x01;
552 return std::make_pair(k, IsInteresting);
553 }
554 };
555}
556
557bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
558 // Open the module file.
559 OwningPtr<llvm::MemoryBuffer> Buffer;
560 Buffer.reset(FileMgr.getBufferForFile(File));
561 if (!Buffer) {
562 return true;
563 }
564
565 // Initialize the input stream
566 llvm::BitstreamReader InStreamFile;
567 llvm::BitstreamCursor InStream;
568 InStreamFile.init((const unsigned char *)Buffer->getBufferStart(),
569 (const unsigned char *)Buffer->getBufferEnd());
570 InStream.init(InStreamFile);
571
572 // Sniff for the signature.
573 if (InStream.Read(8) != 'C' ||
574 InStream.Read(8) != 'P' ||
575 InStream.Read(8) != 'C' ||
576 InStream.Read(8) != 'H') {
577 return true;
578 }
579
580 // Record this module file and assign it a unique ID (if it doesn't have
581 // one already).
582 unsigned ID = getModuleFileInfo(File).ID;
583
584 // Search for the blocks and records we care about.
Douglas Gregor1a49d972013-01-25 01:03:03 +0000585 enum { Other, ControlBlock, ASTBlock } State = Other;
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000586 bool Done = false;
587 while (!Done) {
Douglas Gregor1a49d972013-01-25 01:03:03 +0000588 llvm::BitstreamEntry Entry = InStream.advance();
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000589 switch (Entry.Kind) {
590 case llvm::BitstreamEntry::Error:
Douglas Gregor1a49d972013-01-25 01:03:03 +0000591 Done = true;
592 continue;
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000593
594 case llvm::BitstreamEntry::Record:
Douglas Gregor1a49d972013-01-25 01:03:03 +0000595 // In the 'other' state, just skip the record. We don't care.
596 if (State == Other) {
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000597 InStream.skipRecord(Entry.ID);
598 continue;
599 }
600
601 // Handle potentially-interesting records below.
602 break;
603
604 case llvm::BitstreamEntry::SubBlock:
Douglas Gregor1a49d972013-01-25 01:03:03 +0000605 if (Entry.ID == CONTROL_BLOCK_ID) {
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000606 if (InStream.EnterSubBlock(CONTROL_BLOCK_ID))
607 return true;
608
609 // Found the control block.
610 State = ControlBlock;
611 continue;
612 }
613
Douglas Gregor1a49d972013-01-25 01:03:03 +0000614 if (Entry.ID == AST_BLOCK_ID) {
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000615 if (InStream.EnterSubBlock(AST_BLOCK_ID))
616 return true;
617
618 // Found the AST block.
619 State = ASTBlock;
620 continue;
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000621 }
622
623 if (InStream.SkipBlock())
624 return true;
625
626 continue;
627
628 case llvm::BitstreamEntry::EndBlock:
Douglas Gregor1a49d972013-01-25 01:03:03 +0000629 State = Other;
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000630 continue;
631 }
632
633 // Read the given record.
634 SmallVector<uint64_t, 64> Record;
635 StringRef Blob;
636 unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob);
637
638 // Handle module dependencies.
639 if (State == ControlBlock && Code == IMPORTS) {
640 // Load each of the imported PCH files.
641 unsigned Idx = 0, N = Record.size();
642 while (Idx < N) {
643 // Read information about the AST file.
644
645 // Skip the imported kind
646 ++Idx;
647
648 // Skip the import location
649 ++Idx;
650
651 // Retrieve the imported file name.
652 unsigned Length = Record[Idx++];
653 SmallString<128> ImportedFile(Record.begin() + Idx,
654 Record.begin() + Idx + Length);
655 Idx += Length;
656
657 // Find the imported module file.
658 const FileEntry *DependsOnFile = FileMgr.getFile(ImportedFile);
659 if (!DependsOnFile)
660 return true;
661
662 // Record the dependency.
663 unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
664 getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
665 }
666
667 continue;
668 }
669
670 // Handle the identifier table
671 if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
672 typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait>
673 InterestingIdentifierTable;
674 llvm::OwningPtr<InterestingIdentifierTable>
675 Table(InterestingIdentifierTable::Create(
676 (const unsigned char *)Blob.data() + Record[0],
677 (const unsigned char *)Blob.data()));
678 for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
679 DEnd = Table->data_end();
680 D != DEnd; ++D) {
681 std::pair<StringRef, bool> Ident = *D;
682 if (Ident.second)
683 InterestingIdentifiers[Ident.first].push_back(ID);
Douglas Gregor1a49d972013-01-25 01:03:03 +0000684 else
685 (void)InterestingIdentifiers[Ident.first];
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000686 }
687 }
688
689 // FIXME: Handle the selector table.
690
691 // We don't care about this record.
692 }
693
694 return false;
695}
696
697namespace {
698
699/// \brief Trait used to generate the identifier index as an on-disk hash
700/// table.
701class IdentifierIndexWriterTrait {
702public:
703 typedef StringRef key_type;
704 typedef StringRef key_type_ref;
705 typedef SmallVector<unsigned, 2> data_type;
706 typedef const SmallVector<unsigned, 2> &data_type_ref;
707
708 static unsigned ComputeHash(key_type_ref Key) {
709 return llvm::HashString(Key);
710 }
711
712 std::pair<unsigned,unsigned>
713 EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {
714 unsigned KeyLen = Key.size();
715 unsigned DataLen = Data.size() * 4;
716 clang::io::Emit16(Out, KeyLen);
717 clang::io::Emit16(Out, DataLen);
718 return std::make_pair(KeyLen, DataLen);
719 }
720
721 void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
722 Out.write(Key.data(), KeyLen);
723 }
724
725 void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
726 unsigned DataLen) {
727 for (unsigned I = 0, N = Data.size(); I != N; ++I)
728 clang::io::Emit32(Out, Data[I]);
729 }
730};
731
732}
733
734void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
735 using namespace llvm;
736
737 // Emit the file header.
738 Stream.Emit((unsigned)'B', 8);
739 Stream.Emit((unsigned)'C', 8);
740 Stream.Emit((unsigned)'G', 8);
741 Stream.Emit((unsigned)'I', 8);
742
743 // Write the block-info block, which describes the records in this bitcode
744 // file.
745 emitBlockInfoBlock(Stream);
746
747 Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
748
749 // Write the metadata.
750 SmallVector<uint64_t, 2> Record;
751 Record.push_back(CurrentVersion);
Douglas Gregor1a49d972013-01-25 01:03:03 +0000752 Stream.EmitRecord(INDEX_METADATA, Record);
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000753
754 // Write the set of known module files.
755 for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
756 MEnd = ModuleFiles.end();
757 M != MEnd; ++M) {
758 Record.clear();
759 Record.push_back(M->second.ID);
760 Record.push_back(M->first->getSize());
761 Record.push_back(M->first->getModificationTime());
762
763 // File name
764 StringRef Name(M->first->getName());
765 Record.push_back(Name.size());
766 Record.append(Name.begin(), Name.end());
767
768 // Dependencies
769 Record.push_back(M->second.Dependencies.size());
770 Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
771 Stream.EmitRecord(MODULE, Record);
772 }
773
774 // Write the identifier -> module file mapping.
775 {
776 OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
777 IdentifierIndexWriterTrait Trait;
778
779 // Populate the hash table.
780 for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
781 IEnd = InterestingIdentifiers.end();
782 I != IEnd; ++I) {
783 Generator.insert(I->first(), I->second, Trait);
784 }
785
786 // Create the on-disk hash table in a buffer.
787 SmallString<4096> IdentifierTable;
788 uint32_t BucketOffset;
789 {
790 llvm::raw_svector_ostream Out(IdentifierTable);
791 // Make sure that no bucket is at offset 0
792 clang::io::Emit32(Out, 0);
793 BucketOffset = Generator.Emit(Out, Trait);
794 }
795
796 // Create a blob abbreviation
797 BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
798 Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
799 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
800 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
801 unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
802
803 // Write the identifier table
804 Record.clear();
805 Record.push_back(IDENTIFIER_INDEX);
806 Record.push_back(BucketOffset);
807 Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
808 }
809
810 // FIXME: Selectors.
811
812 Stream.ExitBlock();
813}
814
815GlobalModuleIndex::ErrorCode
816GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
817 llvm::SmallString<128> IndexPath;
818 IndexPath += Path;
819 llvm::sys::path::append(IndexPath, IndexFileName);
820
821 // Coordinate building the global index file with other processes that might
822 // try to do the same.
823 llvm::LockFileManager Locked(IndexPath);
824 switch (Locked) {
825 case llvm::LockFileManager::LFS_Error:
826 return EC_IOError;
827
828 case llvm::LockFileManager::LFS_Owned:
829 // We're responsible for building the index ourselves. Do so below.
830 break;
831
832 case llvm::LockFileManager::LFS_Shared:
833 // Someone else is responsible for building the index. We don't care
834 // when they finish, so we're done.
835 return EC_Building;
836 }
837
838 // The module index builder.
839 GlobalModuleIndexBuilder Builder(FileMgr);
840
841 // Load each of the module files.
842 llvm::error_code EC;
843 for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
844 D != DEnd && !EC;
845 D.increment(EC)) {
846 // If this isn't a module file, we don't care.
847 if (llvm::sys::path::extension(D->path()) != ".pcm") {
848 // ... unless it's a .pcm.lock file, which indicates that someone is
849 // in the process of rebuilding a module. They'll rebuild the index
850 // at the end of that translation unit, so we don't have to.
851 if (llvm::sys::path::extension(D->path()) == ".pcm.lock")
852 return EC_Building;
853
854 continue;
855 }
856
857 // If we can't find the module file, skip it.
858 const FileEntry *ModuleFile = FileMgr.getFile(D->path());
859 if (!ModuleFile)
860 continue;
861
862 // Load this module file.
863 if (Builder.loadModuleFile(ModuleFile))
864 return EC_IOError;
865 }
866
867 // The output buffer, into which the global index will be written.
868 SmallVector<char, 16> OutputBuffer;
869 {
870 llvm::BitstreamWriter OutputStream(OutputBuffer);
871 Builder.writeIndex(OutputStream);
872 }
873
874 // Write the global index file to a temporary file.
875 llvm::SmallString<128> IndexTmpPath;
876 int TmpFD;
877 if (llvm::sys::fs::unique_file(IndexPath + "-%%%%%%%%", TmpFD, IndexTmpPath))
878 return EC_IOError;
879
880 // Open the temporary global index file for output.
NAKAMURA Takumid2db16f2013-01-24 08:20:11 +0000881 llvm::raw_fd_ostream Out(TmpFD, true);
Douglas Gregora6b00fc2013-01-23 22:38:11 +0000882 if (Out.has_error())
883 return EC_IOError;
884
885 // Write the index.
886 Out.write(OutputBuffer.data(), OutputBuffer.size());
887 Out.close();
888 if (Out.has_error())
889 return EC_IOError;
890
891 // Remove the old index file. It isn't relevant any more.
892 bool OldIndexExisted;
893 llvm::sys::fs::remove(IndexPath.str(), OldIndexExisted);
894
895 // Rename the newly-written index file to the proper name.
896 if (llvm::sys::fs::rename(IndexTmpPath.str(), IndexPath.str())) {
897 // Rename failed; just remove the
898 llvm::sys::fs::remove(IndexTmpPath.str(), OldIndexExisted);
899 return EC_IOError;
900 }
901
902 // We're done.
903 return EC_None;
904}