clang: lib/Serialization/ModuleManager.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

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

36#include

37#include

38#include

39#include <system_error>

40

41using namespace clang;

42using namespace serialization;

43

46 false);

47 if (Entry)

48 return lookup(*Entry);

49

50 return nullptr;

51}

52

57

58 return nullptr;

59}

60

62 return Modules.lookup(File);

63}

64

65std::unique_ptrllvm::MemoryBuffer

68 false);

69 if (!Entry)

70 return nullptr;

71 return std::move(InMemoryBuffers[*Entry]);

72}

73

76 std::string &ErrorStr) {

77 if (!ExpectedSignature || Signature == ExpectedSignature)

78 return false;

79

80 ErrorStr =

81 Signature ? "signature mismatch" : "could not read module signature";

82 return true;

83}

84

87 if (ImportedBy) {

89 ImportedBy->Imports.insert(&MF);

90 } else {

93

95 }

96}

97

101 unsigned Generation,

102 off_t ExpectedSize, time_t ExpectedModTime,

106 std::string &ErrorStr) {

108

109

110

113

114

115

116

117 ExpectedModTime = 0;

118 }

119

120

122 ErrorStr = "module file out of date";

124 }

125

126 if (!Entry) {

127 ErrorStr = "module file not found";

129 }

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

148 return true;

149 return Entry.getName() == MF->FileName;

150 };

151

152

153 if (ModuleFile *ModuleEntry = Modules.lookup(*Entry)) {

154 if (implicitModuleNamesMatch(Type, ModuleEntry, *Entry)) {

155

156 if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))

158

159 Module = ModuleEntry;

162 }

163 }

164

165

166 auto NewModule = std::make_unique(Type, *Entry, Generation);

167 NewModule->Index = Chain.size();

168 NewModule->FileName = FileName.str();

169 NewModule->ImportLoc = ImportLoc;

170 NewModule->InputFilesValidationTimestamp = 0;

171

173 std::string TimestampFilename =

175 llvm::vfs::Status Status;

176

178 NewModule->InputFilesValidationTimestamp =

179 llvm::sys::toTimeT(Status.getLastModificationTime());

180 }

181

182

184

185 NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer));

186

187

188

190 } else if (llvm::MemoryBuffer *Buffer =

192 NewModule->Buffer = Buffer;

193

196

197

200 } else {

201

202

203

204

205

206

208 true,

209 false);

210

211 if (!Buf) {

212 ErrorStr = Buf.getError().message();

214 }

215

217 }

218

219

220 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);

221

222

223

224 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),

225 ExpectedSignature, ErrorStr))

227

228

229 Module = Modules[*Entry] = NewModule.get();

230

232

233 if (!NewModule->isModule())

234 PCHChain.push_back(NewModule.get());

235 if (!ImportedBy)

236 Roots.push_back(NewModule.get());

237

238 Chain.push_back(std::move(NewModule));

240}

241

245 return;

246

247

248 VisitOrder.clear();

249

250

252 (llvm::pointer_iterator(First)),

253 (llvm::pointer_iterator(Last)));

254

255 auto IsVictim = [&](ModuleFile *MF) {

256 return victimSet.count(MF);

257 };

258

259 for (auto I = begin(); I != First; ++I) {

260 I->Imports.remove_if(IsVictim);

261 I->ImportedBy.remove_if(IsVictim);

262 }

263 llvm::erase_if(Roots, IsVictim);

264

265

266 for (auto I = First; I != Last; ++I) {

267 if (!I->isModule()) {

268 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());

269 break;

270 }

271 }

272

273

275 Modules.erase(victim->File);

276

277 Chain.erase(Chain.begin() + (First - begin()), Chain.end());

278}

279

280void

282 std::unique_ptrllvm::MemoryBuffer Buffer) {

285 InMemoryBuffers[Entry] = std::move(Buffer);

286}

287

288std::unique_ptrModuleManager::VisitState ModuleManager::allocateVisitState() {

289

290 if (FirstVisitState) {

291 auto Result = std::move(FirstVisitState);

292 FirstVisitState = std::move(Result->NextState);

294 }

295

296

297 return std::make_unique(size());

298}

299

300void ModuleManager::returnVisitState(std::unique_ptr State) {

301 assert(State->NextState == nullptr && "Visited state is in list?");

302 State->NextState = std::move(FirstVisitState);

303 FirstVisitState = std::move(State);

304}

305

307 GlobalIndex = Index;

308 if (!GlobalIndex) {

309 ModulesInCommonWithGlobalIndex.clear();

310 return;

311 }

