clang API Documentation
00001 //===--- FileManager.cpp - File System Probing and Caching ----------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the FileManager interface. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 // 00014 // TODO: This should index all interesting directories with dirent calls. 00015 // getdirentries ? 00016 // opendir/readdir_r/closedir ? 00017 // 00018 //===----------------------------------------------------------------------===// 00019 00020 #include "clang/Basic/FileManager.h" 00021 #include "clang/Basic/FileSystemStatCache.h" 00022 #include "llvm/ADT/SmallString.h" 00023 #include "llvm/Support/FileSystem.h" 00024 #include "llvm/Support/MemoryBuffer.h" 00025 #include "llvm/Support/raw_ostream.h" 00026 #include "llvm/Support/Path.h" 00027 #include "llvm/Support/system_error.h" 00028 #include "llvm/Config/llvm-config.h" 00029 #include <map> 00030 #include <set> 00031 #include <string> 00032 00033 // FIXME: This is terrible, we need this for ::close. 00034 #if !defined(_MSC_VER) && !defined(__MINGW32__) 00035 #include <unistd.h> 00036 #include <sys/uio.h> 00037 #else 00038 #include <io.h> 00039 #endif 00040 using namespace clang; 00041 00042 // FIXME: Enhance libsystem to support inode and other fields. 00043 #include <sys/stat.h> 00044 00045 /// NON_EXISTENT_DIR - A special value distinct from null that is used to 00046 /// represent a dir name that doesn't exist on the disk. 00047 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1) 00048 00049 /// NON_EXISTENT_FILE - A special value distinct from null that is used to 00050 /// represent a filename that doesn't exist on the disk. 00051 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) 00052 00053 00054 FileEntry::~FileEntry() { 00055 // If this FileEntry owns an open file descriptor that never got used, close 00056 // it. 00057 if (FD != -1) ::close(FD); 00058 } 00059 00060 //===----------------------------------------------------------------------===// 00061 // Windows. 00062 //===----------------------------------------------------------------------===// 00063 00064 #ifdef LLVM_ON_WIN32 00065 00066 namespace { 00067 static std::string GetFullPath(const char *relPath) { 00068 char *absPathStrPtr = _fullpath(NULL, relPath, 0); 00069 assert(absPathStrPtr && "_fullpath() returned NULL!"); 00070 00071 std::string absPath(absPathStrPtr); 00072 00073 free(absPathStrPtr); 00074 return absPath; 00075 } 00076 } 00077 00078 class FileManager::UniqueDirContainer { 00079 /// UniqueDirs - Cache from full path to existing directories/files. 00080 /// 00081 llvm::StringMap<DirectoryEntry> UniqueDirs; 00082 00083 public: 00084 /// getDirectory - Return an existing DirectoryEntry with the given 00085 /// name if there is already one; otherwise create and return a 00086 /// default-constructed DirectoryEntry. 00087 DirectoryEntry &getDirectory(const char *Name, 00088 const struct stat & /*StatBuf*/) { 00089 std::string FullPath(GetFullPath(Name)); 00090 return UniqueDirs.GetOrCreateValue(FullPath).getValue(); 00091 } 00092 00093 size_t size() const { return UniqueDirs.size(); } 00094 }; 00095 00096 class FileManager::UniqueFileContainer { 00097 /// UniqueFiles - Cache from full path to existing directories/files. 00098 /// 00099 llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles; 00100 00101 public: 00102 /// getFile - Return an existing FileEntry with the given name if 00103 /// there is already one; otherwise create and return a 00104 /// default-constructed FileEntry. 00105 FileEntry &getFile(const char *Name, const struct stat & /*StatBuf*/) { 00106 std::string FullPath(GetFullPath(Name)); 00107 00108 // Lowercase string because Windows filesystem is case insensitive. 00109 FullPath = StringRef(FullPath).lower(); 00110 return UniqueFiles.GetOrCreateValue(FullPath).getValue(); 00111 } 00112 00113 size_t size() const { return UniqueFiles.size(); } 00114 }; 00115 00116 //===----------------------------------------------------------------------===// 00117 // Unix-like Systems. 00118 //===----------------------------------------------------------------------===// 00119 00120 #else 00121 00122 class FileManager::UniqueDirContainer { 00123 /// UniqueDirs - Cache from ID's to existing directories/files. 00124 std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs; 00125 00126 public: 00127 /// getDirectory - Return an existing DirectoryEntry with the given 00128 /// ID's if there is already one; otherwise create and return a 00129 /// default-constructed DirectoryEntry. 00130 DirectoryEntry &getDirectory(const char * /*Name*/, 00131 const struct stat &StatBuf) { 00132 return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; 00133 } 00134 00135 size_t size() const { return UniqueDirs.size(); } 00136 }; 00137 00138 class FileManager::UniqueFileContainer { 00139 /// UniqueFiles - Cache from ID's to existing directories/files. 00140 std::set<FileEntry> UniqueFiles; 00141 00142 public: 00143 /// getFile - Return an existing FileEntry with the given ID's if 00144 /// there is already one; otherwise create and return a 00145 /// default-constructed FileEntry. 00146 FileEntry &getFile(const char * /*Name*/, const struct stat &StatBuf) { 00147 return 00148 const_cast<FileEntry&>( 00149 *UniqueFiles.insert(FileEntry(StatBuf.st_dev, 00150 StatBuf.st_ino, 00151 StatBuf.st_mode)).first); 00152 } 00153 00154 size_t size() const { return UniqueFiles.size(); } 00155 }; 00156 00157 #endif 00158 00159 //===----------------------------------------------------------------------===// 00160 // Common logic. 00161 //===----------------------------------------------------------------------===// 00162 00163 FileManager::FileManager(const FileSystemOptions &FSO) 00164 : FileSystemOpts(FSO), 00165 UniqueRealDirs(*new UniqueDirContainer()), 00166 UniqueRealFiles(*new UniqueFileContainer()), 00167 SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) { 00168 NumDirLookups = NumFileLookups = 0; 00169 NumDirCacheMisses = NumFileCacheMisses = 0; 00170 } 00171 00172 FileManager::~FileManager() { 00173 delete &UniqueRealDirs; 00174 delete &UniqueRealFiles; 00175 for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i) 00176 delete VirtualFileEntries[i]; 00177 for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i) 00178 delete VirtualDirectoryEntries[i]; 00179 } 00180 00181 void FileManager::addStatCache(FileSystemStatCache *statCache, 00182 bool AtBeginning) { 00183 assert(statCache && "No stat cache provided?"); 00184 if (AtBeginning || StatCache.get() == 0) { 00185 statCache->setNextStatCache(StatCache.take()); 00186 StatCache.reset(statCache); 00187 return; 00188 } 00189 00190 FileSystemStatCache *LastCache = StatCache.get(); 00191 while (LastCache->getNextStatCache()) 00192 LastCache = LastCache->getNextStatCache(); 00193 00194 LastCache->setNextStatCache(statCache); 00195 } 00196 00197 void FileManager::removeStatCache(FileSystemStatCache *statCache) { 00198 if (!statCache) 00199 return; 00200 00201 if (StatCache.get() == statCache) { 00202 // This is the first stat cache. 00203 StatCache.reset(StatCache->takeNextStatCache()); 00204 return; 00205 } 00206 00207 // Find the stat cache in the list. 00208 FileSystemStatCache *PrevCache = StatCache.get(); 00209 while (PrevCache && PrevCache->getNextStatCache() != statCache) 00210 PrevCache = PrevCache->getNextStatCache(); 00211 00212 assert(PrevCache && "Stat cache not found for removal"); 00213 PrevCache->setNextStatCache(statCache->getNextStatCache()); 00214 } 00215 00216 /// \brief Retrieve the directory that the given file name resides in. 00217 /// Filename can point to either a real file or a virtual file. 00218 static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, 00219 StringRef Filename, 00220 bool CacheFailure) { 00221 if (Filename.empty()) 00222 return NULL; 00223 00224 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) 00225 return NULL; // If Filename is a directory. 00226 00227 StringRef DirName = llvm::sys::path::parent_path(Filename); 00228 // Use the current directory if file has no path component. 00229 if (DirName.empty()) 00230 DirName = "."; 00231 00232 return FileMgr.getDirectory(DirName, CacheFailure); 00233 } 00234 00235 /// Add all ancestors of the given path (pointing to either a file or 00236 /// a directory) as virtual directories. 00237 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { 00238 StringRef DirName = llvm::sys::path::parent_path(Path); 00239 if (DirName.empty()) 00240 return; 00241 00242 llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = 00243 SeenDirEntries.GetOrCreateValue(DirName); 00244 00245 // When caching a virtual directory, we always cache its ancestors 00246 // at the same time. Therefore, if DirName is already in the cache, 00247 // we don't need to recurse as its ancestors must also already be in 00248 // the cache. 00249 if (NamedDirEnt.getValue()) 00250 return; 00251 00252 // Add the virtual directory to the cache. 00253 DirectoryEntry *UDE = new DirectoryEntry; 00254 UDE->Name = NamedDirEnt.getKeyData(); 00255 NamedDirEnt.setValue(UDE); 00256 VirtualDirectoryEntries.push_back(UDE); 00257 00258 // Recursively add the other ancestors. 00259 addAncestorsAsVirtualDirs(DirName); 00260 } 00261 00262 /// getDirectory - Lookup, cache, and verify the specified directory 00263 /// (real or virtual). This returns NULL if the directory doesn't 00264 /// exist. 00265 /// 00266 const DirectoryEntry *FileManager::getDirectory(StringRef DirName, 00267 bool CacheFailure) { 00268 // stat doesn't like trailing separators. 00269 // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'. 00270 // (though it can strip '\\') 00271 if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back())) 00272 DirName = DirName.substr(0, DirName.size()-1); 00273 00274 ++NumDirLookups; 00275 llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = 00276 SeenDirEntries.GetOrCreateValue(DirName); 00277 00278 // See if there was already an entry in the map. Note that the map 00279 // contains both virtual and real directories. 00280 if (NamedDirEnt.getValue()) 00281 return NamedDirEnt.getValue() == NON_EXISTENT_DIR 00282 ? 0 : NamedDirEnt.getValue(); 00283 00284 ++NumDirCacheMisses; 00285 00286 // By default, initialize it to invalid. 00287 NamedDirEnt.setValue(NON_EXISTENT_DIR); 00288 00289 // Get the null-terminated directory name as stored as the key of the 00290 // SeenDirEntries map. 00291 const char *InterndDirName = NamedDirEnt.getKeyData(); 00292 00293 // Check to see if the directory exists. 00294 struct stat StatBuf; 00295 if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) { 00296 // There's no real directory at the given path. 00297 if (!CacheFailure) 00298 SeenDirEntries.erase(DirName); 00299 return 0; 00300 } 00301 00302 // It exists. See if we have already opened a directory with the 00303 // same inode (this occurs on Unix-like systems when one dir is 00304 // symlinked to another, for example) or the same path (on 00305 // Windows). 00306 DirectoryEntry &UDE = UniqueRealDirs.getDirectory(InterndDirName, StatBuf); 00307 00308 NamedDirEnt.setValue(&UDE); 00309 if (!UDE.getName()) { 00310 // We don't have this directory yet, add it. We use the string 00311 // key from the SeenDirEntries map as the string. 00312 UDE.Name = InterndDirName; 00313 } 00314 00315 return &UDE; 00316 } 00317 00318 /// getFile - Lookup, cache, and verify the specified file (real or 00319 /// virtual). This returns NULL if the file doesn't exist. 00320 /// 00321 const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, 00322 bool CacheFailure) { 00323 ++NumFileLookups; 00324 00325 // See if there is already an entry in the map. 00326 llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 00327 SeenFileEntries.GetOrCreateValue(Filename); 00328 00329 // See if there is already an entry in the map. 00330 if (NamedFileEnt.getValue()) 00331 return NamedFileEnt.getValue() == NON_EXISTENT_FILE 00332 ? 0 : NamedFileEnt.getValue(); 00333 00334 ++NumFileCacheMisses; 00335 00336 // By default, initialize it to invalid. 00337 NamedFileEnt.setValue(NON_EXISTENT_FILE); 00338 00339 // Get the null-terminated file name as stored as the key of the 00340 // SeenFileEntries map. 00341 const char *InterndFileName = NamedFileEnt.getKeyData(); 00342 00343 // Look up the directory for the file. When looking up something like 00344 // sys/foo.h we'll discover all of the search directories that have a 'sys' 00345 // subdirectory. This will let us avoid having to waste time on known-to-fail 00346 // searches when we go to find sys/bar.h, because all the search directories 00347 // without a 'sys' subdir will get a cached failure result. 00348 const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, 00349 CacheFailure); 00350 if (DirInfo == 0) { // Directory doesn't exist, file can't exist. 00351 if (!CacheFailure) 00352 SeenFileEntries.erase(Filename); 00353 00354 return 0; 00355 } 00356 00357 // FIXME: Use the directory info to prune this, before doing the stat syscall. 00358 // FIXME: This will reduce the # syscalls. 00359 00360 // Nope, there isn't. Check to see if the file exists. 00361 int FileDescriptor = -1; 00362 struct stat StatBuf; 00363 if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) { 00364 // There's no real file at the given path. 00365 if (!CacheFailure) 00366 SeenFileEntries.erase(Filename); 00367 00368 return 0; 00369 } 00370 00371 if (FileDescriptor != -1 && !openFile) { 00372 close(FileDescriptor); 00373 FileDescriptor = -1; 00374 } 00375 00376 // It exists. See if we have already opened a file with the same inode. 00377 // This occurs when one dir is symlinked to another, for example. 00378 FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf); 00379 00380 NamedFileEnt.setValue(&UFE); 00381 if (UFE.getName()) { // Already have an entry with this inode, return it. 00382 // If the stat process opened the file, close it to avoid a FD leak. 00383 if (FileDescriptor != -1) 00384 close(FileDescriptor); 00385 00386 return &UFE; 00387 } 00388 00389 // Otherwise, we don't have this directory yet, add it. 00390 // FIXME: Change the name to be a char* that points back to the 00391 // 'SeenFileEntries' key. 00392 UFE.Name = InterndFileName; 00393 UFE.Size = StatBuf.st_size; 00394 UFE.ModTime = StatBuf.st_mtime; 00395 UFE.Dir = DirInfo; 00396 UFE.UID = NextFileUID++; 00397 UFE.FD = FileDescriptor; 00398 return &UFE; 00399 } 00400 00401 const FileEntry * 00402 FileManager::getVirtualFile(StringRef Filename, off_t Size, 00403 time_t ModificationTime) { 00404 ++NumFileLookups; 00405 00406 // See if there is already an entry in the map. 00407 llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 00408 SeenFileEntries.GetOrCreateValue(Filename); 00409 00410 // See if there is already an entry in the map. 00411 if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE) 00412 return NamedFileEnt.getValue(); 00413 00414 ++NumFileCacheMisses; 00415 00416 // By default, initialize it to invalid. 00417 NamedFileEnt.setValue(NON_EXISTENT_FILE); 00418 00419 addAncestorsAsVirtualDirs(Filename); 00420 FileEntry *UFE = 0; 00421 00422 // Now that all ancestors of Filename are in the cache, the 00423 // following call is guaranteed to find the DirectoryEntry from the 00424 // cache. 00425 const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, 00426 /*CacheFailure=*/true); 00427 assert(DirInfo && 00428 "The directory of a virtual file should already be in the cache."); 00429 00430 // Check to see if the file exists. If so, drop the virtual file 00431 int FileDescriptor = -1; 00432 struct stat StatBuf; 00433 const char *InterndFileName = NamedFileEnt.getKeyData(); 00434 if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) { 00435 // If the stat process opened the file, close it to avoid a FD leak. 00436 if (FileDescriptor != -1) 00437 close(FileDescriptor); 00438 00439 StatBuf.st_size = Size; 00440 StatBuf.st_mtime = ModificationTime; 00441 UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf); 00442 00443 NamedFileEnt.setValue(UFE); 00444 00445 // If we had already opened this file, close it now so we don't 00446 // leak the descriptor. We're not going to use the file 00447 // descriptor anyway, since this is a virtual file. 00448 if (UFE->FD != -1) { 00449 close(UFE->FD); 00450 UFE->FD = -1; 00451 } 00452 00453 // If we already have an entry with this inode, return it. 00454 if (UFE->getName()) 00455 return UFE; 00456 } 00457 00458 if (!UFE) { 00459 UFE = new FileEntry(); 00460 VirtualFileEntries.push_back(UFE); 00461 NamedFileEnt.setValue(UFE); 00462 } 00463 00464 UFE->Name = InterndFileName; 00465 UFE->Size = Size; 00466 UFE->ModTime = ModificationTime; 00467 UFE->Dir = DirInfo; 00468 UFE->UID = NextFileUID++; 00469 UFE->FD = -1; 00470 return UFE; 00471 } 00472 00473 void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { 00474 StringRef pathRef(path.data(), path.size()); 00475 00476 if (FileSystemOpts.WorkingDir.empty() 00477 || llvm::sys::path::is_absolute(pathRef)) 00478 return; 00479 00480 SmallString<128> NewPath(FileSystemOpts.WorkingDir); 00481 llvm::sys::path::append(NewPath, pathRef); 00482 path = NewPath; 00483 } 00484 00485 llvm::MemoryBuffer *FileManager:: 00486 getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) { 00487 OwningPtr<llvm::MemoryBuffer> Result; 00488 llvm::error_code ec; 00489 00490 const char *Filename = Entry->getName(); 00491 // If the file is already open, use the open file descriptor. 00492 if (Entry->FD != -1) { 00493 ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result, 00494 Entry->getSize()); 00495 if (ErrorStr) 00496 *ErrorStr = ec.message(); 00497 00498 close(Entry->FD); 00499 Entry->FD = -1; 00500 return Result.take(); 00501 } 00502 00503 // Otherwise, open the file. 00504 00505 if (FileSystemOpts.WorkingDir.empty()) { 00506 ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize()); 00507 if (ec && ErrorStr) 00508 *ErrorStr = ec.message(); 00509 return Result.take(); 00510 } 00511 00512 SmallString<128> FilePath(Entry->getName()); 00513 FixupRelativePath(FilePath); 00514 ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, Entry->getSize()); 00515 if (ec && ErrorStr) 00516 *ErrorStr = ec.message(); 00517 return Result.take(); 00518 } 00519 00520 llvm::MemoryBuffer *FileManager:: 00521 getBufferForFile(StringRef Filename, std::string *ErrorStr) { 00522 OwningPtr<llvm::MemoryBuffer> Result; 00523 llvm::error_code ec; 00524 if (FileSystemOpts.WorkingDir.empty()) { 00525 ec = llvm::MemoryBuffer::getFile(Filename, Result); 00526 if (ec && ErrorStr) 00527 *ErrorStr = ec.message(); 00528 return Result.take(); 00529 } 00530 00531 SmallString<128> FilePath(Filename); 00532 FixupRelativePath(FilePath); 00533 ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result); 00534 if (ec && ErrorStr) 00535 *ErrorStr = ec.message(); 00536 return Result.take(); 00537 } 00538 00539 /// getStatValue - Get the 'stat' information for the specified path, 00540 /// using the cache to accelerate it if possible. This returns true 00541 /// if the path points to a virtual file or does not exist, or returns 00542 /// false if it's an existent real file. If FileDescriptor is NULL, 00543 /// do directory look-up instead of file look-up. 00544 bool FileManager::getStatValue(const char *Path, struct stat &StatBuf, 00545 int *FileDescriptor) { 00546 // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be 00547 // absolute! 00548 if (FileSystemOpts.WorkingDir.empty()) 00549 return FileSystemStatCache::get(Path, StatBuf, FileDescriptor, 00550 StatCache.get()); 00551 00552 SmallString<128> FilePath(Path); 00553 FixupRelativePath(FilePath); 00554 00555 return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor, 00556 StatCache.get()); 00557 } 00558 00559 bool FileManager::getNoncachedStatValue(StringRef Path, 00560 struct stat &StatBuf) { 00561 SmallString<128> FilePath(Path); 00562 FixupRelativePath(FilePath); 00563 00564 return ::stat(FilePath.c_str(), &StatBuf) != 0; 00565 } 00566 00567 void FileManager::GetUniqueIDMapping( 00568 SmallVectorImpl<const FileEntry *> &UIDToFiles) const { 00569 UIDToFiles.clear(); 00570 UIDToFiles.resize(NextFileUID); 00571 00572 // Map file entries 00573 for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator 00574 FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end(); 00575 FE != FEEnd; ++FE) 00576 if (FE->getValue() && FE->getValue() != NON_EXISTENT_FILE) 00577 UIDToFiles[FE->getValue()->getUID()] = FE->getValue(); 00578 00579 // Map virtual file entries 00580 for (SmallVector<FileEntry*, 4>::const_iterator 00581 VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end(); 00582 VFE != VFEEnd; ++VFE) 00583 if (*VFE && *VFE != NON_EXISTENT_FILE) 00584 UIDToFiles[(*VFE)->getUID()] = *VFE; 00585 } 00586 00587 void FileManager::modifyFileEntry(FileEntry *File, 00588 off_t Size, time_t ModificationTime) { 00589 File->Size = Size; 00590 File->ModTime = ModificationTime; 00591 } 00592 00593 00594 void FileManager::PrintStats() const { 00595 llvm::errs() << "\n*** File Manager Stats:\n"; 00596 llvm::errs() << UniqueRealFiles.size() << " real files found, " 00597 << UniqueRealDirs.size() << " real dirs found.\n"; 00598 llvm::errs() << VirtualFileEntries.size() << " virtual files found, " 00599 << VirtualDirectoryEntries.size() << " virtual dirs found.\n"; 00600 llvm::errs() << NumDirLookups << " dir lookups, " 00601 << NumDirCacheMisses << " dir cache misses.\n"; 00602 llvm::errs() << NumFileLookups << " file lookups, " 00603 << NumFileCacheMisses << " file cache misses.\n"; 00604 00605 //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; 00606 }