[llvm-commits] CVS: llvm/lib/Support/MemoryBuffer.cpp

Chris Lattner sabre at nondot.org
Sat Apr 28 23:59:15 PDT 2007



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;
+ }






More information about the llvm-commits mailing list