312

313

314

317 ModulesInCommonWithGlobalIndex.push_back(&M);

318}

319

322 return;

323

324 ModulesInCommonWithGlobalIndex.push_back(MF);

325}

326

331 : FileMgr(FileMgr), ModuleCache(&ModuleCache),

332 PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}

333

335 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {

336

337 if (VisitOrder.size() != Chain.size()) {

338 unsigned N = size();

339 VisitOrder.clear();

340 VisitOrder.reserve(N);

341

342

343

344

346 Queue.reserve(N);

348 UnusedIncomingEdges.resize(size());

349 for (ModuleFile &M : llvm::reverse(*this)) {

351 UnusedIncomingEdges[M.Index] = Size;

352 if (!Size)

353 Queue.push_back(&M);

354 }

355

356

357

358 while (!Queue.empty()) {

359 ModuleFile *CurrentModule = Queue.pop_back_val();

360 VisitOrder.push_back(CurrentModule);

361

362

363

365

366

367

368

369 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->Index];

370 if (NumUnusedEdges && (--NumUnusedEdges == 0))

371 Queue.push_back(M);

372 }

373 }

374

375 assert(VisitOrder.size() == N && "Visitation order is wrong?");

376

377 FirstVisitState = nullptr;

378 }

379

380 auto State = allocateVisitState();

381 unsigned VisitNumber = State->NextVisitNumber++;

382

383

384

385

386 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {

387 for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)

388 {

389 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];

390 if (!ModuleFilesHit->count(M))

391 State->VisitNumber[M->Index] = VisitNumber;

392 }

393 }

394

395 for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {

396 ModuleFile *CurrentModule = VisitOrder[I];

397

398 if (State->VisitNumber[CurrentModule->Index] == VisitNumber)

399 continue;

400

401

402 assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);

403 State->VisitNumber[CurrentModule->Index] = VisitNumber;

404 if (!Visitor(*CurrentModule))

405 continue;

406

407

408

409

410 ModuleFile *NextModule = CurrentModule;

411 do {

412

413

414 for (llvm::SetVector<ModuleFile *>::iterator

415 M = NextModule->Imports.begin(),

416 MEnd = NextModule->Imports.end();

417 M != MEnd; ++M) {

418 if (State->VisitNumber[(*M)->Index] != VisitNumber) {

419 State->Stack.push_back(*M);

420 State->VisitNumber[(*M)->Index] = VisitNumber;

421 }

422 }

423

424 if (State->Stack.empty())

425 break;

426

427

428 NextModule = State->Stack.pop_back_val();

429 } while (true);

430 }

431

432 returnVisitState(std::move(State));

433}

434

436 time_t ExpectedModTime,

439 File = expectedToOptional(FileMgr.getSTDIN());

440 return false;

441 }

442

443

444

446 false);

447

449 ((ExpectedSize && ExpectedSize != File->getSize()) ||

450 (ExpectedModTime && ExpectedModTime != File->getModificationTime())))

451

452

453 return true;

454

455 return false;

456}

457

458#ifndef NDEBUG

459namespace llvm {

460

461 template<>

465 using nodes_iterator = pointer_iteratorModuleManager::ModuleConstIterator;

466

468 return Node->Imports.begin();

469 }

470

472 return Node->Imports.end();

473 }

474

477 }

478

481 }

482 };

483

484 template<>

488

490

493 }

494 };

495

496}

497

499 llvm::ViewGraph(*this, "Modules");

500}

501#endif

Defines the clang::FileManager interface and associated types.

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

static bool checkSignature(ASTFileSignature Signature, ASTFileSignature ExpectedSignature, std::string &ErrorStr)

static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, SourceLocation ImportLoc)

A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...

Cached information about one file (either on disk or in the virtual file system).

Implements support for file system lookup, file system caching, and directory search management.

llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(FileEntryRef Entry, bool isVolatile=false, bool RequiresNullTerminator=true, std::optional< int64_t > MaybeLimit=std::nullopt, bool IsText=true)

Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...

std::error_code getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)

Get the 'stat' information for the given Path.

OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)

Get a FileEntryRef if it exists, without doing anything on error.

llvm::Expected< FileEntryRef > getSTDIN()

Get the FileEntryRef for stdin, returning an error if stdin cannot be read.

FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size, time_t ModificationTime)

Retrieve a file entry for a "virtual" file that acts as if there were a file with the given name on d...

A global index for a set of module files, providing information about the identifiers within those mo...

bool loadedModuleFile(ModuleFile *File)

Note that the given module file has been loaded.

In-memory cache for modules.

llvm::MemoryBuffer & addPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer)

Store the PCM under the Filename.

Module * findModule(StringRef Name) const

Retrieve a module with the given name.

Describes a module or submodule.

This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...

virtual llvm::StringRef ExtractPCH(llvm::MemoryBufferRef Buffer) const =0

Returns the serialized AST inside the PCH container Buffer.

Encodes a location in the source.

The base class of the type hierarchy.

Information about a module that has been loaded by the ASTReader.

bool DirectlyImported

Whether this module has been directly imported by the user.

llvm::SetVector< ModuleFile * > ImportedBy

List of modules which depend on this module.

SourceLocation ImportLoc

The source location where this module was first imported.

static std::string getTimestampFilename(StringRef FileName)

unsigned Index

The index of this module in the list of modules.

llvm::SetVector< ModuleFile * > Imports

List of modules which this module directly imported.

std::string ModuleName

The name of the module.

Manages the set of modules loaded by an AST reader.

ModuleManager(FileManager &FileMgr, InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, const HeaderSearch &HeaderSearchInfo)

bool lookupModuleFile(StringRef FileName, off_t ExpectedSize, time_t ExpectedModTime, OptionalFileEntryRef &File)

Attempt to resolve the given module file name to a file entry.

AddModuleResult

The result of attempting to add a new module.

@ Missing

The module file is missing.

@ OutOfDate

The module file is out-of-date.

@ NewlyLoaded

The module file was just loaded in response to this call.

@ AlreadyLoaded

The module file had already been loaded.

void moduleFileAccepted(ModuleFile *MF)

Notification from the AST reader that the given module file has been "accepted", and will not (can no...

ModuleFile * lookup(const FileEntry *File) const

Returns the module associated with the given module file.

void viewGraph()

View the graphviz representation of the module graph.

ModuleIterator begin()

Forward iterator to traverse all loaded modules.

void setGlobalIndex(GlobalModuleIndex *Index)

Set the global module index.

ModuleFile * lookupByFileName(StringRef FileName) const

Returns the module associated with the given file name.

void removeModules(ModuleIterator First)

Remove the modules starting from First (to the end).

ModuleIterator end()

Forward iterator end-point to traverse all loaded modules.

std::unique_ptr< llvm::MemoryBuffer > lookupBuffer(StringRef Name)

Returns the in-memory (virtual file) buffer with the given name.

void addInMemoryBuffer(StringRef FileName, std::unique_ptr< llvm::MemoryBuffer > Buffer)

Add an in-memory buffer the list of known buffers.

void visit(llvm::function_ref< bool(ModuleFile &M)> Visitor, llvm::SmallPtrSetImpl< ModuleFile * > *ModuleFilesHit=nullptr)

Visit each of the modules.

unsigned size() const

Number of modules loaded.

InMemoryModuleCache & getModuleCache() const

AddModuleResult addModule(StringRef FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, ASTFileSignatureReader ReadSignature, ModuleFile *&Module, std::string &ErrorStr)

Attempts to create a new module and add it to the list of known modules.

ASTFileSignature(*)(StringRef) ASTFileSignatureReader

llvm::pointee_iterator< SmallVectorImpl< std::unique_ptr< ModuleFile > >::iterator > ModuleIterator

ModuleFile * lookupByModuleName(StringRef ModName) const

Returns the module associated with the given module name.

ModuleKind

Specifies the kind of module that has been loaded.

@ MK_ExplicitModule

File is an explicitly-loaded module.

@ MK_ImplicitModule

File is an implicitly-loaded module.

@ MK_PrebuiltModule

File is from a prebuilt module path.

The JSON file list parser is used to communicate input to InstallAPI.

@ Result

The result type of a method or function.

Diagnostic wrappers for TextAPI types for error reporting.

The signature of a module, which is a hash of the AST content.

DOTGraphTraits(bool IsSimple=false)

std::string getNodeLabel(ModuleFile *M, const ModuleManager &)

static bool renderGraphFromBottomUp()

static ChildIteratorType child_end(NodeRef Node)

static nodes_iterator nodes_begin(const ModuleManager &Manager)

static ChildIteratorType child_begin(NodeRef Node)

pointer_iterator< ModuleManager::ModuleConstIterator > nodes_iterator

llvm::SetVector< ModuleFile * >::const_iterator ChildIteratorType

static nodes_iterator nodes_end(const ModuleManager &Manager)