Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 1 | //===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 10 | #include "llvm/DebugInfo/Msf/MappedBlockStream.h" |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 11 | |
| 12 | #include "llvm/DebugInfo/Msf/IMsfFile.h" |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 13 | #include "llvm/DebugInfo/Msf/MsfError.h" |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 14 | #include "llvm/DebugInfo/Msf/MsfStreamLayout.h" |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 15 | |
| 16 | using namespace llvm; |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 17 | using namespace llvm::msf; |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 18 | |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 19 | namespace { |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 20 | // This exists so that we can use make_unique (which requires a public default |
| 21 | // constructor, while still keeping the constructor of MappedBlockStream |
| 22 | // protected, forcing users to go through the `create` interface. |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 23 | class MappedBlockStreamImpl : public MappedBlockStream { |
| 24 | public: |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 25 | MappedBlockStreamImpl(const MsfStreamLayout &Layout, const IMsfFile &File) |
| 26 | : MappedBlockStream(Layout, File) {} |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 27 | }; |
| 28 | } |
| 29 | |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 30 | typedef std::pair<uint32_t, uint32_t> Interval; |
| 31 | static Interval intersect(const Interval &I1, const Interval &I2) { |
| 32 | return std::make_pair(std::max(I1.first, I2.first), |
| 33 | std::min(I1.second, I2.second)); |
| 34 | } |
| 35 | |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 36 | MappedBlockStream::MappedBlockStream(const MsfStreamLayout &Layout, |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 37 | const IMsfFile &File) |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 38 | : Msf(File), Layout(Layout) {} |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 39 | |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 40 | Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, |
| 41 | ArrayRef<uint8_t> &Buffer) const { |
| 42 | // Make sure we aren't trying to read beyond the end of the stream. |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 43 | if (Size > Layout.Length) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 44 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 45 | if (Offset > Layout.Length - Size) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 46 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 47 | |
| 48 | if (tryReadContiguously(Offset, Size, Buffer)) |
| 49 | return Error::success(); |
| 50 | |
| 51 | auto CacheIter = CacheMap.find(Offset); |
| 52 | if (CacheIter != CacheMap.end()) { |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 53 | // Try to find an alloc that was large enough for this request. |
| 54 | for (auto &Entry : CacheIter->second) { |
| 55 | if (Entry.size() >= Size) { |
| 56 | Buffer = Entry.slice(0, Size); |
| 57 | return Error::success(); |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | // We couldn't find a buffer that started at the correct offset (the most |
| 63 | // common scenario). Try to see if there is a buffer that starts at some |
| 64 | // other offset but overlaps the desired range. |
| 65 | for (auto &CacheItem : CacheMap) { |
| 66 | Interval RequestExtent = std::make_pair(Offset, Offset + Size); |
| 67 | |
| 68 | // We already checked this one on the fast path above. |
| 69 | if (CacheItem.first == Offset) |
| 70 | continue; |
| 71 | // If the initial extent of the cached item is beyond the ending extent |
| 72 | // of the request, there is no overlap. |
| 73 | if (CacheItem.first >= Offset + Size) |
| 74 | continue; |
| 75 | |
| 76 | // We really only have to check the last item in the list, since we append |
| 77 | // in order of increasing length. |
| 78 | if (CacheItem.second.empty()) |
| 79 | continue; |
| 80 | |
| 81 | auto CachedAlloc = CacheItem.second.back(); |
| 82 | // If the initial extent of the request is beyond the ending extent of |
| 83 | // the cached item, there is no overlap. |
| 84 | Interval CachedExtent = |
| 85 | std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); |
| 86 | if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) |
| 87 | continue; |
| 88 | |
| 89 | Interval Intersection = intersect(CachedExtent, RequestExtent); |
| 90 | // Only use this if the entire request extent is contained in the cached |
| 91 | // extent. |
| 92 | if (Intersection != RequestExtent) |
| 93 | continue; |
| 94 | |
| 95 | uint32_t CacheRangeOffset = |
| 96 | AbsoluteDifference(CachedExtent.first, Intersection.first); |
| 97 | Buffer = CachedAlloc.slice(CacheRangeOffset, Size); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 98 | return Error::success(); |
| 99 | } |
| 100 | |
| 101 | // Otherwise allocate a large enough buffer in the pool, memcpy the data |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 102 | // into it, and return an ArrayRef to that. Do not touch existing pool |
| 103 | // allocations, as existing clients may be holding a pointer which must |
| 104 | // not be invalidated. |
Zachary Turner | 97609bb | 2016-06-10 21:47:26 +0000 | [diff] [blame] | 105 | uint8_t *WriteBuffer = static_cast<uint8_t *>(Pool.Allocate(Size, 8)); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 106 | if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size))) |
| 107 | return EC; |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 108 | |
| 109 | if (CacheIter != CacheMap.end()) { |
| 110 | CacheIter->second.emplace_back(WriteBuffer, Size); |
| 111 | } else { |
| 112 | std::vector<CacheEntry> List; |
| 113 | List.emplace_back(WriteBuffer, Size); |
| 114 | CacheMap.insert(std::make_pair(Offset, List)); |
| 115 | } |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 116 | Buffer = ArrayRef<uint8_t>(WriteBuffer, Size); |
| 117 | return Error::success(); |
| 118 | } |
| 119 | |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 120 | Error MappedBlockStream::readLongestContiguousChunk( |
| 121 | uint32_t Offset, ArrayRef<uint8_t> &Buffer) const { |
| 122 | // Make sure we aren't trying to read beyond the end of the stream. |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 123 | if (Offset >= Layout.Length) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 124 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
| 125 | uint32_t First = Offset / Msf.getBlockSize(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 126 | uint32_t Last = First; |
| 127 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 128 | while (Last < Msf.getBlockCount() - 1) { |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 129 | if (Layout.Blocks[Last] != Layout.Blocks[Last + 1] - 1) |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 130 | break; |
| 131 | ++Last; |
| 132 | } |
| 133 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 134 | uint32_t OffsetInFirstBlock = Offset % Msf.getBlockSize(); |
| 135 | uint32_t BytesFromFirstBlock = Msf.getBlockSize() - OffsetInFirstBlock; |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 136 | uint32_t BlockSpan = Last - First + 1; |
| 137 | uint32_t ByteSpan = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 138 | BytesFromFirstBlock + (BlockSpan - 1) * Msf.getBlockSize(); |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 139 | auto Result = Msf.getBlockData(Layout.Blocks[First], Msf.getBlockSize()); |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 140 | if (!Result) |
| 141 | return Result.takeError(); |
| 142 | Buffer = Result->drop_front(OffsetInFirstBlock); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 143 | Buffer = ArrayRef<uint8_t>(Buffer.data(), ByteSpan); |
| 144 | return Error::success(); |
| 145 | } |
| 146 | |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 147 | uint32_t MappedBlockStream::getLength() const { return Layout.Length; } |
Zachary Turner | d844799 | 2016-06-07 05:28:55 +0000 | [diff] [blame] | 148 | |
Zachary Turner | ab58ae8 | 2016-06-30 17:43:00 +0000 | [diff] [blame] | 149 | Error MappedBlockStream::commit() const { return Error::success(); } |
| 150 | |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 151 | bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, |
| 152 | ArrayRef<uint8_t> &Buffer) const { |
| 153 | // Attempt to fulfill the request with a reference directly into the stream. |
| 154 | // This can work even if the request crosses a block boundary, provided that |
| 155 | // all subsequent blocks are contiguous. For example, a 10k read with a 4k |
| 156 | // block size can be filled with a reference if, from the starting offset, |
| 157 | // 3 blocks in a row are contiguous. |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 158 | uint32_t BlockNum = Offset / Msf.getBlockSize(); |
| 159 | uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 160 | uint32_t BytesFromFirstBlock = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 161 | std::min(Size, Msf.getBlockSize() - OffsetInBlock); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 162 | uint32_t NumAdditionalBlocks = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 163 | llvm::alignTo(Size - BytesFromFirstBlock, Msf.getBlockSize()) / |
| 164 | Msf.getBlockSize(); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 165 | |
| 166 | uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 167 | uint32_t E = Layout.Blocks[BlockNum]; |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 168 | for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 169 | if (Layout.Blocks[I + BlockNum] != E) |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 170 | return false; |
| 171 | } |
| 172 | |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 173 | uint32_t FirstBlockAddr = Layout.Blocks[BlockNum]; |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 174 | auto Result = Msf.getBlockData(FirstBlockAddr, Msf.getBlockSize()); |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 175 | if (!Result) { |
| 176 | consumeError(Result.takeError()); |
| 177 | return false; |
| 178 | } |
| 179 | auto Data = Result->drop_front(OffsetInBlock); |
Zachary Turner | e6fee88 | 2016-06-07 20:38:37 +0000 | [diff] [blame] | 180 | Buffer = ArrayRef<uint8_t>(Data.data(), Size); |
Zachary Turner | 8dbe362 | 2016-05-27 01:54:44 +0000 | [diff] [blame] | 181 | return true; |
| 182 | } |
| 183 | |
Zachary Turner | 819e77d | 2016-05-06 20:51:57 +0000 | [diff] [blame] | 184 | Error MappedBlockStream::readBytes(uint32_t Offset, |
| 185 | MutableArrayRef<uint8_t> Buffer) const { |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 186 | uint32_t BlockNum = Offset / Msf.getBlockSize(); |
| 187 | uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 188 | |
| 189 | // Make sure we aren't trying to read beyond the end of the stream. |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 190 | if (Buffer.size() > Layout.Length) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 191 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 192 | if (Offset > Layout.Length - Buffer.size()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 193 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 194 | |
| 195 | uint32_t BytesLeft = Buffer.size(); |
| 196 | uint32_t BytesWritten = 0; |
| 197 | uint8_t *WriteBuffer = Buffer.data(); |
| 198 | while (BytesLeft > 0) { |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 199 | uint32_t StreamBlockAddr = Layout.Blocks[BlockNum]; |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 200 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 201 | auto Result = Msf.getBlockData(StreamBlockAddr, Msf.getBlockSize()); |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 202 | if (!Result) |
| 203 | return Result.takeError(); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 204 | |
David Majnemer | 6211b1f | 2016-07-10 03:34:47 +0000 | [diff] [blame] | 205 | auto Data = *Result; |
Zachary Turner | e6fee88 | 2016-06-07 20:38:37 +0000 | [diff] [blame] | 206 | const uint8_t *ChunkStart = Data.data() + OffsetInBlock; |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 207 | uint32_t BytesInChunk = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 208 | std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock); |
Zachary Turner | 6ba65de | 2016-04-29 17:22:58 +0000 | [diff] [blame] | 209 | ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); |
| 210 | |
| 211 | BytesWritten += BytesInChunk; |
| 212 | BytesLeft -= BytesInChunk; |
| 213 | ++BlockNum; |
| 214 | OffsetInBlock = 0; |
| 215 | } |
| 216 | |
Zachary Turner | 819e77d | 2016-05-06 20:51:57 +0000 | [diff] [blame] | 217 | return Error::success(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 218 | } |
Zachary Turner | f5c5965 | 2016-05-03 00:28:21 +0000 | [diff] [blame] | 219 | |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 220 | Error MappedBlockStream::writeBytes(uint32_t Offset, |
| 221 | ArrayRef<uint8_t> Buffer) const { |
| 222 | // Make sure we aren't trying to write beyond the end of the stream. |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 223 | if (Buffer.size() > Layout.Length) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 224 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 225 | |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 226 | if (Offset > Layout.Length - Buffer.size()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 227 | return make_error<MsfError>(msf_error_code::insufficient_buffer); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 228 | |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 229 | uint32_t BlockNum = Offset / Msf.getBlockSize(); |
| 230 | uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 231 | |
| 232 | uint32_t BytesLeft = Buffer.size(); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 233 | uint32_t BytesWritten = 0; |
| 234 | while (BytesLeft > 0) { |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 235 | uint32_t StreamBlockAddr = Layout.Blocks[BlockNum]; |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 236 | uint32_t BytesToWriteInChunk = |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 237 | std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock); |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 238 | |
| 239 | const uint8_t *Chunk = Buffer.data() + BytesWritten; |
| 240 | ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk); |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 241 | if (auto EC = Msf.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData)) |
Zachary Turner | 5acb4ac | 2016-06-10 05:09:12 +0000 | [diff] [blame] | 242 | return EC; |
| 243 | |
| 244 | BytesLeft -= BytesToWriteInChunk; |
| 245 | BytesWritten += BytesToWriteInChunk; |
| 246 | ++BlockNum; |
| 247 | OffsetInBlock = 0; |
| 248 | } |
| 249 | |
| 250 | // If this write overlapped a read which previously came from the pool, |
| 251 | // someone may still be holding a pointer to that alloc which is now invalid. |
| 252 | // Compute the overlapping range and update the cache entry, so any |
| 253 | // outstanding buffers are automatically updated. |
| 254 | for (const auto &MapEntry : CacheMap) { |
| 255 | // If the end of the written extent precedes the beginning of the cached |
| 256 | // extent, ignore this map entry. |
| 257 | if (Offset + BytesWritten < MapEntry.first) |
| 258 | continue; |
| 259 | for (const auto &Alloc : MapEntry.second) { |
| 260 | // If the end of the cached extent precedes the beginning of the written |
| 261 | // extent, ignore this alloc. |
| 262 | if (MapEntry.first + Alloc.size() < Offset) |
| 263 | continue; |
| 264 | |
| 265 | // If we get here, they are guaranteed to overlap. |
| 266 | Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten); |
| 267 | Interval CachedInterval = |
| 268 | std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); |
| 269 | // If they overlap, we need to write the new data into the overlapping |
| 270 | // range. |
| 271 | auto Intersection = intersect(WriteInterval, CachedInterval); |
| 272 | assert(Intersection.first <= Intersection.second); |
| 273 | |
| 274 | uint32_t Length = Intersection.second - Intersection.first; |
| 275 | uint32_t SrcOffset = |
| 276 | AbsoluteDifference(WriteInterval.first, Intersection.first); |
| 277 | uint32_t DestOffset = |
| 278 | AbsoluteDifference(CachedInterval.first, Intersection.first); |
| 279 | ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | return Error::success(); |
Zachary Turner | f5c5965 | 2016-05-03 00:28:21 +0000 | [diff] [blame] | 284 | } |
Zachary Turner | 90b8b8d | 2016-05-31 22:41:52 +0000 | [diff] [blame] | 285 | |
| 286 | uint32_t MappedBlockStream::getNumBytesCopied() const { |
| 287 | return static_cast<uint32_t>(Pool.getBytesAllocated()); |
| 288 | } |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 289 | |
| 290 | Expected<std::unique_ptr<MappedBlockStream>> |
| 291 | MappedBlockStream::createIndexedStream(uint32_t StreamIdx, |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 292 | const IMsfFile &File) { |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 293 | if (StreamIdx >= File.getNumStreams()) |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 294 | return make_error<MsfError>(msf_error_code::no_stream); |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 295 | MsfStreamLayout L; |
| 296 | L.Blocks = File.getStreamBlockList(StreamIdx); |
| 297 | L.Length = File.getStreamByteSize(StreamIdx); |
| 298 | return llvm::make_unique<MappedBlockStreamImpl>(L, File); |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | Expected<std::unique_ptr<MappedBlockStream>> |
Zachary Turner | bac69d3 | 2016-07-22 19:56:05 +0000 | [diff] [blame] | 302 | MappedBlockStream::createDirectoryStream(uint32_t Length, |
| 303 | ArrayRef<support::ulittle32_t> Blocks, |
| 304 | const IMsfFile &File) { |
Zachary Turner | 199f48a | 2016-07-28 19:11:09 +0000 | [diff] [blame^] | 305 | MsfStreamLayout L; |
| 306 | L.Blocks = Blocks; |
| 307 | L.Length = Length; |
| 308 | |
| 309 | return llvm::make_unique<MappedBlockStreamImpl>(L, File); |
Zachary Turner | a1657a9 | 2016-06-08 17:26:39 +0000 | [diff] [blame] | 310 | } |