Changes in directory llvm/lib/Support:
MemoryBuffer.cpp added (r1.1) --- Log message: Add a new memorybuffer class, to unify all the file reading code in the system --- Diffs of the changes: (+239 -0) MemoryBuffer.cpp | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 239 insertions(+) Index: llvm/lib/Support/MemoryBuffer.cpp diff -c /dev/null llvm/lib/Support/MemoryBuffer.cpp:1.1 *** /dev/null Sun Apr 29 01:59:02 2007 --- llvm/lib/Support/MemoryBuffer.cpp Sun Apr 29 01:58:52 2007 *************** *** 0 **** --- 1,239 ---- + //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Chris Lattner and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements the MemoryBuffer interface. + // + //===----------------------------------------------------------------------===// + + #include "llvm/Support/MemoryBuffer.h" + #include "llvm/System/MappedFile.h" + #include "llvm/System/Process.h" + #include <cstdio> + #include <cstring> + #include <cerrno> + using namespace llvm; + + //===----------------------------------------------------------------------===// + // MemoryBuffer implementation itself. + //===----------------------------------------------------------------------===// + + MemoryBuffer::~MemoryBuffer() { + if (MustDeleteBuffer) + delete [] BufferStart; + } + + /// initCopyOf - Initialize this source buffer with a copy of the specified + /// memory range. We make the copy so that we can null terminate it + /// successfully. + void MemoryBuffer::initCopyOf(const char *BufStart, const char *BufEnd) { + size_t Size = BufEnd-BufStart; + BufferStart = new char[Size+1]; + BufferEnd = BufferStart+Size; + memcpy(const_cast<char*>(BufferStart), BufStart, Size); + *const_cast<char*>(BufferEnd) = 0; // Null terminate buffer. + MustDeleteBuffer = false; + } + + /// init - Initialize this MemoryBuffer as a reference to externally allocated + /// memory, memory that we know is already null terminated. + void MemoryBuffer::init(const char *BufStart, const char *BufEnd) { + assert(BufEnd[0] == 0 && "Buffer is not null terminated!"); + BufferStart = BufStart; + BufferEnd = BufEnd; + MustDeleteBuffer = false; + } + + //===----------------------------------------------------------------------===// + // MemoryBufferMem implementation. + //===----------------------------------------------------------------------===// + + namespace { + class MemoryBufferMem : public MemoryBuffer { + std::string FileID; + public: + MemoryBufferMem(const char *Start, const char *End, const char *FID) + : FileID(FID) { + init(Start, End); + } + + virtual const char *getBufferIdentifier() const { + return FileID.c_str(); + } + }; + } + + /// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note + /// that EndPtr[0] must be a null byte and be accessible! + MemoryBuffer *MemoryBuffer::getMemBuffer(const char *StartPtr, + const char *EndPtr, + const char *BufferName) { + return new MemoryBufferMem(StartPtr, EndPtr, BufferName); + } + + /// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size + /// that is completely initialized to zeros. Note that the caller should + /// initialize the memory allocated by this method. The memory is owned by + /// the MemoryBuffer object. + MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(unsigned Size, + const char *BufferName) { + char *Buf = new char[Size+1]; + Buf[Size] = 0; + MemoryBufferMem *SB = new MemoryBufferMem(Buf, Buf+Size, BufferName); + // The memory for this buffer is owned by the MemoryBuffer. + SB->MustDeleteBuffer = true; + return SB; + } + + /// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that + /// is completely initialized to zeros. Note that the caller should + /// initialize the memory allocated by this method. The memory is owned by + /// the MemoryBuffer object. + MemoryBuffer *MemoryBuffer::getNewMemBuffer(unsigned Size, + const char *BufferName) { + MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName); + memset(const_cast<char*>(SB->getBufferStart()), 0, Size+1); + return SB; + } + + + //===----------------------------------------------------------------------===// + // MemoryBufferMMapFile implementation. + //===----------------------------------------------------------------------===// + + namespace { + class MemoryBufferMMapFile : public MemoryBuffer { + sys::MappedFile File; + public: + MemoryBufferMMapFile(const sys::Path &Filename); + + virtual const char *getBufferIdentifier() const { + return File.path().c_str(); + } + + ~MemoryBufferMMapFile(); + }; + } + + MemoryBufferMMapFile::MemoryBufferMMapFile(const sys::Path &Filename) { + // FIXME: This does an extra stat syscall to figure out the size, but we + // already know the size! + bool Failure = File.open(Filename); + Failure = Failure; // Silence warning in no-asserts mode. + assert(!Failure && "Can't open file??"); + + File.map(); + + size_t Size = File.size(); + + static unsigned PageSize = sys::Process::GetPageSize(); + assert(((PageSize & (PageSize-1)) == 0) && PageSize && + "Page size is not a power of 2!"); + + // If this file is not an exact multiple of the system page size (common + // case), then the OS has zero terminated the buffer for us. + if ((Size & (PageSize-1))) { + init(File.charBase(), File.charBase()+Size); + } else { + // Otherwise, we allocate a new memory buffer and copy the data over + initCopyOf(File.charBase(), File.charBase()+Size); + + // No need to keep the file mapped any longer. + File.unmap(); + } + } + + MemoryBufferMMapFile::~MemoryBufferMMapFile() { + File.unmap(); + } + + //===----------------------------------------------------------------------===// + // MemoryBuffer::getFile implementation. + //===----------------------------------------------------------------------===// + + MemoryBuffer *MemoryBuffer::getFile(const char *FilenameStart, unsigned FnSize, + int64_t FileSize) { + sys::PathWithStatus P(FilenameStart, FnSize); + #if 1 + return new MemoryBufferMMapFile(P); + #else + // FIXME: We need an efficient and portable method to open a file and then use + // 'read' to copy the bits out. The unix implementation is below. This is + // an important optimization for clients that want to open large numbers of + // small files (using mmap on everything can easily exhaust address space!). + + // If the user didn't specify a filesize, do a stat to find it. + if (FileSize == -1) { + const sys::FileStatus *FS = P.getFileStatus(); + if (FS == 0) return 0; // Error stat'ing file. + + FileSize = FS->fileSize; + } + + // If the file is larger than some threshold, use mmap, otherwise use 'read'. + if (FileSize >= 4096*4) + return new MemoryBufferMMapFile(P); + + MemoryBuffer *SB = getNewUninitMemBuffer(FileSize, FilenameStart); + char *BufPtr = const_cast<char*>(SB->getBufferStart()); + + int FD = ::open(FilenameStart, O_RDONLY); + if (FD == -1) { + delete SB; + return 0; + } + + unsigned BytesLeft = FileSize; + while (BytesLeft) { + ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); + if (NumRead != -1) { + BytesLeft -= NumRead; + BufPtr += NumRead; + } else if (errno == EINTR) { + // try again + } else { + // error reading. + close(FD); + delete SB; + return 0; + } + } + close(FD); + + return SB; + #endif + } + + + //===----------------------------------------------------------------------===// + // MemoryBuffer::getSTDIN implementation. + //===----------------------------------------------------------------------===// + + namespace { + class STDINBufferFile : public MemoryBuffer { + public: + virtual const char *getBufferIdentifier() const { + return "<stdin>"; + } + }; + } + + MemoryBuffer *MemoryBuffer::getSTDIN() { + char Buffer[4096*4]; + + std::vector<char> FileData; + + // Read in all of the data from stdin, we cannot mmap stdin. + while (size_t ReadBytes = fread(Buffer, 1, 4096*4, stdin)) + FileData.insert(FileData.end(), Buffer, Buffer+ReadBytes); + + size_t Size = FileData.size(); + MemoryBuffer *B = new STDINBufferFile(); + B->initCopyOf(&FileData[0], &FileData[Size]); + return B; + } _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits