1 //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the MemoryBuffer interface.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Support/MemoryBuffer.h"
15 #include "llvm/System/MappedFile.h"
16 #include "llvm/System/Process.h"
17 #include "llvm/System/Program.h"
24 //===----------------------------------------------------------------------===//
25 // MemoryBuffer implementation itself.
26 //===----------------------------------------------------------------------===//
28 MemoryBuffer::~MemoryBuffer() {
30 delete [] BufferStart;
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
36 void 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;
45 /// init - Initialize this MemoryBuffer as a reference to externally allocated
46 /// memory, memory that we know is already null terminated.
47 void MemoryBuffer::init(const char *BufStart, const char *BufEnd) {
48 assert(BufEnd[0] == 0 && "Buffer is not null terminated!");
49 BufferStart = BufStart;
51 MustDeleteBuffer = false;
54 //===----------------------------------------------------------------------===//
55 // MemoryBufferMem implementation.
56 //===----------------------------------------------------------------------===//
59 class MemoryBufferMem : public MemoryBuffer {
62 MemoryBufferMem(const char *Start, const char *End, const char *FID,
68 initCopyOf(Start, End);
71 virtual const char *getBufferIdentifier() const {
72 return FileID.c_str();
77 /// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note
78 /// that EndPtr[0] must be a null byte and be accessible!
79 MemoryBuffer *MemoryBuffer::getMemBuffer(const char *StartPtr,
81 const char *BufferName) {
82 return new MemoryBufferMem(StartPtr, EndPtr, BufferName);
85 /// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
86 /// copying the contents and taking ownership of it. This has no requirements
88 MemoryBuffer *MemoryBuffer::getMemBufferCopy(const char *StartPtr,
90 const char *BufferName) {
91 return new MemoryBufferMem(StartPtr, EndPtr, BufferName, true);
94 /// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
95 /// that is completely initialized to zeros. Note that the caller should
96 /// initialize the memory allocated by this method. The memory is owned by
97 /// the MemoryBuffer object.
98 MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(unsigned Size,
99 const char *BufferName) {
100 char *Buf = new char[Size+1];
102 MemoryBufferMem *SB = new MemoryBufferMem(Buf, Buf+Size, BufferName);
103 // The memory for this buffer is owned by the MemoryBuffer.
104 SB->MustDeleteBuffer = true;
108 /// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
109 /// is completely initialized to zeros. Note that the caller should
110 /// initialize the memory allocated by this method. The memory is owned by
111 /// the MemoryBuffer object.
112 MemoryBuffer *MemoryBuffer::getNewMemBuffer(unsigned Size,
113 const char *BufferName) {
114 MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
115 memset(const_cast<char*>(SB->getBufferStart()), 0, Size+1);
120 /// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
121 /// if the Filename is "-". If an error occurs, this returns null and fills
122 /// in *ErrStr with a reason. If stdin is empty, this API (unlike getSTDIN)
123 /// returns an empty buffer.
124 MemoryBuffer *MemoryBuffer::getFileOrSTDIN(const char *FilenameStart,
128 if (FnSize != 1 || FilenameStart[0] != '-')
129 return getFile(FilenameStart, FnSize, ErrStr, FileSize);
130 MemoryBuffer *M = getSTDIN();
133 // If stdin was empty, M is null. Cons up an empty memory buffer now.
134 const char *EmptyStr = "";
135 return MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<stdin>");
138 //===----------------------------------------------------------------------===//
139 // MemoryBufferMMapFile implementation.
140 //===----------------------------------------------------------------------===//
143 class MemoryBufferMMapFile : public MemoryBuffer {
144 sys::MappedFile File;
146 MemoryBufferMMapFile() {}
148 bool open(const sys::Path &Filename, std::string *ErrStr);
150 virtual const char *getBufferIdentifier() const {
151 return File.path().c_str();
154 ~MemoryBufferMMapFile();
158 bool MemoryBufferMMapFile::open(const sys::Path &Filename,
159 std::string *ErrStr) {
160 // FIXME: This does an extra stat syscall to figure out the size, but we
161 // already know the size!
162 bool Failure = File.open(Filename, sys::MappedFile::READ_ACCESS, ErrStr);
163 if (Failure) return true;
165 if (!File.map(ErrStr))
168 size_t Size = File.size();
170 static unsigned PageSize = sys::Process::GetPageSize();
171 assert(((PageSize & (PageSize-1)) == 0) && PageSize &&
172 "Page size is not a power of 2!");
174 // If this file is not an exact multiple of the system page size (common
175 // case), then the OS has zero terminated the buffer for us.
176 if ((Size & (PageSize-1))) {
177 init(File.charBase(), File.charBase()+Size);
179 // Otherwise, we allocate a new memory buffer and copy the data over
180 initCopyOf(File.charBase(), File.charBase()+Size);
182 // No need to keep the file mapped any longer.
188 MemoryBufferMMapFile::~MemoryBufferMMapFile() {
193 //===----------------------------------------------------------------------===//
194 // MemoryBuffer::getFile implementation.
195 //===----------------------------------------------------------------------===//
197 MemoryBuffer *MemoryBuffer::getFile(const char *FilenameStart, unsigned FnSize,
198 std::string *ErrStr, int64_t FileSize){
199 // FIXME: it would be nice if PathWithStatus didn't copy the filename into a
200 // temporary string. :(
201 sys::PathWithStatus P(FilenameStart, FnSize);
203 MemoryBufferMMapFile *M = new MemoryBufferMMapFile();
204 if (!M->open(P, ErrStr))
209 // FIXME: We need an efficient and portable method to open a file and then use
210 // 'read' to copy the bits out. The unix implementation is below. This is
211 // an important optimization for clients that want to open large numbers of
212 // small files (using mmap on everything can easily exhaust address space!).
214 // If the user didn't specify a filesize, do a stat to find it.
215 if (FileSize == -1) {
216 const sys::FileStatus *FS = P.getFileStatus();
217 if (FS == 0) return 0; // Error stat'ing file.
219 FileSize = FS->fileSize;
222 // If the file is larger than some threshold, use mmap, otherwise use 'read'.
223 if (FileSize >= 4096*4) {
224 MemoryBufferMMapFile *M = new MemoryBufferMMapFile();
225 if (!M->open(P, ErrStr))
231 MemoryBuffer *SB = getNewUninitMemBuffer(FileSize, FilenameStart);
232 char *BufPtr = const_cast<char*>(SB->getBufferStart());
234 int FD = ::open(FilenameStart, O_RDONLY);
240 unsigned BytesLeft = FileSize;
242 ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
244 BytesLeft -= NumRead;
246 } else if (errno == EINTR) {
262 //===----------------------------------------------------------------------===//
263 // MemoryBuffer::getSTDIN implementation.
264 //===----------------------------------------------------------------------===//
267 class STDINBufferFile : public MemoryBuffer {
269 virtual const char *getBufferIdentifier() const {
275 MemoryBuffer *MemoryBuffer::getSTDIN() {
278 std::vector<char> FileData;
280 // Read in all of the data from stdin, we cannot mmap stdin.
281 sys::Program::ChangeStdinToBinary();
282 while (size_t ReadBytes = fread(Buffer, sizeof(char), 4096*4, stdin))
283 FileData.insert(FileData.end(), Buffer, Buffer+ReadBytes);
285 FileData.push_back(0); // &FileData[Size] is invalid. So is &*FileData.end().
286 size_t Size = FileData.size();
289 MemoryBuffer *B = new STDINBufferFile();
290 B->initCopyOf(&FileData[0], &FileData[Size-1]);