/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Support/MemoryBuffer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file implements the MemoryBuffer interface. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "llvm/Support/MemoryBuffer.h" |
14 | | #include "llvm/ADT/SmallString.h" |
15 | | #include "llvm/Config/config.h" |
16 | | #include "llvm/Support/Errc.h" |
17 | | #include "llvm/Support/Errno.h" |
18 | | #include "llvm/Support/FileSystem.h" |
19 | | #include "llvm/Support/MathExtras.h" |
20 | | #include "llvm/Support/Path.h" |
21 | | #include "llvm/Support/Process.h" |
22 | | #include "llvm/Support/Program.h" |
23 | | #include "llvm/Support/SmallVectorMemoryBuffer.h" |
24 | | #include <cassert> |
25 | | #include <cerrno> |
26 | | #include <cstring> |
27 | | #include <new> |
28 | | #include <sys/types.h> |
29 | | #include <system_error> |
30 | | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
31 | | #include <unistd.h> |
32 | | #else |
33 | | #include <io.h> |
34 | | #endif |
35 | | using namespace llvm; |
36 | | |
37 | | //===----------------------------------------------------------------------===// |
38 | | // MemoryBuffer implementation itself. |
39 | | //===----------------------------------------------------------------------===// |
40 | | |
41 | 607k | MemoryBuffer::~MemoryBuffer() { } |
42 | | |
43 | | /// init - Initialize this MemoryBuffer as a reference to externally allocated |
44 | | /// memory, memory that we know is already null terminated. |
45 | | void MemoryBuffer::init(const char *BufStart, const char *BufEnd, |
46 | 1.08M | bool RequiresNullTerminator) { |
47 | 1.08M | assert((!RequiresNullTerminator || BufEnd[0] == 0) && |
48 | 1.08M | "Buffer is not null terminated!"); |
49 | 1.08M | BufferStart = BufStart; |
50 | 1.08M | BufferEnd = BufEnd; |
51 | 1.08M | } |
52 | | |
53 | | //===----------------------------------------------------------------------===// |
54 | | // MemoryBufferMem implementation. |
55 | | //===----------------------------------------------------------------------===// |
56 | | |
57 | | /// CopyStringRef - Copies contents of a StringRef into a block of memory and |
58 | | /// null-terminates it. |
59 | 1.08M | static void CopyStringRef(char *Memory, StringRef Data) { |
60 | 1.08M | if (!Data.empty()) |
61 | 1.01M | memcpy(Memory, Data.data(), Data.size()); |
62 | 1.08M | Memory[Data.size()] = 0; // Null terminate string. |
63 | 1.08M | } |
64 | | |
65 | | namespace { |
66 | | struct NamedBufferAlloc { |
67 | | const Twine &Name; |
68 | 267k | NamedBufferAlloc(const Twine &Name) : Name(Name) {} |
69 | | }; |
70 | | } |
71 | | |
72 | 267k | void *operator new(size_t N, const NamedBufferAlloc &Alloc) { |
73 | 267k | SmallString<256> NameBuf; |
74 | 267k | StringRef NameRef = Alloc.Name.toStringRef(NameBuf); |
75 | 267k | |
76 | 267k | char *Mem = static_cast<char *>(operator new(N + NameRef.size() + 1)); |
77 | 267k | CopyStringRef(Mem + N, NameRef); |
78 | 267k | return Mem; |
79 | 267k | } |
80 | | |
81 | | namespace { |
82 | | /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. |
83 | | template<typename MB> |
84 | | class MemoryBufferMem : public MB { |
85 | | public: |
86 | 1.01M | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { |
87 | 1.01M | MemoryBuffer::init(InputData.begin(), InputData.end(), |
88 | 1.01M | RequiresNullTerminator); |
89 | 1.01M | } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::MemoryBuffer>::MemoryBufferMem(llvm::StringRef, bool) Line | Count | Source | 86 | 195k | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { | 87 | 195k | MemoryBuffer::init(InputData.begin(), InputData.end(), | 88 | 195k | RequiresNullTerminator); | 89 | 195k | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::WritableMemoryBuffer>::MemoryBufferMem(llvm::StringRef, bool) Line | Count | Source | 86 | 817k | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { | 87 | 817k | MemoryBuffer::init(InputData.begin(), InputData.end(), | 88 | 817k | RequiresNullTerminator); | 89 | 817k | } |
|
90 | | |
91 | | /// Disable sized deallocation for MemoryBufferMem, because it has |
92 | | /// tail-allocated data. |
93 | 585k | void operator delete(void *p) { ::operator delete(p); } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::MemoryBuffer>::operator delete(void*) Line | Count | Source | 93 | 195k | void operator delete(void *p) { ::operator delete(p); } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::WritableMemoryBuffer>::operator delete(void*) Line | Count | Source | 93 | 390k | void operator delete(void *p) { ::operator delete(p); } |
|
94 | | |
95 | 1.96M | StringRef getBufferIdentifier() const override { |
96 | 1.96M | // The name is stored after the class itself. |
97 | 1.96M | return StringRef(reinterpret_cast<const char *>(this + 1)); |
98 | 1.96M | } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::MemoryBuffer>::getBufferIdentifier() const Line | Count | Source | 95 | 52.0k | StringRef getBufferIdentifier() const override { | 96 | 52.0k | // The name is stored after the class itself. | 97 | 52.0k | return StringRef(reinterpret_cast<const char *>(this + 1)); | 98 | 52.0k | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::WritableMemoryBuffer>::getBufferIdentifier() const Line | Count | Source | 95 | 1.91M | StringRef getBufferIdentifier() const override { | 96 | 1.91M | // The name is stored after the class itself. | 97 | 1.91M | return StringRef(reinterpret_cast<const char *>(this + 1)); | 98 | 1.91M | } |
|
99 | | |
100 | 2 | MemoryBuffer::BufferKind getBufferKind() const override { |
101 | 2 | return MemoryBuffer::MemoryBuffer_Malloc; |
102 | 2 | } Unexecuted instantiation: MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::MemoryBuffer>::getBufferKind() const MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMem<llvm::WritableMemoryBuffer>::getBufferKind() const Line | Count | Source | 100 | 2 | MemoryBuffer::BufferKind getBufferKind() const override { | 101 | 2 | return MemoryBuffer::MemoryBuffer_Malloc; | 102 | 2 | } |
|
103 | | }; |
104 | | } |
105 | | |
106 | | template <typename MB> |
107 | | static ErrorOr<std::unique_ptr<MB>> |
108 | | getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, |
109 | | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile); |
110 | | |
111 | | std::unique_ptr<MemoryBuffer> |
112 | | MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, |
113 | 195k | bool RequiresNullTerminator) { |
114 | 195k | auto *Ret = new (NamedBufferAlloc(BufferName)) |
115 | 195k | MemoryBufferMem<MemoryBuffer>(InputData, RequiresNullTerminator); |
116 | 195k | return std::unique_ptr<MemoryBuffer>(Ret); |
117 | 195k | } |
118 | | |
119 | | std::unique_ptr<MemoryBuffer> |
120 | 43.9k | MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { |
121 | 43.9k | return std::unique_ptr<MemoryBuffer>(getMemBuffer( |
122 | 43.9k | Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator)); |
123 | 43.9k | } |
124 | | |
125 | | static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
126 | 312k | getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) { |
127 | 312k | auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(InputData.size(), BufferName); |
128 | 312k | if (!Buf) |
129 | 0 | return make_error_code(errc::not_enough_memory); |
130 | 312k | memcpy(Buf->getBufferStart(), InputData.data(), InputData.size()); |
131 | 312k | return std::move(Buf); |
132 | 312k | } |
133 | | |
134 | | std::unique_ptr<MemoryBuffer> |
135 | 271k | MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { |
136 | 271k | auto Buf = getMemBufferCopyImpl(InputData, BufferName); |
137 | 271k | if (Buf) |
138 | 271k | return std::move(*Buf); |
139 | 0 | return nullptr; |
140 | 0 | } |
141 | | |
142 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
143 | | MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize, |
144 | 66.8k | bool RequiresNullTerminator) { |
145 | 66.8k | SmallString<256> NameBuf; |
146 | 66.8k | StringRef NameRef = Filename.toStringRef(NameBuf); |
147 | 66.8k | |
148 | 66.8k | if (NameRef == "-") |
149 | 39.8k | return getSTDIN(); |
150 | 27.0k | return getFile(Filename, FileSize, RequiresNullTerminator); |
151 | 27.0k | } |
152 | | |
153 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
154 | | MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, |
155 | 10 | uint64_t Offset, bool IsVolatile) { |
156 | 10 | return getFileAux<MemoryBuffer>(FilePath, -1, MapSize, Offset, false, |
157 | 10 | IsVolatile); |
158 | 10 | } |
159 | | |
160 | | //===----------------------------------------------------------------------===// |
161 | | // MemoryBuffer::getFile implementation. |
162 | | //===----------------------------------------------------------------------===// |
163 | | |
164 | | namespace { |
165 | | /// Memory maps a file descriptor using sys::fs::mapped_file_region. |
166 | | /// |
167 | | /// This handles converting the offset into a legal offset on the platform. |
168 | | template<typename MB> |
169 | | class MemoryBufferMMapFile : public MB { |
170 | | sys::fs::mapped_file_region MFR; |
171 | | |
172 | 216k | static uint64_t getLegalMapOffset(uint64_t Offset) { |
173 | 216k | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); |
174 | 216k | } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::getLegalMapOffset(unsigned long long) Line | Count | Source | 172 | 3 | static uint64_t getLegalMapOffset(uint64_t Offset) { | 173 | 3 | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); | 174 | 3 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::getLegalMapOffset(unsigned long long) Line | Count | Source | 172 | 3 | static uint64_t getLegalMapOffset(uint64_t Offset) { | 173 | 3 | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); | 174 | 3 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::getLegalMapOffset(unsigned long long) Line | Count | Source | 172 | 216k | static uint64_t getLegalMapOffset(uint64_t Offset) { | 173 | 216k | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); | 174 | 216k | } |
|
175 | | |
176 | 72.0k | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { |
177 | 72.0k | return Len + (Offset - getLegalMapOffset(Offset)); |
178 | 72.0k | } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::getLegalMapSize(unsigned long long, unsigned long long) Line | Count | Source | 176 | 1 | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { | 177 | 1 | return Len + (Offset - getLegalMapOffset(Offset)); | 178 | 1 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::getLegalMapSize(unsigned long long, unsigned long long) Line | Count | Source | 176 | 1 | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { | 177 | 1 | return Len + (Offset - getLegalMapOffset(Offset)); | 178 | 1 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::getLegalMapSize(unsigned long long, unsigned long long) Line | Count | Source | 176 | 72.0k | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { | 177 | 72.0k | return Len + (Offset - getLegalMapOffset(Offset)); | 178 | 72.0k | } |
|
179 | | |
180 | 72.0k | const char *getStart(uint64_t Len, uint64_t Offset) { |
181 | 72.0k | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); |
182 | 72.0k | } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::getStart(unsigned long long, unsigned long long) Line | Count | Source | 180 | 1 | const char *getStart(uint64_t Len, uint64_t Offset) { | 181 | 1 | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); | 182 | 1 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::getStart(unsigned long long, unsigned long long) Line | Count | Source | 180 | 1 | const char *getStart(uint64_t Len, uint64_t Offset) { | 181 | 1 | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); | 182 | 1 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::getStart(unsigned long long, unsigned long long) Line | Count | Source | 180 | 72.0k | const char *getStart(uint64_t Len, uint64_t Offset) { | 181 | 72.0k | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); | 182 | 72.0k | } |
|
183 | | |
184 | | public: |
185 | | MemoryBufferMMapFile(bool RequiresNullTerminator, sys::fs::file_t FD, uint64_t Len, |
186 | | uint64_t Offset, std::error_code &EC) |
187 | | : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset), |
188 | 72.0k | getLegalMapOffset(Offset), EC) { |
189 | 72.0k | if (!EC) { |
190 | 72.0k | const char *Start = getStart(Len, Offset); |
191 | 72.0k | MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); |
192 | 72.0k | } |
193 | 72.0k | } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::MemoryBufferMMapFile(bool, int, unsigned long long, unsigned long long, std::__1::error_code&) Line | Count | Source | 188 | 1 | getLegalMapOffset(Offset), EC) { | 189 | 1 | if (!EC) { | 190 | 1 | const char *Start = getStart(Len, Offset); | 191 | 1 | MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); | 192 | 1 | } | 193 | 1 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::MemoryBufferMMapFile(bool, int, unsigned long long, unsigned long long, std::__1::error_code&) Line | Count | Source | 188 | 1 | getLegalMapOffset(Offset), EC) { | 189 | 1 | if (!EC) { | 190 | 1 | const char *Start = getStart(Len, Offset); | 191 | 1 | MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); | 192 | 1 | } | 193 | 1 | } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::MemoryBufferMMapFile(bool, int, unsigned long long, unsigned long long, std::__1::error_code&) Line | Count | Source | 188 | 72.0k | getLegalMapOffset(Offset), EC) { | 189 | 72.0k | if (!EC) { | 190 | 72.0k | const char *Start = getStart(Len, Offset); | 191 | 72.0k | MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); | 192 | 72.0k | } | 193 | 72.0k | } |
|
194 | | |
195 | | /// Disable sized deallocation for MemoryBufferMMapFile, because it has |
196 | | /// tail-allocated data. |
197 | 21.3k | void operator delete(void *p) { ::operator delete(p); } MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::operator delete(void*) Line | Count | Source | 197 | 1 | void operator delete(void *p) { ::operator delete(p); } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::operator delete(void*) Line | Count | Source | 197 | 1 | void operator delete(void *p) { ::operator delete(p); } |
MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::operator delete(void*) Line | Count | Source | 197 | 21.3k | void operator delete(void *p) { ::operator delete(p); } |
|
198 | | |
199 | 398k | StringRef getBufferIdentifier() const override { |
200 | 398k | // The name is stored after the class itself. |
201 | 398k | return StringRef(reinterpret_cast<const char *>(this + 1)); |
202 | 398k | } Unexecuted instantiation: MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::getBufferIdentifier() const Unexecuted instantiation: MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::getBufferIdentifier() const MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::getBufferIdentifier() const Line | Count | Source | 199 | 398k | StringRef getBufferIdentifier() const override { | 200 | 398k | // The name is stored after the class itself. | 201 | 398k | return StringRef(reinterpret_cast<const char *>(this + 1)); | 202 | 398k | } |
|
203 | | |
204 | 0 | MemoryBuffer::BufferKind getBufferKind() const override { |
205 | 0 | return MemoryBuffer::MemoryBuffer_MMap; |
206 | 0 | } Unexecuted instantiation: MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WriteThroughMemoryBuffer>::getBufferKind() const Unexecuted instantiation: MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::WritableMemoryBuffer>::getBufferKind() const Unexecuted instantiation: MemoryBuffer.cpp:(anonymous namespace)::MemoryBufferMMapFile<llvm::MemoryBuffer>::getBufferKind() const |
207 | | }; |
208 | | } |
209 | | |
210 | | static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
211 | 40.4k | getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) { |
212 | 40.4k | const ssize_t ChunkSize = 4096*4; |
213 | 40.4k | SmallString<ChunkSize> Buffer; |
214 | 40.4k | size_t ReadBytes; |
215 | 40.4k | // Read into Buffer until we hit EOF. |
216 | 111k | do { |
217 | 111k | Buffer.reserve(Buffer.size() + ChunkSize); |
218 | 111k | if (auto EC = sys::fs::readNativeFile( |
219 | 0 | FD, makeMutableArrayRef(Buffer.end(), ChunkSize), &ReadBytes)) |
220 | 0 | return EC; |
221 | 111k | Buffer.set_size(Buffer.size() + ReadBytes); |
222 | 111k | } while (ReadBytes != 0); |
223 | 40.4k | |
224 | 40.4k | return getMemBufferCopyImpl(Buffer, BufferName); |
225 | 40.4k | } |
226 | | |
227 | | |
228 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
229 | | MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, |
230 | 64.6k | bool RequiresNullTerminator, bool IsVolatile) { |
231 | 64.6k | return getFileAux<MemoryBuffer>(Filename, FileSize, FileSize, 0, |
232 | 64.6k | RequiresNullTerminator, IsVolatile); |
233 | 64.6k | } |
234 | | |
235 | | template <typename MB> |
236 | | static ErrorOr<std::unique_ptr<MB>> |
237 | | getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, |
238 | | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
239 | | bool IsVolatile); |
240 | | |
241 | | template <typename MB> |
242 | | static ErrorOr<std::unique_ptr<MB>> |
243 | | getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, |
244 | 64.6k | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { |
245 | 64.6k | Expected<sys::fs::file_t> FDOrErr = |
246 | 64.6k | sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); |
247 | 64.6k | if (!FDOrErr) |
248 | 18.6k | return errorToErrorCode(FDOrErr.takeError()); |
249 | 46.0k | sys::fs::file_t FD = *FDOrErr; |
250 | 46.0k | auto Ret = getOpenFileImpl<MB>(FD, Filename, FileSize, MapSize, Offset, |
251 | 46.0k | RequiresNullTerminator, IsVolatile); |
252 | 46.0k | sys::fs::closeFile(FD); |
253 | 46.0k | return Ret; |
254 | 46.0k | } MemoryBuffer.cpp:llvm::ErrorOr<std::__1::unique_ptr<llvm::MemoryBuffer, std::__1::default_delete<llvm::MemoryBuffer> > > getFileAux<llvm::MemoryBuffer>(llvm::Twine const&, long long, unsigned long long, unsigned long long, bool, bool) Line | Count | Source | 244 | 64.6k | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { | 245 | 64.6k | Expected<sys::fs::file_t> FDOrErr = | 246 | 64.6k | sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); | 247 | 64.6k | if (!FDOrErr) | 248 | 18.6k | return errorToErrorCode(FDOrErr.takeError()); | 249 | 46.0k | sys::fs::file_t FD = *FDOrErr; | 250 | 46.0k | auto Ret = getOpenFileImpl<MB>(FD, Filename, FileSize, MapSize, Offset, | 251 | 46.0k | RequiresNullTerminator, IsVolatile); | 252 | 46.0k | sys::fs::closeFile(FD); | 253 | 46.0k | return Ret; | 254 | 46.0k | } |
MemoryBuffer.cpp:llvm::ErrorOr<std::__1::unique_ptr<llvm::WritableMemoryBuffer, std::__1::default_delete<llvm::WritableMemoryBuffer> > > getFileAux<llvm::WritableMemoryBuffer>(llvm::Twine const&, long long, unsigned long long, unsigned long long, bool, bool) Line | Count | Source | 244 | 1 | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { | 245 | 1 | Expected<sys::fs::file_t> FDOrErr = | 246 | 1 | sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); | 247 | 1 | if (!FDOrErr) | 248 | 0 | return errorToErrorCode(FDOrErr.takeError()); | 249 | 1 | sys::fs::file_t FD = *FDOrErr; | 250 | 1 | auto Ret = getOpenFileImpl<MB>(FD, Filename, FileSize, MapSize, Offset, | 251 | 1 | RequiresNullTerminator, IsVolatile); | 252 | 1 | sys::fs::closeFile(FD); | 253 | 1 | return Ret; | 254 | 1 | } |
|
255 | | |
256 | | ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
257 | | WritableMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, |
258 | 0 | bool IsVolatile) { |
259 | 0 | return getFileAux<WritableMemoryBuffer>(Filename, FileSize, FileSize, 0, |
260 | 0 | /*RequiresNullTerminator*/ false, |
261 | 0 | IsVolatile); |
262 | 0 | } |
263 | | |
264 | | ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
265 | | WritableMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, |
266 | 1 | uint64_t Offset, bool IsVolatile) { |
267 | 1 | return getFileAux<WritableMemoryBuffer>(Filename, -1, MapSize, Offset, false, |
268 | 1 | IsVolatile); |
269 | 1 | } |
270 | | |
271 | | std::unique_ptr<WritableMemoryBuffer> |
272 | 817k | WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) { |
273 | 817k | using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>; |
274 | 817k | // Allocate space for the MemoryBuffer, the data and the name. It is important |
275 | 817k | // that MemoryBuffer and data are aligned so PointerIntPair works with them. |
276 | 817k | // TODO: Is 16-byte alignment enough? We copy small object files with large |
277 | 817k | // alignment expectations into this buffer. |
278 | 817k | SmallString<256> NameBuf; |
279 | 817k | StringRef NameRef = BufferName.toStringRef(NameBuf); |
280 | 817k | size_t AlignedStringLen = alignTo(sizeof(MemBuffer) + NameRef.size() + 1, 16); |
281 | 817k | size_t RealLen = AlignedStringLen + Size + 1; |
282 | 817k | char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); |
283 | 817k | if (!Mem) |
284 | 0 | return nullptr; |
285 | 817k | |
286 | 817k | // The name is stored after the class itself. |
287 | 817k | CopyStringRef(Mem + sizeof(MemBuffer), NameRef); |
288 | 817k | |
289 | 817k | // The buffer begins after the name and must be aligned. |
290 | 817k | char *Buf = Mem + AlignedStringLen; |
291 | 817k | Buf[Size] = 0; // Null terminate buffer. |
292 | 817k | |
293 | 817k | auto *Ret = new (Mem) MemBuffer(StringRef(Buf, Size), true); |
294 | 817k | return std::unique_ptr<WritableMemoryBuffer>(Ret); |
295 | 817k | } |
296 | | |
297 | | std::unique_ptr<WritableMemoryBuffer> |
298 | 20.5k | WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) { |
299 | 20.5k | auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName); |
300 | 20.5k | if (!SB) |
301 | 0 | return nullptr; |
302 | 20.5k | memset(SB->getBufferStart(), 0, Size); |
303 | 20.5k | return SB; |
304 | 20.5k | } |
305 | | |
306 | | static bool shouldUseMmap(sys::fs::file_t FD, |
307 | | size_t FileSize, |
308 | | size_t MapSize, |
309 | | off_t Offset, |
310 | | bool RequiresNullTerminator, |
311 | | int PageSize, |
312 | 555k | bool IsVolatile) { |
313 | 555k | // mmap may leave the buffer without null terminator if the file size changed |
314 | 555k | // by the time the last page is mapped in, so avoid it if the file size is |
315 | 555k | // likely to change. |
316 | 555k | if (IsVolatile) |
317 | 3.81k | return false; |
318 | 551k | |
319 | 551k | // We don't use mmap for small files because this can severely fragment our |
320 | 551k | // address space. |
321 | 551k | if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize72.0k ) |
322 | 479k | return false; |
323 | 72.0k | |
324 | 72.0k | if (!RequiresNullTerminator) |
325 | 1.22k | return true; |
326 | 70.8k | |
327 | 70.8k | // If we don't know the file size, use fstat to find out. fstat on an open |
328 | 70.8k | // file descriptor is cheaper than stat on a random path. |
329 | 70.8k | // FIXME: this chunk of code is duplicated, but it avoids a fstat when |
330 | 70.8k | // RequiresNullTerminator = false and MapSize != -1. |
331 | 70.8k | if (FileSize == size_t(-1)) { |
332 | 0 | sys::fs::file_status Status; |
333 | 0 | if (sys::fs::status(FD, Status)) |
334 | 0 | return false; |
335 | 0 | FileSize = Status.getSize(); |
336 | 0 | } |
337 | 70.8k | |
338 | 70.8k | // If we need a null terminator and the end of the map is inside the file, |
339 | 70.8k | // we cannot use mmap. |
340 | 70.8k | size_t End = Offset + MapSize; |
341 | 70.8k | assert(End <= FileSize); |
342 | 70.8k | if (End != FileSize) |
343 | 0 | return false; |
344 | 70.8k | |
345 | 70.8k | // Don't try to map files that are exactly a multiple of the system page size |
346 | 70.8k | // if we need a null terminator. |
347 | 70.8k | if ((FileSize & (PageSize -1)) == 0) |
348 | 11 | return false; |
349 | 70.8k | |
350 | | #if defined(__CYGWIN__) |
351 | | // Don't try to map files that are exactly a multiple of the physical page size |
352 | | // if we need a null terminator. |
353 | | // FIXME: We should reorganize again getPageSize() on Win32. |
354 | | if ((FileSize & (4096 - 1)) == 0) |
355 | | return false; |
356 | | #endif |
357 | | |
358 | 70.8k | return true; |
359 | 70.8k | } |
360 | | |
361 | | static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
362 | | getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize, |
363 | 1 | uint64_t Offset) { |
364 | 1 | Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForReadWrite( |
365 | 1 | Filename, sys::fs::CD_OpenExisting, sys::fs::OF_None); |
366 | 1 | if (!FDOrErr) |
367 | 0 | return errorToErrorCode(FDOrErr.takeError()); |
368 | 1 | sys::fs::file_t FD = *FDOrErr; |
369 | 1 | |
370 | 1 | // Default is to map the full file. |
371 | 1 | if (MapSize == uint64_t(-1)) { |
372 | 1 | // If we don't know the file size, use fstat to find out. fstat on an open |
373 | 1 | // file descriptor is cheaper than stat on a random path. |
374 | 1 | if (FileSize == uint64_t(-1)) { |
375 | 1 | sys::fs::file_status Status; |
376 | 1 | std::error_code EC = sys::fs::status(FD, Status); |
377 | 1 | if (EC) |
378 | 0 | return EC; |
379 | 1 | |
380 | 1 | // If this not a file or a block device (e.g. it's a named pipe |
381 | 1 | // or character device), we can't mmap it, so error out. |
382 | 1 | sys::fs::file_type Type = Status.type(); |
383 | 1 | if (Type != sys::fs::file_type::regular_file && |
384 | 1 | Type != sys::fs::file_type::block_file0 ) |
385 | 0 | return make_error_code(errc::invalid_argument); |
386 | 1 | |
387 | 1 | FileSize = Status.getSize(); |
388 | 1 | } |
389 | 1 | MapSize = FileSize; |
390 | 1 | } |
391 | 1 | |
392 | 1 | std::error_code EC; |
393 | 1 | std::unique_ptr<WriteThroughMemoryBuffer> Result( |
394 | 1 | new (NamedBufferAlloc(Filename)) |
395 | 1 | MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize, |
396 | 1 | Offset, EC)); |
397 | 1 | if (EC) |
398 | 0 | return EC; |
399 | 1 | return std::move(Result); |
400 | 1 | } |
401 | | |
402 | | ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
403 | 1 | WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) { |
404 | 1 | return getReadWriteFile(Filename, FileSize, FileSize, 0); |
405 | 1 | } |
406 | | |
407 | | /// Map a subrange of the specified file as a WritableMemoryBuffer. |
408 | | ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
409 | | WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, |
410 | 0 | uint64_t Offset) { |
411 | 0 | return getReadWriteFile(Filename, -1, MapSize, Offset); |
412 | 0 | } |
413 | | |
414 | | template <typename MB> |
415 | | static ErrorOr<std::unique_ptr<MB>> |
416 | | getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, |
417 | | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
418 | 555k | bool IsVolatile) { |
419 | 555k | static int PageSize = sys::Process::getPageSizeEstimate(); |
420 | 555k | |
421 | 555k | // Default is to map the full file. |
422 | 555k | if (MapSize == uint64_t(-1)) { |
423 | 57.2k | // If we don't know the file size, use fstat to find out. fstat on an open |
424 | 57.2k | // file descriptor is cheaper than stat on a random path. |
425 | 57.2k | if (FileSize == uint64_t(-1)) { |
426 | 57.2k | sys::fs::file_status Status; |
427 | 57.2k | std::error_code EC = sys::fs::status(FD, Status); |
428 | 57.2k | if (EC) |
429 | 0 | return EC; |
430 | 57.2k | |
431 | 57.2k | // If this not a file or a block device (e.g. it's a named pipe |
432 | 57.2k | // or character device), we can't trust the size. Create the memory |
433 | 57.2k | // buffer by copying off the stream. |
434 | 57.2k | sys::fs::file_type Type = Status.type(); |
435 | 57.2k | if (Type != sys::fs::file_type::regular_file && |
436 | 57.2k | Type != sys::fs::file_type::block_file74 ) |
437 | 74 | return getMemoryBufferForStream(FD, Filename); |
438 | 57.1k | |
439 | 57.1k | FileSize = Status.getSize(); |
440 | 57.1k | } |
441 | 57.2k | MapSize = FileSize; |
442 | 57.1k | } |
443 | 555k | |
444 | 555k | if (555k shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, |
445 | 555k | PageSize, IsVolatile)) { |
446 | 72.0k | std::error_code EC; |
447 | 72.0k | std::unique_ptr<MB> Result( |
448 | 72.0k | new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>( |
449 | 72.0k | RequiresNullTerminator, FD, MapSize, Offset, EC)); |
450 | 72.0k | if (!EC) |
451 | 72.0k | return std::move(Result); |
452 | 483k | } |
453 | 483k | |
454 | 483k | auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); |
455 | 483k | if (!Buf) { |
456 | 0 | // Failed to create a buffer. The only way it can fail is if |
457 | 0 | // new(std::nothrow) returns 0. |
458 | 0 | return make_error_code(errc::not_enough_memory); |
459 | 0 | } |
460 | 483k | |
461 | 483k | sys::fs::readNativeFileSlice(FD, Buf->getBuffer(), Offset); |
462 | 483k | |
463 | 483k | return std::move(Buf); |
464 | 483k | } MemoryBuffer.cpp:llvm::ErrorOr<std::__1::unique_ptr<llvm::WritableMemoryBuffer, std::__1::default_delete<llvm::WritableMemoryBuffer> > > getOpenFileImpl<llvm::WritableMemoryBuffer>(int, llvm::Twine const&, unsigned long long, unsigned long long, long long, bool, bool) Line | Count | Source | 418 | 1 | bool IsVolatile) { | 419 | 1 | static int PageSize = sys::Process::getPageSizeEstimate(); | 420 | 1 | | 421 | 1 | // Default is to map the full file. | 422 | 1 | if (MapSize == uint64_t(-1)) { | 423 | 0 | // If we don't know the file size, use fstat to find out. fstat on an open | 424 | 0 | // file descriptor is cheaper than stat on a random path. | 425 | 0 | if (FileSize == uint64_t(-1)) { | 426 | 0 | sys::fs::file_status Status; | 427 | 0 | std::error_code EC = sys::fs::status(FD, Status); | 428 | 0 | if (EC) | 429 | 0 | return EC; | 430 | 0 | | 431 | 0 | // If this not a file or a block device (e.g. it's a named pipe | 432 | 0 | // or character device), we can't trust the size. Create the memory | 433 | 0 | // buffer by copying off the stream. | 434 | 0 | sys::fs::file_type Type = Status.type(); | 435 | 0 | if (Type != sys::fs::file_type::regular_file && | 436 | 0 | Type != sys::fs::file_type::block_file) | 437 | 0 | return getMemoryBufferForStream(FD, Filename); | 438 | 0 | | 439 | 0 | FileSize = Status.getSize(); | 440 | 0 | } | 441 | 0 | MapSize = FileSize; | 442 | 0 | } | 443 | 1 | | 444 | 1 | if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, | 445 | 1 | PageSize, IsVolatile)) { | 446 | 1 | std::error_code EC; | 447 | 1 | std::unique_ptr<MB> Result( | 448 | 1 | new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>( | 449 | 1 | RequiresNullTerminator, FD, MapSize, Offset, EC)); | 450 | 1 | if (!EC) | 451 | 1 | return std::move(Result); | 452 | 0 | } | 453 | 0 | | 454 | 0 | auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); | 455 | 0 | if (!Buf) { | 456 | 0 | // Failed to create a buffer. The only way it can fail is if | 457 | 0 | // new(std::nothrow) returns 0. | 458 | 0 | return make_error_code(errc::not_enough_memory); | 459 | 0 | } | 460 | 0 | | 461 | 0 | sys::fs::readNativeFileSlice(FD, Buf->getBuffer(), Offset); | 462 | 0 |
| 463 | 0 | return std::move(Buf); | 464 | 0 | } |
MemoryBuffer.cpp:llvm::ErrorOr<std::__1::unique_ptr<llvm::MemoryBuffer, std::__1::default_delete<llvm::MemoryBuffer> > > getOpenFileImpl<llvm::MemoryBuffer>(int, llvm::Twine const&, unsigned long long, unsigned long long, long long, bool, bool) Line | Count | Source | 418 | 555k | bool IsVolatile) { | 419 | 555k | static int PageSize = sys::Process::getPageSizeEstimate(); | 420 | 555k | | 421 | 555k | // Default is to map the full file. | 422 | 555k | if (MapSize == uint64_t(-1)) { | 423 | 57.2k | // If we don't know the file size, use fstat to find out. fstat on an open | 424 | 57.2k | // file descriptor is cheaper than stat on a random path. | 425 | 57.2k | if (FileSize == uint64_t(-1)) { | 426 | 57.2k | sys::fs::file_status Status; | 427 | 57.2k | std::error_code EC = sys::fs::status(FD, Status); | 428 | 57.2k | if (EC) | 429 | 0 | return EC; | 430 | 57.2k | | 431 | 57.2k | // If this not a file or a block device (e.g. it's a named pipe | 432 | 57.2k | // or character device), we can't trust the size. Create the memory | 433 | 57.2k | // buffer by copying off the stream. | 434 | 57.2k | sys::fs::file_type Type = Status.type(); | 435 | 57.2k | if (Type != sys::fs::file_type::regular_file && | 436 | 57.2k | Type != sys::fs::file_type::block_file74 ) | 437 | 74 | return getMemoryBufferForStream(FD, Filename); | 438 | 57.1k | | 439 | 57.1k | FileSize = Status.getSize(); | 440 | 57.1k | } | 441 | 57.2k | MapSize = FileSize; | 442 | 57.1k | } | 443 | 555k | | 444 | 555k | if (555k shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, | 445 | 555k | PageSize, IsVolatile)) { | 446 | 72.0k | std::error_code EC; | 447 | 72.0k | std::unique_ptr<MB> Result( | 448 | 72.0k | new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>( | 449 | 72.0k | RequiresNullTerminator, FD, MapSize, Offset, EC)); | 450 | 72.0k | if (!EC) | 451 | 72.0k | return std::move(Result); | 452 | 483k | } | 453 | 483k | | 454 | 483k | auto Buf = WritableMemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); | 455 | 483k | if (!Buf) { | 456 | 0 | // Failed to create a buffer. The only way it can fail is if | 457 | 0 | // new(std::nothrow) returns 0. | 458 | 0 | return make_error_code(errc::not_enough_memory); | 459 | 0 | } | 460 | 483k | | 461 | 483k | sys::fs::readNativeFileSlice(FD, Buf->getBuffer(), Offset); | 462 | 483k | | 463 | 483k | return std::move(Buf); | 464 | 483k | } |
|
465 | | |
466 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
467 | | MemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, |
468 | 509k | bool RequiresNullTerminator, bool IsVolatile) { |
469 | 509k | return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, FileSize, 0, |
470 | 509k | RequiresNullTerminator, IsVolatile); |
471 | 509k | } |
472 | | |
473 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
474 | | MemoryBuffer::getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, |
475 | 2 | int64_t Offset, bool IsVolatile) { |
476 | 2 | assert(MapSize != uint64_t(-1)); |
477 | 2 | return getOpenFileImpl<MemoryBuffer>(FD, Filename, -1, MapSize, Offset, false, |
478 | 2 | IsVolatile); |
479 | 2 | } |
480 | | |
481 | 40.3k | ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { |
482 | 40.3k | // Read in all of the data from stdin, we cannot mmap stdin. |
483 | 40.3k | // |
484 | 40.3k | // FIXME: That isn't necessarily true, we should try to mmap stdin and |
485 | 40.3k | // fallback if it fails. |
486 | 40.3k | sys::ChangeStdinToBinary(); |
487 | 40.3k | |
488 | 40.3k | return getMemoryBufferForStream(sys::fs::getStdinHandle(), "<stdin>"); |
489 | 40.3k | } |
490 | | |
491 | | ErrorOr<std::unique_ptr<MemoryBuffer>> |
492 | 3 | MemoryBuffer::getFileAsStream(const Twine &Filename) { |
493 | 3 | Expected<sys::fs::file_t> FDOrErr = |
494 | 3 | sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); |
495 | 3 | if (!FDOrErr) |
496 | 0 | return errorToErrorCode(FDOrErr.takeError()); |
497 | 3 | sys::fs::file_t FD = *FDOrErr; |
498 | 3 | ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = |
499 | 3 | getMemoryBufferForStream(FD, Filename); |
500 | 3 | sys::fs::closeFile(FD); |
501 | 3 | return Ret; |
502 | 3 | } |
503 | | |
504 | 62.7k | MemoryBufferRef MemoryBuffer::getMemBufferRef() const { |
505 | 62.7k | StringRef Data = getBuffer(); |
506 | 62.7k | StringRef Identifier = getBufferIdentifier(); |
507 | 62.7k | return MemoryBufferRef(Data, Identifier); |
508 | 62.7k | } |
509 | | |
510 | 288 | SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() {} |