1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/Serialization/ModuleManager.h" |
15 | #include "clang/Basic/FileManager.h" |
16 | #include "clang/Basic/LLVM.h" |
17 | #include "clang/Lex/HeaderSearch.h" |
18 | #include "clang/Lex/ModuleMap.h" |
19 | #include "clang/Serialization/GlobalModuleIndex.h" |
20 | #include "clang/Serialization/InMemoryModuleCache.h" |
21 | #include "clang/Serialization/Module.h" |
22 | #include "clang/Serialization/PCHContainerOperations.h" |
23 | #include "llvm/ADT/STLExtras.h" |
24 | #include "llvm/ADT/SetVector.h" |
25 | #include "llvm/ADT/SmallPtrSet.h" |
26 | #include "llvm/ADT/SmallVector.h" |
27 | #include "llvm/ADT/StringRef.h" |
28 | #include "llvm/ADT/iterator.h" |
29 | #include "llvm/Support/Chrono.h" |
30 | #include "llvm/Support/DOTGraphTraits.h" |
31 | #include "llvm/Support/ErrorOr.h" |
32 | #include "llvm/Support/GraphWriter.h" |
33 | #include "llvm/Support/MemoryBuffer.h" |
34 | #include "llvm/Support/VirtualFileSystem.h" |
35 | #include <algorithm> |
36 | #include <cassert> |
37 | #include <memory> |
38 | #include <string> |
39 | #include <system_error> |
40 | |
41 | using namespace clang; |
42 | using namespace serialization; |
43 | |
44 | ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const { |
45 | const FileEntry *Entry = FileMgr.getFile(Name, , |
46 | ); |
47 | if (Entry) |
48 | return lookup(Entry); |
49 | |
50 | return nullptr; |
51 | } |
52 | |
53 | ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const { |
54 | if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name)) |
55 | if (const FileEntry *File = Mod->getASTFile()) |
56 | return lookup(File); |
57 | |
58 | return nullptr; |
59 | } |
60 | |
61 | ModuleFile *ModuleManager::lookup(const FileEntry *File) const { |
62 | auto Known = Modules.find(File); |
63 | if (Known == Modules.end()) |
64 | return nullptr; |
65 | |
66 | return Known->second; |
67 | } |
68 | |
69 | std::unique_ptr<llvm::MemoryBuffer> |
70 | ModuleManager::lookupBuffer(StringRef Name) { |
71 | const FileEntry *Entry = FileMgr.getFile(Name, , |
72 | ); |
73 | return std::move(InMemoryBuffers[Entry]); |
74 | } |
75 | |
76 | static bool checkSignature(ASTFileSignature Signature, |
77 | ASTFileSignature ExpectedSignature, |
78 | std::string &ErrorStr) { |
79 | if (!ExpectedSignature || Signature == ExpectedSignature) |
80 | return false; |
81 | |
82 | ErrorStr = |
83 | Signature ? "signature mismatch" : "could not read module signature"; |
84 | return true; |
85 | } |
86 | |
87 | static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, |
88 | SourceLocation ImportLoc) { |
89 | if (ImportedBy) { |
90 | MF.ImportedBy.insert(ImportedBy); |
91 | ImportedBy->Imports.insert(&MF); |
92 | } else { |
93 | if (!MF.DirectlyImported) |
94 | MF.ImportLoc = ImportLoc; |
95 | |
96 | MF.DirectlyImported = true; |
97 | } |
98 | } |
99 | |
100 | ModuleManager::AddModuleResult |
101 | ModuleManager::addModule(StringRef FileName, ModuleKind Type, |
102 | SourceLocation ImportLoc, ModuleFile *ImportedBy, |
103 | unsigned Generation, |
104 | off_t ExpectedSize, time_t ExpectedModTime, |
105 | ASTFileSignature ExpectedSignature, |
106 | ASTFileSignatureReader ReadSignature, |
107 | ModuleFile *&Module, |
108 | std::string &ErrorStr) { |
109 | Module = nullptr; |
110 | |
111 | |
112 | |
113 | const FileEntry *Entry; |
114 | if (Type == MK_ExplicitModule || Type == MK_PrebuiltModule) { |
115 | |
116 | |
117 | |
118 | |
119 | ExpectedModTime = 0; |
120 | } |
121 | |
122 | |
123 | if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) { |
124 | ErrorStr = "module file out of date"; |
125 | return OutOfDate; |
126 | } |
127 | |
128 | if (!Entry && FileName != "-") { |
129 | ErrorStr = "module file not found"; |
130 | return Missing; |
131 | } |
132 | |
133 | |
134 | if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) { |
135 | |
136 | if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr)) |
137 | return OutOfDate; |
138 | |
139 | Module = ModuleEntry; |
140 | updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc); |
141 | return AlreadyLoaded; |
142 | } |
143 | |
144 | |
145 | auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation); |
146 | NewModule->Index = Chain.size(); |
147 | NewModule->FileName = FileName.str(); |
148 | NewModule->File = Entry; |
149 | NewModule->ImportLoc = ImportLoc; |
150 | NewModule->InputFilesValidationTimestamp = 0; |
151 | |
152 | if (NewModule->Kind == MK_ImplicitModule) { |
153 | std::string TimestampFilename = NewModule->getTimestampFilename(); |
154 | llvm::vfs::Status Status; |
155 | |
156 | if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status)) |
157 | NewModule->InputFilesValidationTimestamp = |
158 | llvm::sys::toTimeT(Status.getLastModificationTime()); |
159 | } |
160 | |
161 | |
162 | if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) { |
163 | |
164 | NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer)); |
165 | |
166 | |
167 | |
168 | Entry->closeFile(); |
169 | } else if (llvm::MemoryBuffer *Buffer = |
170 | getModuleCache().lookupPCM(FileName)) { |
171 | NewModule->Buffer = Buffer; |
172 | |
173 | Entry->closeFile(); |
174 | } else if (getModuleCache().shouldBuildPCM(FileName)) { |
175 | |
176 | |
177 | Entry->closeFile(); |
178 | return OutOfDate; |
179 | } else { |
180 | |
181 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code())); |
182 | if (FileName == "-") { |
183 | Buf = llvm::MemoryBuffer::getSTDIN(); |
184 | } else { |
185 | |
186 | Buf = FileMgr.getBufferForFile(NewModule->File, |
187 | , |
188 | ); |
189 | } |
190 | |
191 | if (!Buf) { |
192 | ErrorStr = Buf.getError().message(); |
193 | return Missing; |
194 | } |
195 | |
196 | NewModule->Buffer = &getModuleCache().addPCM(FileName, std::move(*Buf)); |
197 | } |
198 | |
199 | |
200 | NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer); |
201 | |
202 | |
203 | |
204 | if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data), |
205 | ExpectedSignature, ErrorStr)) { |
206 | |
207 | |
208 | if (!getModuleCache().tryToDropPCM(NewModule->FileName)) |
209 | FileMgr.invalidateCache(NewModule->File); |
210 | return OutOfDate; |
211 | } |
212 | |
213 | |
214 | Module = Modules[Entry] = NewModule.get(); |
215 | |
216 | updateModuleImports(*NewModule, ImportedBy, ImportLoc); |
217 | |
218 | if (!NewModule->isModule()) |
219 | PCHChain.push_back(NewModule.get()); |
220 | if (!ImportedBy) |
221 | Roots.push_back(NewModule.get()); |
222 | |
223 | Chain.push_back(std::move(NewModule)); |
224 | return NewlyLoaded; |
225 | } |
226 | |
227 | void ModuleManager::removeModules( |
228 | ModuleIterator First, |
229 | llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully, |
230 | ModuleMap *modMap) { |
231 | auto Last = end(); |
232 | if (First == Last) |
233 | return; |
234 | |
235 | |
236 | VisitOrder.clear(); |
237 | |
238 | |
239 | llvm::SmallPtrSet<ModuleFile *, 4> victimSet( |
240 | (llvm::pointer_iterator<ModuleIterator>(First)), |
241 | (llvm::pointer_iterator<ModuleIterator>(Last))); |
242 | |
243 | auto IsVictim = [&](ModuleFile *MF) { |
244 | return victimSet.count(MF); |
245 | }; |
246 | |
247 | for (auto I = begin(); I != First; ++I) { |
248 | I->Imports.remove_if(IsVictim); |
249 | I->ImportedBy.remove_if(IsVictim); |
250 | } |
251 | Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim), |
252 | Roots.end()); |
253 | |
254 | |
255 | for (auto I = First; I != Last; ++I) { |
256 | if (!I->isModule()) { |
257 | PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), &*I), |
258 | PCHChain.end()); |
259 | break; |
260 | } |
261 | } |
262 | |
263 | |
264 | for (ModuleIterator victim = First; victim != Last; ++victim) { |
265 | Modules.erase(victim->File); |
266 | |
267 | if (modMap) { |
268 | StringRef ModuleName = victim->ModuleName; |
269 | if (Module *mod = modMap->findModule(ModuleName)) { |
270 | mod->setASTFile(nullptr); |
271 | } |
272 | } |
273 | } |
274 | |
275 | |
276 | Chain.erase(Chain.begin() + (First - begin()), Chain.end()); |
277 | } |
278 | |
279 | void |
280 | ModuleManager::addInMemoryBuffer(StringRef FileName, |
281 | std::unique_ptr<llvm::MemoryBuffer> Buffer) { |
282 | const FileEntry *Entry = |
283 | FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0); |
284 | InMemoryBuffers[Entry] = std::move(Buffer); |
285 | } |
286 | |
287 | ModuleManager::VisitState *ModuleManager::allocateVisitState() { |
288 | |
289 | if (FirstVisitState) { |
290 | VisitState *Result = FirstVisitState; |
291 | FirstVisitState = FirstVisitState->NextState; |
292 | Result->NextState = nullptr; |
293 | return Result; |
294 | } |
295 | |
296 | |
297 | return new VisitState(size()); |
298 | } |
299 | |
300 | void ModuleManager::returnVisitState(VisitState *State) { |
301 | (0) . __assert_fail ("State->NextState == nullptr && \"Visited state is in list?\"", "/home/seafit/code_projects/clang_source/clang/lib/Serialization/ModuleManager.cpp", 301, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(State->NextState == nullptr && "Visited state is in list?"); |
302 | State->NextState = FirstVisitState; |
303 | FirstVisitState = State; |
304 | } |
305 | |
306 | void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { |
307 | GlobalIndex = Index; |
308 | if (!GlobalIndex) { |
309 | ModulesInCommonWithGlobalIndex.clear(); |
310 | return; |
311 | } |
312 | |
313 | |
314 | |
315 | for (ModuleFile &M : *this) |
316 | if (!GlobalIndex->loadedModuleFile(&M)) |
317 | ModulesInCommonWithGlobalIndex.push_back(&M); |
318 | } |
319 | |
320 | void ModuleManager::moduleFileAccepted(ModuleFile *MF) { |
321 | if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) |
322 | return; |
323 | |
324 | ModulesInCommonWithGlobalIndex.push_back(MF); |
325 | } |
326 | |
327 | ModuleManager::ModuleManager(FileManager &FileMgr, |
328 | InMemoryModuleCache &ModuleCache, |
329 | const PCHContainerReader &PCHContainerRdr, |
330 | const HeaderSearch &) |
331 | : FileMgr(FileMgr), ModuleCache(&ModuleCache), |
332 | PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {} |
333 | |
334 | ModuleManager::~ModuleManager() { delete FirstVisitState; } |
335 | |
336 | void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, |
337 | llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) { |
338 | |
339 | if (VisitOrder.size() != Chain.size()) { |
340 | unsigned N = size(); |
341 | VisitOrder.clear(); |
342 | VisitOrder.reserve(N); |
343 | |
344 | |
345 | |
346 | |
347 | SmallVector<ModuleFile *, 4> Queue; |
348 | Queue.reserve(N); |
349 | llvm::SmallVector<unsigned, 4> UnusedIncomingEdges; |
350 | UnusedIncomingEdges.resize(size()); |
351 | for (ModuleFile &M : llvm::reverse(*this)) { |
352 | unsigned Size = M.ImportedBy.size(); |
353 | UnusedIncomingEdges[M.Index] = Size; |
354 | if (!Size) |
355 | Queue.push_back(&M); |
356 | } |
357 | |
358 | |
359 | |
360 | while (!Queue.empty()) { |
361 | ModuleFile *CurrentModule = Queue.pop_back_val(); |
362 | VisitOrder.push_back(CurrentModule); |
363 | |
364 | |
365 | |
366 | for (auto M = CurrentModule->Imports.rbegin(), |
367 | MEnd = CurrentModule->Imports.rend(); |
368 | M != MEnd; ++M) { |
369 | |
370 | |
371 | |
372 | |
373 | unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index]; |
374 | if (NumUnusedEdges && (--NumUnusedEdges == 0)) |
375 | Queue.push_back(*M); |
376 | } |
377 | } |
378 | |
379 | (0) . __assert_fail ("VisitOrder.size() == N && \"Visitation order is wrong?\"", "/home/seafit/code_projects/clang_source/clang/lib/Serialization/ModuleManager.cpp", 379, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(VisitOrder.size() == N && "Visitation order is wrong?"); |
380 | |
381 | delete FirstVisitState; |
382 | FirstVisitState = nullptr; |
383 | } |
384 | |
385 | VisitState *State = allocateVisitState(); |
386 | unsigned VisitNumber = State->NextVisitNumber++; |
387 | |
388 | |
389 | |
390 | |
391 | if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) { |
392 | for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I) |
393 | { |
394 | ModuleFile *M = ModulesInCommonWithGlobalIndex[I]; |
395 | if (!ModuleFilesHit->count(M)) |
396 | State->VisitNumber[M->Index] = VisitNumber; |
397 | } |
398 | } |
399 | |
400 | for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) { |
401 | ModuleFile *CurrentModule = VisitOrder[I]; |
402 | |
403 | if (State->VisitNumber[CurrentModule->Index] == VisitNumber) |
404 | continue; |
405 | |
406 | |
407 | VisitNumber[CurrentModule->Index] == VisitNumber - 1", "/home/seafit/code_projects/clang_source/clang/lib/Serialization/ModuleManager.cpp", 407, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1); |
408 | State->VisitNumber[CurrentModule->Index] = VisitNumber; |
409 | if (!Visitor(*CurrentModule)) |
410 | continue; |
411 | |
412 | |
413 | |
414 | |
415 | ModuleFile *NextModule = CurrentModule; |
416 | do { |
417 | |
418 | |
419 | for (llvm::SetVector<ModuleFile *>::iterator |
420 | M = NextModule->Imports.begin(), |
421 | MEnd = NextModule->Imports.end(); |
422 | M != MEnd; ++M) { |
423 | if (State->VisitNumber[(*M)->Index] != VisitNumber) { |
424 | State->Stack.push_back(*M); |
425 | State->VisitNumber[(*M)->Index] = VisitNumber; |
426 | } |
427 | } |
428 | |
429 | if (State->Stack.empty()) |
430 | break; |
431 | |
432 | |
433 | NextModule = State->Stack.pop_back_val(); |
434 | } while (true); |
435 | } |
436 | |
437 | returnVisitState(State); |
438 | } |
439 | |
440 | bool ModuleManager::lookupModuleFile(StringRef FileName, |
441 | off_t ExpectedSize, |
442 | time_t ExpectedModTime, |
443 | const FileEntry *&File) { |
444 | if (FileName == "-") { |
445 | File = nullptr; |
446 | return false; |
447 | } |
448 | |
449 | |
450 | |
451 | File = FileMgr.getFile(FileName, , ); |
452 | if (!File) |
453 | return false; |
454 | |
455 | if ((ExpectedSize && ExpectedSize != File->getSize()) || |
456 | (ExpectedModTime && ExpectedModTime != File->getModificationTime())) |
457 | |
458 | |
459 | return true; |
460 | |
461 | return false; |
462 | } |
463 | |
464 | #ifndef NDEBUG |
465 | namespace llvm { |
466 | |
467 | template<> |
468 | struct GraphTraits<ModuleManager> { |
469 | using NodeRef = ModuleFile *; |
470 | using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator; |
471 | using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>; |
472 | |
473 | static ChildIteratorType child_begin(NodeRef Node) { |
474 | return Node->Imports.begin(); |
475 | } |
476 | |
477 | static ChildIteratorType child_end(NodeRef Node) { |
478 | return Node->Imports.end(); |
479 | } |
480 | |
481 | static nodes_iterator nodes_begin(const ModuleManager &Manager) { |
482 | return nodes_iterator(Manager.begin()); |
483 | } |
484 | |
485 | static nodes_iterator nodes_end(const ModuleManager &Manager) { |
486 | return nodes_iterator(Manager.end()); |
487 | } |
488 | }; |
489 | |
490 | template<> |
491 | struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits { |
492 | explicit DOTGraphTraits(bool IsSimple = false) |
493 | : DefaultDOTGraphTraits(IsSimple) {} |
494 | |
495 | static bool renderGraphFromBottomUp() { return true; } |
496 | |
497 | std::string getNodeLabel(ModuleFile *M, const ModuleManager&) { |
498 | return M->ModuleName; |
499 | } |
500 | }; |
501 | |
502 | } |
503 | |
504 | void ModuleManager::viewGraph() { |
505 | llvm::ViewGraph(*this, "Modules"); |
506 | } |
507 | #endif |
508 | |