bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) { // Open the module file. OwningPtr<llvm::MemoryBuffer> Buffer; Buffer.reset(FileMgr.getBufferForFile(File)); if (!Buffer) { return true; } // Initialize the input stream llvm::BitstreamReader InStreamFile; llvm::BitstreamCursor InStream; InStreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); InStream.init(InStreamFile); // Sniff for the signature. if (InStream.Read(8) != 'C' || InStream.Read(8) != 'P' || InStream.Read(8) != 'C' || InStream.Read(8) != 'H') { return true; } // Record this module file and assign it a unique ID (if it doesn't have // one already). unsigned ID = getModuleFileInfo(File).ID; // Search for the blocks and records we care about. enum { Other, ControlBlock, ASTBlock } State = Other; bool Done = false; while (!Done) { llvm::BitstreamEntry Entry = InStream.advance(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: Done = true; continue; case llvm::BitstreamEntry::Record: // In the 'other' state, just skip the record. We don't care. if (State == Other) { InStream.skipRecord(Entry.ID); continue; } // Handle potentially-interesting records below. break; case llvm::BitstreamEntry::SubBlock: if (Entry.ID == CONTROL_BLOCK_ID) { if (InStream.EnterSubBlock(CONTROL_BLOCK_ID)) return true; // Found the control block. State = ControlBlock; continue; } if (Entry.ID == AST_BLOCK_ID) { if (InStream.EnterSubBlock(AST_BLOCK_ID)) return true; // Found the AST block. State = ASTBlock; continue; } if (InStream.SkipBlock()) return true; continue; case llvm::BitstreamEntry::EndBlock: State = Other; continue; } // Read the given record. SmallVector<uint64_t, 64> Record; StringRef Blob; unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob); // Handle module dependencies. if (State == ControlBlock && Code == IMPORTS) { // Load each of the imported PCH files. unsigned Idx = 0, N = Record.size(); while (Idx < N) { // Read information about the AST file. // Skip the imported kind ++Idx; // Skip the import location ++Idx; // Retrieve the imported file name. unsigned Length = Record[Idx++]; SmallString<128> ImportedFile(Record.begin() + Idx, Record.begin() + Idx + Length); Idx += Length; // Find the imported module file. const FileEntry *DependsOnFile = FileMgr.getFile(ImportedFile); if (!DependsOnFile) return true; // Record the dependency. unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID; getModuleFileInfo(File).Dependencies.push_back(DependsOnID); } continue; } // Handle the identifier table if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) { typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait> InterestingIdentifierTable; llvm::OwningPtr<InterestingIdentifierTable> Table(InterestingIdentifierTable::Create( (const unsigned char *)Blob.data() + Record[0], (const unsigned char *)Blob.data())); for (InterestingIdentifierTable::data_iterator D = Table->data_begin(), DEnd = Table->data_end(); D != DEnd; ++D) { std::pair<StringRef, bool> Ident = *D; if (Ident.second) InterestingIdentifiers[Ident.first].push_back(ID); else (void)InterestingIdentifiers[Ident.first]; } } // FIXME: Handle the selector table. // We don't care about this record. } return false; }
void BenchmarkIRParsing() { outs() << "Benchmarking IR parsing...\n"; OwningPtr<MemoryBuffer> FileBuf; error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), FileBuf); if (ec) { report_fatal_error("Could not open input file: " + ec.message()); } size_t BufSize = FileBuf->getBufferSize(); const uint8_t *BufPtr = reinterpret_cast<const uint8_t*>(FileBuf->getBufferStart()); const uint8_t *EndBufPtr = reinterpret_cast<const uint8_t*>(FileBuf->getBufferEnd()); // Since MemoryBuffer may use mmap, make sure to first touch all bytes in the // input buffer to make sure it's actually in memory. volatile uint8_t *Slot = new uint8_t; for (const uint8_t *S = BufPtr; S != EndBufPtr; ++S) { *Slot = *S; } delete Slot; outs() << "Read bitcode into buffer. Size=" << BufSize << "\n"; // Trivial copy into a new buffer with a cascading XOR that simulates // "touching" every byte in the buffer in a simple way. { TimingOperationBlock T("Simple XOR copy", BufSize); volatile uint8_t *OutBuf = new uint8_t[BufSize]; OutBuf[0] = 1; size_t N = 1; // Run over the input buffer from start to end-1; run over the output buffer // from 1 to end. for (const uint8_t *S = BufPtr; S != EndBufPtr - 1; ++S, ++N) { OutBuf[N] = OutBuf[N - 1] ^ *S; } delete[] OutBuf; } // Bitcode parsing without any additional operations. This is the minimum // required to actually extract information from PNaCl bitcode. { TimingOperationBlock T("Bitcode block parsing", BufSize); NaClBitcodeHeader Header; if (Header.Read(BufPtr, EndBufPtr)) { report_fatal_error("Invalid PNaCl bitcode header"); } if (!Header.IsSupported()) { errs() << "Warning: " << Header.Unsupported() << "\n"; } if (!Header.IsReadable()) { report_fatal_error("Bitcode file is not readable"); } NaClBitstreamReader StreamFile(BufPtr, EndBufPtr); NaClBitstreamCursor Stream(StreamFile); StreamFile.CollectBlockInfoNames(); DummyBitcodeParser Parser(Stream); while (!Stream.AtEndOfStream()) { if (Parser.Parse()) { report_fatal_error("Parsing failed"); } } } // Actual LLVM IR parsing and formation from the bitcode { TimingOperationBlock T("LLVM IR parsing", BufSize); SMDiagnostic Err; Module *M = NaClParseIRFile(InputFilename, PNaClFormat, Err, getGlobalContext()); if (!M) { report_fatal_error("Unable to NaClParseIRFile"); } } }
CXDiagnosticSet DiagLoader::load(const char *file) { // Open the diagnostics file. std::string ErrStr; FileSystemOptions FO; FileManager FileMgr(FO); OwningPtr<llvm::MemoryBuffer> Buffer; Buffer.reset(FileMgr.getBufferForFile(file)); if (!Buffer) { reportBad(CXLoadDiag_CannotLoad, ErrStr); return 0; } llvm::BitstreamReader StreamFile; StreamFile.init((const unsigned char *)Buffer->getBufferStart(), (const unsigned char *)Buffer->getBufferEnd()); llvm::BitstreamCursor Stream; Stream.init(StreamFile); // Sniff for the signature. if (Stream.Read(8) != 'D' || Stream.Read(8) != 'I' || Stream.Read(8) != 'A' || Stream.Read(8) != 'G') { reportBad(CXLoadDiag_InvalidFile, "Bad header in diagnostics file"); return 0; } OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl()); while (true) { unsigned BlockID = 0; StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level", BlockID, true); switch (Res) { case Read_EndOfStream: return (CXDiagnosticSet) Diags.take(); case Read_Failure: return 0; case Read_Record: llvm_unreachable("Top-level does not have records"); case Read_BlockEnd: continue; case Read_BlockBegin: break; } switch (BlockID) { case serialized_diags::BLOCK_META: if (readMetaBlock(Stream)) return 0; break; case serialized_diags::BLOCK_DIAG: if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get())) return 0; break; default: if (!Stream.SkipBlock()) { reportInvalidFile("Malformed block at top-level of diagnostics file"); return 0; } break; } } }
error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, OwningPtr<MemoryBuffer> &result, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator) { static int PageSize = sys::Process::GetPageSize(); // Default is to map the full file. if (MapSize == uint64_t(-1)) { // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. if (FileSize == uint64_t(-1)) { struct stat FileInfo; // TODO: This should use fstat64 when available. if (fstat(FD, &FileInfo) == -1) { return error_code(errno, posix_category()); } FileSize = FileInfo.st_size; } MapSize = FileSize; } if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, PageSize)) { off_t RealMapOffset = Offset & ~(PageSize - 1); off_t Delta = Offset - RealMapOffset; size_t RealMapSize = MapSize + Delta; if (const char *Pages = sys::Path::MapInFilePages(FD, RealMapSize, RealMapOffset)) { result.reset(GetNamedBuffer<MemoryBufferMMapFile>( StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); if (RequiresNullTerminator && result->getBufferEnd()[0] != '\0') { // There could be a racing issue that resulted in the file being larger // than the FileSize passed by the caller. We already have an assertion // for this in MemoryBuffer::init() but have a runtime guarantee that // the buffer will be null-terminated here, so do a copy that adds a // null-terminator. result.reset(MemoryBuffer::getMemBufferCopy(result->getBuffer(), Filename)); } return error_code::success(); } } MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); if (!Buf) { // Failed to create a buffer. The only way it can fail is if // new(std::nothrow) returns 0. return make_error_code(errc::not_enough_memory); } OwningPtr<MemoryBuffer> SB(Buf); char *BufPtr = const_cast<char*>(SB->getBufferStart()); size_t BytesLeft = MapSize; #ifndef HAVE_PREAD if (lseek(FD, Offset, SEEK_SET) == -1) return error_code(errno, posix_category()); #endif while (BytesLeft) { #ifdef HAVE_PREAD ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); #else ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); #endif if (NumRead == -1) { if (errno == EINTR) continue; // Error while reading. return error_code(errno, posix_category()); } if (NumRead == 0) { assert(0 && "We got inaccurate FileSize value or fstat reported an " "invalid file size."); *BufPtr = '\0'; // null-terminate at the actual size. break; } BytesLeft -= NumRead; BufPtr += NumRead; } result.swap(SB); return error_code::success(); }