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