MemoryBuffer.cpp revision ea332946d3577cc75422a1ad0cbce9321e9e8c59
1//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file was developed by Chris Lattner and is distributed under 6// the University of Illinois Open Source License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the MemoryBuffer interface. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/Support/MemoryBuffer.h" 15#include "llvm/System/MappedFile.h" 16#include "llvm/System/Process.h" 17#include "llvm/System/Program.h" 18#include <cassert> 19#include <cstdio> 20#include <cstring> 21#include <cerrno> 22using namespace llvm; 23 24//===----------------------------------------------------------------------===// 25// MemoryBuffer implementation itself. 26//===----------------------------------------------------------------------===// 27 28MemoryBuffer::~MemoryBuffer() { 29 if (MustDeleteBuffer) 30 delete [] BufferStart; 31} 32 33/// initCopyOf - Initialize this source buffer with a copy of the specified 34/// memory range. We make the copy so that we can null terminate it 35/// successfully. 36void MemoryBuffer::initCopyOf(const char *BufStart, const char *BufEnd) { 37 size_t Size = BufEnd-BufStart; 38 BufferStart = new char[Size+1]; 39 BufferEnd = BufferStart+Size; 40 memcpy(const_cast<char*>(BufferStart), BufStart, Size); 41 *const_cast<char*>(BufferEnd) = 0; // Null terminate buffer. 42 MustDeleteBuffer = true; 43} 44 45/// init - Initialize this MemoryBuffer as a reference to externally allocated 46/// memory, memory that we know is already null terminated. 47void MemoryBuffer::init(const char *BufStart, const char *BufEnd) { 48 assert(BufEnd[0] == 0 && "Buffer is not null terminated!"); 49 BufferStart = BufStart; 50 BufferEnd = BufEnd; 51 MustDeleteBuffer = false; 52} 53 54//===----------------------------------------------------------------------===// 55// MemoryBufferMem implementation. 56//===----------------------------------------------------------------------===// 57 58namespace { 59class MemoryBufferMem : public MemoryBuffer { 60 std::string FileID; 61public: 62 MemoryBufferMem(const char *Start, const char *End, const char *FID) 63 : FileID(FID) { 64 init(Start, End); 65 } 66 67 virtual const char *getBufferIdentifier() const { 68 return FileID.c_str(); 69 } 70}; 71} 72 73/// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note 74/// that EndPtr[0] must be a null byte and be accessible! 75MemoryBuffer *MemoryBuffer::getMemBuffer(const char *StartPtr, 76 const char *EndPtr, 77 const char *BufferName) { 78 return new MemoryBufferMem(StartPtr, EndPtr, BufferName); 79} 80 81/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size 82/// that is completely initialized to zeros. Note that the caller should 83/// initialize the memory allocated by this method. The memory is owned by 84/// the MemoryBuffer object. 85MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(unsigned Size, 86 const char *BufferName) { 87 char *Buf = new char[Size+1]; 88 Buf[Size] = 0; 89 MemoryBufferMem *SB = new MemoryBufferMem(Buf, Buf+Size, BufferName); 90 // The memory for this buffer is owned by the MemoryBuffer. 91 SB->MustDeleteBuffer = true; 92 return SB; 93} 94 95/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that 96/// is completely initialized to zeros. Note that the caller should 97/// initialize the memory allocated by this method. The memory is owned by 98/// the MemoryBuffer object. 99MemoryBuffer *MemoryBuffer::getNewMemBuffer(unsigned Size, 100 const char *BufferName) { 101 MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName); 102 memset(const_cast<char*>(SB->getBufferStart()), 0, Size+1); 103 return SB; 104} 105 106 107//===----------------------------------------------------------------------===// 108// MemoryBufferMMapFile implementation. 109//===----------------------------------------------------------------------===// 110 111namespace { 112class MemoryBufferMMapFile : public MemoryBuffer { 113 sys::MappedFile File; 114public: 115 MemoryBufferMMapFile() {} 116 117 bool open(const sys::Path &Filename, std::string *ErrStr); 118 119 virtual const char *getBufferIdentifier() const { 120 return File.path().c_str(); 121 } 122 123 ~MemoryBufferMMapFile(); 124}; 125} 126 127bool MemoryBufferMMapFile::open(const sys::Path &Filename, 128 std::string *ErrStr) { 129 // FIXME: This does an extra stat syscall to figure out the size, but we 130 // already know the size! 131 bool Failure = File.open(Filename, sys::MappedFile::READ_ACCESS, ErrStr); 132 if (Failure) return true; 133 134 if (!File.map(ErrStr)) 135 return true; 136 137 size_t Size = File.size(); 138 139 static unsigned PageSize = sys::Process::GetPageSize(); 140 assert(((PageSize & (PageSize-1)) == 0) && PageSize && 141 "Page size is not a power of 2!"); 142 143 // If this file is not an exact multiple of the system page size (common 144 // case), then the OS has zero terminated the buffer for us. 145 if ((Size & (PageSize-1))) { 146 init(File.charBase(), File.charBase()+Size); 147 } else { 148 // Otherwise, we allocate a new memory buffer and copy the data over 149 initCopyOf(File.charBase(), File.charBase()+Size); 150 151 // No need to keep the file mapped any longer. 152 File.unmap(); 153 } 154 return false; 155} 156 157MemoryBufferMMapFile::~MemoryBufferMMapFile() { 158 if (File.isMapped()) 159 File.unmap(); 160} 161 162//===----------------------------------------------------------------------===// 163// MemoryBuffer::getFile implementation. 164//===----------------------------------------------------------------------===// 165 166MemoryBuffer *MemoryBuffer::getFile(const char *FilenameStart, unsigned FnSize, 167 std::string *ErrStr, int64_t FileSize){ 168 // FIXME: it would be nice if PathWithStatus didn't copy the filename into a 169 // temporary string. :( 170 sys::PathWithStatus P(FilenameStart, FnSize); 171#if 1 172 MemoryBufferMMapFile *M = new MemoryBufferMMapFile(); 173 if (!M->open(P, ErrStr)) 174 return M; 175 delete M; 176 return 0; 177#else 178 // FIXME: We need an efficient and portable method to open a file and then use 179 // 'read' to copy the bits out. The unix implementation is below. This is 180 // an important optimization for clients that want to open large numbers of 181 // small files (using mmap on everything can easily exhaust address space!). 182 183 // If the user didn't specify a filesize, do a stat to find it. 184 if (FileSize == -1) { 185 const sys::FileStatus *FS = P.getFileStatus(); 186 if (FS == 0) return 0; // Error stat'ing file. 187 188 FileSize = FS->fileSize; 189 } 190 191 // If the file is larger than some threshold, use mmap, otherwise use 'read'. 192 if (FileSize >= 4096*4) { 193 MemoryBufferMMapFile *M = new MemoryBufferMMapFile(); 194 if (!M->open(P, ErrStr)) 195 return M; 196 delete M; 197 return 0; 198 } 199 200 MemoryBuffer *SB = getNewUninitMemBuffer(FileSize, FilenameStart); 201 char *BufPtr = const_cast<char*>(SB->getBufferStart()); 202 203 int FD = ::open(FilenameStart, O_RDONLY); 204 if (FD == -1) { 205 delete SB; 206 return 0; 207 } 208 209 unsigned BytesLeft = FileSize; 210 while (BytesLeft) { 211 ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); 212 if (NumRead != -1) { 213 BytesLeft -= NumRead; 214 BufPtr += NumRead; 215 } else if (errno == EINTR) { 216 // try again 217 } else { 218 // error reading. 219 close(FD); 220 delete SB; 221 return 0; 222 } 223 } 224 close(FD); 225 226 return SB; 227#endif 228} 229 230 231//===----------------------------------------------------------------------===// 232// MemoryBuffer::getSTDIN implementation. 233//===----------------------------------------------------------------------===// 234 235namespace { 236class STDINBufferFile : public MemoryBuffer { 237public: 238 virtual const char *getBufferIdentifier() const { 239 return "<stdin>"; 240 } 241}; 242} 243 244MemoryBuffer *MemoryBuffer::getSTDIN() { 245 char Buffer[4096*4]; 246 247 std::vector<char> FileData; 248 249 // Read in all of the data from stdin, we cannot mmap stdin. 250 sys::Program::ChangeStdinToBinary(); 251 while (size_t ReadBytes = fread(Buffer, 1, 4096*4, stdin)) 252 FileData.insert(FileData.end(), Buffer, Buffer+ReadBytes); 253 254 FileData.push_back(0); // &FileData[Size] is invalid. So is &*FileData.end(). 255 size_t Size = FileData.size(); 256 MemoryBuffer *B = new STDINBufferFile(); 257 B->initCopyOf(&FileData[0], &FileData[Size-1]); 258 return B; 259} 260