LLVM API Documentation

MemoryBuffer.cpp

Go to the documentation of this file.
00001 //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
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 MemoryBuffer interface.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "llvm/Support/MemoryBuffer.h"
00015 #include "llvm/ADT/OwningPtr.h"
00016 #include "llvm/ADT/SmallString.h"
00017 #include "llvm/System/Path.h"
00018 #include "llvm/System/Process.h"
00019 #include "llvm/System/Program.h"
00020 #include <cassert>
00021 #include <cstdio>
00022 #include <cstring>
00023 #include <cerrno>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #if !defined(_MSC_VER) && !defined(__MINGW32__)
00027 #include <unistd.h>
00028 #include <sys/uio.h>
00029 #else
00030 #include <io.h>
00031 #endif
00032 #include <fcntl.h>
00033 using namespace llvm;
00034 
00035 //===----------------------------------------------------------------------===//
00036 // MemoryBuffer implementation itself.
00037 //===----------------------------------------------------------------------===//
00038 
00039 MemoryBuffer::~MemoryBuffer() {
00040   if (MustDeleteBuffer)
00041     delete [] BufferStart;
00042 }
00043 
00044 /// initCopyOf - Initialize this source buffer with a copy of the specified
00045 /// memory range.  We make the copy so that we can null terminate it
00046 /// successfully.
00047 void MemoryBuffer::initCopyOf(const char *BufStart, const char *BufEnd) {
00048   size_t Size = BufEnd-BufStart;
00049   BufferStart = new char[Size+1];
00050   BufferEnd = BufferStart+Size;
00051   memcpy(const_cast<char*>(BufferStart), BufStart, Size);
00052   *const_cast<char*>(BufferEnd) = 0;   // Null terminate buffer.
00053   MustDeleteBuffer = true;
00054 }
00055 
00056 /// init - Initialize this MemoryBuffer as a reference to externally allocated
00057 /// memory, memory that we know is already null terminated.
00058 void MemoryBuffer::init(const char *BufStart, const char *BufEnd) {
00059   assert(BufEnd[0] == 0 && "Buffer is not null terminated!");
00060   BufferStart = BufStart;
00061   BufferEnd = BufEnd;
00062   MustDeleteBuffer = false;
00063 }
00064 
00065 //===----------------------------------------------------------------------===//
00066 // MemoryBufferMem implementation.
00067 //===----------------------------------------------------------------------===//
00068 
00069 namespace {
00070 class MemoryBufferMem : public MemoryBuffer {
00071   std::string FileID;
00072 public:
00073   MemoryBufferMem(const char *Start, const char *End, const char *FID,
00074                   bool Copy = false)
00075   : FileID(FID) {
00076     if (!Copy)
00077       init(Start, End);
00078     else
00079       initCopyOf(Start, End);
00080   }
00081   
00082   virtual const char *getBufferIdentifier() const {
00083     return FileID.c_str();
00084   }
00085 };
00086 }
00087 
00088 /// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
00089 /// that EndPtr[0] must be a null byte and be accessible!
00090 MemoryBuffer *MemoryBuffer::getMemBuffer(const char *StartPtr, 
00091                                          const char *EndPtr,
00092                                          const char *BufferName) {
00093   return new MemoryBufferMem(StartPtr, EndPtr, BufferName);
00094 }
00095 
00096 /// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
00097 /// copying the contents and taking ownership of it.  This has no requirements
00098 /// on EndPtr[0].
00099 MemoryBuffer *MemoryBuffer::getMemBufferCopy(const char *StartPtr, 
00100                                              const char *EndPtr,
00101                                              const char *BufferName) {
00102   return new MemoryBufferMem(StartPtr, EndPtr, BufferName, true);
00103 }
00104 
00105 /// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
00106 /// that is completely initialized to zeros.  Note that the caller should
00107 /// initialize the memory allocated by this method.  The memory is owned by
00108 /// the MemoryBuffer object.
00109 MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
00110                                                   const char *BufferName) {
00111   char *Buf = new char[Size+1];
00112   Buf[Size] = 0;
00113   MemoryBufferMem *SB = new MemoryBufferMem(Buf, Buf+Size, BufferName);
00114   // The memory for this buffer is owned by the MemoryBuffer.
00115   SB->MustDeleteBuffer = true;
00116   return SB;
00117 }
00118 
00119 /// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
00120 /// is completely initialized to zeros.  Note that the caller should
00121 /// initialize the memory allocated by this method.  The memory is owned by
00122 /// the MemoryBuffer object.
00123 MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size,
00124                                             const char *BufferName) {
00125   MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
00126   memset(const_cast<char*>(SB->getBufferStart()), 0, Size+1);
00127   return SB;
00128 }
00129 
00130 
00131 /// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
00132 /// if the Filename is "-".  If an error occurs, this returns null and fills
00133 /// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
00134 /// returns an empty buffer.
00135 MemoryBuffer *MemoryBuffer::getFileOrSTDIN(const char *Filename,
00136                                            std::string *ErrStr,
00137                                            int64_t FileSize) {
00138   if (Filename[0] != '-' || Filename[1] != 0)
00139     return getFile(Filename, ErrStr, FileSize);
00140   MemoryBuffer *M = getSTDIN();
00141   if (M) return M;
00142 
00143   // If stdin was empty, M is null.  Cons up an empty memory buffer now.
00144   const char *EmptyStr = "";
00145   return MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<stdin>");
00146 }
00147 
00148 //===----------------------------------------------------------------------===//
00149 // MemoryBuffer::getFile implementation.
00150 //===----------------------------------------------------------------------===//
00151 
00152 namespace {
00153 /// MemoryBufferMMapFile - This represents a file that was mapped in with the
00154 /// sys::Path::MapInFilePages method.  When destroyed, it calls the
00155 /// sys::Path::UnMapFilePages method.
00156 class MemoryBufferMMapFile : public MemoryBuffer {
00157   std::string Filename;
00158 public:
00159   MemoryBufferMMapFile(const char *filename, const char *Pages, uint64_t Size)
00160     : Filename(filename) {
00161     init(Pages, Pages+Size);
00162   }
00163   
00164   virtual const char *getBufferIdentifier() const {
00165     return Filename.c_str();
00166   }
00167     
00168   ~MemoryBufferMMapFile() {
00169     sys::Path::UnMapFilePages(getBufferStart(), getBufferSize());
00170   }
00171 };
00172 }
00173 
00174 MemoryBuffer *MemoryBuffer::getFile(const char *Filename, std::string *ErrStr,
00175                                     int64_t FileSize) {
00176   int OpenFlags = 0;
00177 #ifdef O_BINARY
00178   OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
00179 #endif
00180   int FD = ::open(Filename, O_RDONLY|OpenFlags);
00181   if (FD == -1) {
00182     if (ErrStr) *ErrStr = "could not open file";
00183     return 0;
00184   }
00185   
00186   // If we don't know the file size, use fstat to find out.  fstat on an open
00187   // file descriptor is cheaper than stat on a random path.
00188   if (FileSize == -1) {
00189     struct stat FileInfo;
00190     // TODO: This should use fstat64 when available.
00191     if (fstat(FD, &FileInfo) == -1) {
00192       if (ErrStr) *ErrStr = "could not get file length";
00193       ::close(FD);
00194       return 0;
00195     }
00196     FileSize = FileInfo.st_size;
00197   }
00198   
00199   
00200   // If the file is large, try to use mmap to read it in.  We don't use mmap
00201   // for small files, because this can severely fragment our address space. Also
00202   // don't try to map files that are exactly a multiple of the system page size,
00203   // as the file would not have the required null terminator.
00204   if (FileSize >= 4096*4 &&
00205       (FileSize & (sys::Process::GetPageSize()-1)) != 0) {
00206     if (const char *Pages = sys::Path::MapInFilePages(FD, FileSize)) {
00207       // Close the file descriptor, now that the whole file is in memory.
00208       ::close(FD);
00209       return new MemoryBufferMMapFile(Filename, Pages, FileSize);
00210     }
00211   }
00212   
00213   OwningPtr<MemoryBuffer> SB;
00214   SB.reset(MemoryBuffer::getNewUninitMemBuffer(FileSize, Filename));
00215   char *BufPtr = const_cast<char*>(SB->getBufferStart());
00216   
00217   size_t BytesLeft = FileSize;
00218   while (BytesLeft) {
00219     ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
00220     if (NumRead != -1) {
00221       BytesLeft -= NumRead;
00222       BufPtr += NumRead;
00223     } else if (errno == EINTR) {
00224       // try again
00225     } else {
00226       // error reading.
00227       close(FD);
00228       if (ErrStr) *ErrStr = "error reading file data";
00229       return 0;
00230     }
00231   }
00232   close(FD);
00233   
00234   return SB.take();
00235 }
00236 
00237 //===----------------------------------------------------------------------===//
00238 // MemoryBuffer::getSTDIN implementation.
00239 //===----------------------------------------------------------------------===//
00240 
00241 namespace {
00242 class STDINBufferFile : public MemoryBuffer {
00243 public:
00244   virtual const char *getBufferIdentifier() const {
00245     return "<stdin>";
00246   }
00247 };
00248 }
00249 
00250 MemoryBuffer *MemoryBuffer::getSTDIN() {
00251   char Buffer[4096*4];
00252   
00253   std::vector<char> FileData;
00254   
00255   // Read in all of the data from stdin, we cannot mmap stdin.
00256   sys::Program::ChangeStdinToBinary();
00257   while (size_t ReadBytes = fread(Buffer, sizeof(char), 4096*4, stdin))
00258     FileData.insert(FileData.end(), Buffer, Buffer+ReadBytes);
00259 
00260   FileData.push_back(0); // &FileData[Size] is invalid. So is &*FileData.end().
00261   size_t Size = FileData.size();
00262   if (Size <= 1)
00263     return 0;
00264   MemoryBuffer *B = new STDINBufferFile();
00265   B->initCopyOf(&FileData[0], &FileData[Size-1]);
00266   return B;
00267 }