1a3225b04SZachary Turner //===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// 2a3225b04SZachary Turner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a3225b04SZachary Turner // 7a3225b04SZachary Turner //===----------------------------------------------------------------------===// 8a3225b04SZachary Turner 9a3225b04SZachary Turner #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 102db0cfa6SEugene Zelenko #include "llvm/ADT/ArrayRef.h" 112db0cfa6SEugene Zelenko #include "llvm/ADT/STLExtras.h" 12a3225b04SZachary Turner #include "llvm/DebugInfo/MSF/MSFCommon.h" 139fb9d71dSZachary Turner #include "llvm/Support/BinaryStreamWriter.h" 142db0cfa6SEugene Zelenko #include "llvm/Support/Endian.h" 152db0cfa6SEugene Zelenko #include "llvm/Support/Error.h" 162db0cfa6SEugene Zelenko #include "llvm/Support/MathExtras.h" 172db0cfa6SEugene Zelenko #include <algorithm> 182db0cfa6SEugene Zelenko #include <cassert> 192db0cfa6SEugene Zelenko #include <cstdint> 202db0cfa6SEugene Zelenko #include <cstring> 212db0cfa6SEugene Zelenko #include <utility> 222db0cfa6SEugene Zelenko #include <vector> 23a3225b04SZachary Turner 24a3225b04SZachary Turner using namespace llvm; 25a3225b04SZachary Turner using namespace llvm::msf; 26a3225b04SZachary Turner 27a3225b04SZachary Turner namespace { 282db0cfa6SEugene Zelenko 29a3225b04SZachary Turner template <typename Base> class MappedBlockStreamImpl : public Base { 30a3225b04SZachary Turner public: 31a3225b04SZachary Turner template <typename... Args> 32a3225b04SZachary Turner MappedBlockStreamImpl(Args &&... Params) 33a3225b04SZachary Turner : Base(std::forward<Args>(Params)...) {} 34a3225b04SZachary Turner }; 352db0cfa6SEugene Zelenko 362db0cfa6SEugene Zelenko } // end anonymous namespace 37a3225b04SZachary Turner 382db0cfa6SEugene Zelenko using Interval = std::pair<uint32_t, uint32_t>; 392db0cfa6SEugene Zelenko 40a3225b04SZachary Turner static Interval intersect(const Interval &I1, const Interval &I2) { 41a3225b04SZachary Turner return std::make_pair(std::max(I1.first, I2.first), 42a3225b04SZachary Turner std::min(I1.second, I2.second)); 43a3225b04SZachary Turner } 44a3225b04SZachary Turner 45c4e4b7e3SZachary Turner MappedBlockStream::MappedBlockStream(uint32_t BlockSize, 46a3225b04SZachary Turner const MSFStreamLayout &Layout, 475b74ff33SZachary Turner BinaryStreamRef MsfData, 485b74ff33SZachary Turner BumpPtrAllocator &Allocator) 495b74ff33SZachary Turner : BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData), 505b74ff33SZachary Turner Allocator(Allocator) {} 51a3225b04SZachary Turner 525b74ff33SZachary Turner std::unique_ptr<MappedBlockStream> MappedBlockStream::createStream( 535b74ff33SZachary Turner uint32_t BlockSize, const MSFStreamLayout &Layout, BinaryStreamRef MsfData, 545b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 55*0eaee545SJonas Devlieghere return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( 565b74ff33SZachary Turner BlockSize, Layout, MsfData, Allocator); 57a3225b04SZachary Turner } 58a3225b04SZachary Turner 59120faca4SZachary Turner std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream( 605b74ff33SZachary Turner const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex, 615b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 62a5b43589SBob Haarman assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); 63a3225b04SZachary Turner MSFStreamLayout SL; 64a3225b04SZachary Turner SL.Blocks = Layout.StreamMap[StreamIndex]; 65a3225b04SZachary Turner SL.Length = Layout.StreamSizes[StreamIndex]; 66*0eaee545SJonas Devlieghere return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>( 675b74ff33SZachary Turner Layout.SB->BlockSize, SL, MsfData, Allocator); 68a3225b04SZachary Turner } 69a3225b04SZachary Turner 70a3225b04SZachary Turner std::unique_ptr<MappedBlockStream> 71a3225b04SZachary Turner MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, 725b74ff33SZachary Turner BinaryStreamRef MsfData, 735b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 74a3225b04SZachary Turner MSFStreamLayout SL; 75a3225b04SZachary Turner SL.Blocks = Layout.DirectoryBlocks; 76a3225b04SZachary Turner SL.Length = Layout.SB->NumDirectoryBytes; 775b74ff33SZachary Turner return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); 78a3225b04SZachary Turner } 79a3225b04SZachary Turner 808cf51c34SZachary Turner std::unique_ptr<MappedBlockStream> 818cf51c34SZachary Turner MappedBlockStream::createFpmStream(const MSFLayout &Layout, 825b74ff33SZachary Turner BinaryStreamRef MsfData, 835b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 84c3d8eec9SZachary Turner MSFStreamLayout SL(getFpmStreamLayout(Layout)); 855b74ff33SZachary Turner return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); 868cf51c34SZachary Turner } 878cf51c34SZachary Turner 88a3225b04SZachary Turner Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, 89120faca4SZachary Turner ArrayRef<uint8_t> &Buffer) { 90a3225b04SZachary Turner // Make sure we aren't trying to read beyond the end of the stream. 9196c6985bSZachary Turner if (auto EC = checkOffsetForRead(Offset, Size)) 92d0b44fa7SZachary Turner return EC; 93a3225b04SZachary Turner 94a3225b04SZachary Turner if (tryReadContiguously(Offset, Size, Buffer)) 95a3225b04SZachary Turner return Error::success(); 96a3225b04SZachary Turner 97a3225b04SZachary Turner auto CacheIter = CacheMap.find(Offset); 98a3225b04SZachary Turner if (CacheIter != CacheMap.end()) { 99a3225b04SZachary Turner // Try to find an alloc that was large enough for this request. 100a3225b04SZachary Turner for (auto &Entry : CacheIter->second) { 101a3225b04SZachary Turner if (Entry.size() >= Size) { 102a3225b04SZachary Turner Buffer = Entry.slice(0, Size); 103a3225b04SZachary Turner return Error::success(); 104a3225b04SZachary Turner } 105a3225b04SZachary Turner } 106a3225b04SZachary Turner } 107a3225b04SZachary Turner 108a3225b04SZachary Turner // We couldn't find a buffer that started at the correct offset (the most 109a3225b04SZachary Turner // common scenario). Try to see if there is a buffer that starts at some 110a3225b04SZachary Turner // other offset but overlaps the desired range. 111a3225b04SZachary Turner for (auto &CacheItem : CacheMap) { 112a3225b04SZachary Turner Interval RequestExtent = std::make_pair(Offset, Offset + Size); 113a3225b04SZachary Turner 114a3225b04SZachary Turner // We already checked this one on the fast path above. 115a3225b04SZachary Turner if (CacheItem.first == Offset) 116a3225b04SZachary Turner continue; 117a3225b04SZachary Turner // If the initial extent of the cached item is beyond the ending extent 118a3225b04SZachary Turner // of the request, there is no overlap. 119a3225b04SZachary Turner if (CacheItem.first >= Offset + Size) 120a3225b04SZachary Turner continue; 121a3225b04SZachary Turner 122a3225b04SZachary Turner // We really only have to check the last item in the list, since we append 123a3225b04SZachary Turner // in order of increasing length. 124a3225b04SZachary Turner if (CacheItem.second.empty()) 125a3225b04SZachary Turner continue; 126a3225b04SZachary Turner 127a3225b04SZachary Turner auto CachedAlloc = CacheItem.second.back(); 128a3225b04SZachary Turner // If the initial extent of the request is beyond the ending extent of 129a3225b04SZachary Turner // the cached item, there is no overlap. 130a3225b04SZachary Turner Interval CachedExtent = 131a3225b04SZachary Turner std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); 132a3225b04SZachary Turner if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) 133a3225b04SZachary Turner continue; 134a3225b04SZachary Turner 135a3225b04SZachary Turner Interval Intersection = intersect(CachedExtent, RequestExtent); 136a3225b04SZachary Turner // Only use this if the entire request extent is contained in the cached 137a3225b04SZachary Turner // extent. 138a3225b04SZachary Turner if (Intersection != RequestExtent) 139a3225b04SZachary Turner continue; 140a3225b04SZachary Turner 141a3225b04SZachary Turner uint32_t CacheRangeOffset = 142a3225b04SZachary Turner AbsoluteDifference(CachedExtent.first, Intersection.first); 143a3225b04SZachary Turner Buffer = CachedAlloc.slice(CacheRangeOffset, Size); 144a3225b04SZachary Turner return Error::success(); 145a3225b04SZachary Turner } 146a3225b04SZachary Turner 147a3225b04SZachary Turner // Otherwise allocate a large enough buffer in the pool, memcpy the data 148a3225b04SZachary Turner // into it, and return an ArrayRef to that. Do not touch existing pool 149a3225b04SZachary Turner // allocations, as existing clients may be holding a pointer which must 150a3225b04SZachary Turner // not be invalidated. 1515b74ff33SZachary Turner uint8_t *WriteBuffer = static_cast<uint8_t *>(Allocator.Allocate(Size, 8)); 152a3225b04SZachary Turner if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size))) 153a3225b04SZachary Turner return EC; 154a3225b04SZachary Turner 155a3225b04SZachary Turner if (CacheIter != CacheMap.end()) { 156a3225b04SZachary Turner CacheIter->second.emplace_back(WriteBuffer, Size); 157a3225b04SZachary Turner } else { 158a3225b04SZachary Turner std::vector<CacheEntry> List; 159a3225b04SZachary Turner List.emplace_back(WriteBuffer, Size); 160a3225b04SZachary Turner CacheMap.insert(std::make_pair(Offset, List)); 161a3225b04SZachary Turner } 162a3225b04SZachary Turner Buffer = ArrayRef<uint8_t>(WriteBuffer, Size); 163a3225b04SZachary Turner return Error::success(); 164a3225b04SZachary Turner } 165a3225b04SZachary Turner 166120faca4SZachary Turner Error MappedBlockStream::readLongestContiguousChunk(uint32_t Offset, 167120faca4SZachary Turner ArrayRef<uint8_t> &Buffer) { 168a3225b04SZachary Turner // Make sure we aren't trying to read beyond the end of the stream. 16996c6985bSZachary Turner if (auto EC = checkOffsetForRead(Offset, 1)) 170d0b44fa7SZachary Turner return EC; 171d0b44fa7SZachary Turner 172a3225b04SZachary Turner uint32_t First = Offset / BlockSize; 173a3225b04SZachary Turner uint32_t Last = First; 174a3225b04SZachary Turner 175c4e4b7e3SZachary Turner while (Last < getNumBlocks() - 1) { 176a3225b04SZachary Turner if (StreamLayout.Blocks[Last] != StreamLayout.Blocks[Last + 1] - 1) 177a3225b04SZachary Turner break; 178a3225b04SZachary Turner ++Last; 179a3225b04SZachary Turner } 180a3225b04SZachary Turner 181a3225b04SZachary Turner uint32_t OffsetInFirstBlock = Offset % BlockSize; 182a3225b04SZachary Turner uint32_t BytesFromFirstBlock = BlockSize - OffsetInFirstBlock; 183a3225b04SZachary Turner uint32_t BlockSpan = Last - First + 1; 184a3225b04SZachary Turner uint32_t ByteSpan = BytesFromFirstBlock + (BlockSpan - 1) * BlockSize; 185a3225b04SZachary Turner 186a3225b04SZachary Turner ArrayRef<uint8_t> BlockData; 187a3225b04SZachary Turner uint32_t MsfOffset = blockToOffset(StreamLayout.Blocks[First], BlockSize); 188a3225b04SZachary Turner if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData)) 189a3225b04SZachary Turner return EC; 190a3225b04SZachary Turner 191a3225b04SZachary Turner BlockData = BlockData.drop_front(OffsetInFirstBlock); 192a3225b04SZachary Turner Buffer = ArrayRef<uint8_t>(BlockData.data(), ByteSpan); 193a3225b04SZachary Turner return Error::success(); 194a3225b04SZachary Turner } 195a3225b04SZachary Turner 196120faca4SZachary Turner uint32_t MappedBlockStream::getLength() { return StreamLayout.Length; } 197a3225b04SZachary Turner 198a3225b04SZachary Turner bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, 199120faca4SZachary Turner ArrayRef<uint8_t> &Buffer) { 20036efbfa6SZachary Turner if (Size == 0) { 20136efbfa6SZachary Turner Buffer = ArrayRef<uint8_t>(); 20236efbfa6SZachary Turner return true; 20336efbfa6SZachary Turner } 204a3225b04SZachary Turner // Attempt to fulfill the request with a reference directly into the stream. 205a3225b04SZachary Turner // This can work even if the request crosses a block boundary, provided that 206a3225b04SZachary Turner // all subsequent blocks are contiguous. For example, a 10k read with a 4k 207a3225b04SZachary Turner // block size can be filled with a reference if, from the starting offset, 208a3225b04SZachary Turner // 3 blocks in a row are contiguous. 209a3225b04SZachary Turner uint32_t BlockNum = Offset / BlockSize; 210a3225b04SZachary Turner uint32_t OffsetInBlock = Offset % BlockSize; 211a3225b04SZachary Turner uint32_t BytesFromFirstBlock = std::min(Size, BlockSize - OffsetInBlock); 212a3225b04SZachary Turner uint32_t NumAdditionalBlocks = 2132db0cfa6SEugene Zelenko alignTo(Size - BytesFromFirstBlock, BlockSize) / BlockSize; 214a3225b04SZachary Turner 215a3225b04SZachary Turner uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; 216a3225b04SZachary Turner uint32_t E = StreamLayout.Blocks[BlockNum]; 217a3225b04SZachary Turner for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { 218a3225b04SZachary Turner if (StreamLayout.Blocks[I + BlockNum] != E) 219a3225b04SZachary Turner return false; 220a3225b04SZachary Turner } 221a3225b04SZachary Turner 222a3225b04SZachary Turner // Read out the entire block where the requested offset starts. Then drop 223a3225b04SZachary Turner // bytes from the beginning so that the actual starting byte lines up with 224a3225b04SZachary Turner // the requested starting byte. Then, since we know this is a contiguous 225a3225b04SZachary Turner // cross-block span, explicitly resize the ArrayRef to cover the entire 226a3225b04SZachary Turner // request length. 227a3225b04SZachary Turner ArrayRef<uint8_t> BlockData; 228a3225b04SZachary Turner uint32_t FirstBlockAddr = StreamLayout.Blocks[BlockNum]; 229a3225b04SZachary Turner uint32_t MsfOffset = blockToOffset(FirstBlockAddr, BlockSize); 230a3225b04SZachary Turner if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData)) { 231a3225b04SZachary Turner consumeError(std::move(EC)); 232a3225b04SZachary Turner return false; 233a3225b04SZachary Turner } 234a3225b04SZachary Turner BlockData = BlockData.drop_front(OffsetInBlock); 235a3225b04SZachary Turner Buffer = ArrayRef<uint8_t>(BlockData.data(), Size); 236a3225b04SZachary Turner return true; 237a3225b04SZachary Turner } 238a3225b04SZachary Turner 239a3225b04SZachary Turner Error MappedBlockStream::readBytes(uint32_t Offset, 240120faca4SZachary Turner MutableArrayRef<uint8_t> Buffer) { 241a3225b04SZachary Turner uint32_t BlockNum = Offset / BlockSize; 242a3225b04SZachary Turner uint32_t OffsetInBlock = Offset % BlockSize; 243a3225b04SZachary Turner 244a3225b04SZachary Turner // Make sure we aren't trying to read beyond the end of the stream. 24596c6985bSZachary Turner if (auto EC = checkOffsetForRead(Offset, Buffer.size())) 246d0b44fa7SZachary Turner return EC; 247a3225b04SZachary Turner 248a3225b04SZachary Turner uint32_t BytesLeft = Buffer.size(); 249a3225b04SZachary Turner uint32_t BytesWritten = 0; 250a3225b04SZachary Turner uint8_t *WriteBuffer = Buffer.data(); 251a3225b04SZachary Turner while (BytesLeft > 0) { 252a3225b04SZachary Turner uint32_t StreamBlockAddr = StreamLayout.Blocks[BlockNum]; 253a3225b04SZachary Turner 254a3225b04SZachary Turner ArrayRef<uint8_t> BlockData; 255a3225b04SZachary Turner uint32_t Offset = blockToOffset(StreamBlockAddr, BlockSize); 256a3225b04SZachary Turner if (auto EC = MsfData.readBytes(Offset, BlockSize, BlockData)) 257a3225b04SZachary Turner return EC; 258a3225b04SZachary Turner 259a3225b04SZachary Turner const uint8_t *ChunkStart = BlockData.data() + OffsetInBlock; 260a3225b04SZachary Turner uint32_t BytesInChunk = std::min(BytesLeft, BlockSize - OffsetInBlock); 261a3225b04SZachary Turner ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); 262a3225b04SZachary Turner 263a3225b04SZachary Turner BytesWritten += BytesInChunk; 264a3225b04SZachary Turner BytesLeft -= BytesInChunk; 265a3225b04SZachary Turner ++BlockNum; 266a3225b04SZachary Turner OffsetInBlock = 0; 267a3225b04SZachary Turner } 268a3225b04SZachary Turner 269a3225b04SZachary Turner return Error::success(); 270a3225b04SZachary Turner } 271a3225b04SZachary Turner 272a3225b04SZachary Turner void MappedBlockStream::invalidateCache() { CacheMap.shrink_and_clear(); } 273a3225b04SZachary Turner 274a3225b04SZachary Turner void MappedBlockStream::fixCacheAfterWrite(uint32_t Offset, 275a3225b04SZachary Turner ArrayRef<uint8_t> Data) const { 276a3225b04SZachary Turner // If this write overlapped a read which previously came from the pool, 277a3225b04SZachary Turner // someone may still be holding a pointer to that alloc which is now invalid. 278a3225b04SZachary Turner // Compute the overlapping range and update the cache entry, so any 279a3225b04SZachary Turner // outstanding buffers are automatically updated. 280a3225b04SZachary Turner for (const auto &MapEntry : CacheMap) { 281a3225b04SZachary Turner // If the end of the written extent precedes the beginning of the cached 282a3225b04SZachary Turner // extent, ignore this map entry. 283a3225b04SZachary Turner if (Offset + Data.size() < MapEntry.first) 284a3225b04SZachary Turner continue; 285a3225b04SZachary Turner for (const auto &Alloc : MapEntry.second) { 286a3225b04SZachary Turner // If the end of the cached extent precedes the beginning of the written 287a3225b04SZachary Turner // extent, ignore this alloc. 288a3225b04SZachary Turner if (MapEntry.first + Alloc.size() < Offset) 289a3225b04SZachary Turner continue; 290a3225b04SZachary Turner 291a3225b04SZachary Turner // If we get here, they are guaranteed to overlap. 292a3225b04SZachary Turner Interval WriteInterval = std::make_pair(Offset, Offset + Data.size()); 293a3225b04SZachary Turner Interval CachedInterval = 294a3225b04SZachary Turner std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); 295a3225b04SZachary Turner // If they overlap, we need to write the new data into the overlapping 296a3225b04SZachary Turner // range. 297a3225b04SZachary Turner auto Intersection = intersect(WriteInterval, CachedInterval); 298a3225b04SZachary Turner assert(Intersection.first <= Intersection.second); 299a3225b04SZachary Turner 300a3225b04SZachary Turner uint32_t Length = Intersection.second - Intersection.first; 301a3225b04SZachary Turner uint32_t SrcOffset = 302a3225b04SZachary Turner AbsoluteDifference(WriteInterval.first, Intersection.first); 303a3225b04SZachary Turner uint32_t DestOffset = 304a3225b04SZachary Turner AbsoluteDifference(CachedInterval.first, Intersection.first); 305a3225b04SZachary Turner ::memcpy(Alloc.data() + DestOffset, Data.data() + SrcOffset, Length); 306a3225b04SZachary Turner } 307a3225b04SZachary Turner } 308a3225b04SZachary Turner } 309a3225b04SZachary Turner 310a3225b04SZachary Turner WritableMappedBlockStream::WritableMappedBlockStream( 311c4e4b7e3SZachary Turner uint32_t BlockSize, const MSFStreamLayout &Layout, 3125b74ff33SZachary Turner WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator) 3135b74ff33SZachary Turner : ReadInterface(BlockSize, Layout, MsfData, Allocator), 3145b74ff33SZachary Turner WriteInterface(MsfData) {} 315a3225b04SZachary Turner 316a3225b04SZachary Turner std::unique_ptr<WritableMappedBlockStream> 317c4e4b7e3SZachary Turner WritableMappedBlockStream::createStream(uint32_t BlockSize, 318a3225b04SZachary Turner const MSFStreamLayout &Layout, 3195b74ff33SZachary Turner WritableBinaryStreamRef MsfData, 3205b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 321*0eaee545SJonas Devlieghere return std::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>( 3225b74ff33SZachary Turner BlockSize, Layout, MsfData, Allocator); 323a3225b04SZachary Turner } 324a3225b04SZachary Turner 325a3225b04SZachary Turner std::unique_ptr<WritableMappedBlockStream> 326a3225b04SZachary Turner WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, 327120faca4SZachary Turner WritableBinaryStreamRef MsfData, 3285b74ff33SZachary Turner uint32_t StreamIndex, 3295b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 330a5b43589SBob Haarman assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); 331a3225b04SZachary Turner MSFStreamLayout SL; 332a3225b04SZachary Turner SL.Blocks = Layout.StreamMap[StreamIndex]; 333a3225b04SZachary Turner SL.Length = Layout.StreamSizes[StreamIndex]; 3345b74ff33SZachary Turner return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); 335a3225b04SZachary Turner } 336a3225b04SZachary Turner 337a3225b04SZachary Turner std::unique_ptr<WritableMappedBlockStream> 338a3225b04SZachary Turner WritableMappedBlockStream::createDirectoryStream( 3395b74ff33SZachary Turner const MSFLayout &Layout, WritableBinaryStreamRef MsfData, 3405b74ff33SZachary Turner BumpPtrAllocator &Allocator) { 341a3225b04SZachary Turner MSFStreamLayout SL; 342a3225b04SZachary Turner SL.Blocks = Layout.DirectoryBlocks; 343a3225b04SZachary Turner SL.Length = Layout.SB->NumDirectoryBytes; 3445b74ff33SZachary Turner return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator); 345a3225b04SZachary Turner } 346a3225b04SZachary Turner 3478cf51c34SZachary Turner std::unique_ptr<WritableMappedBlockStream> 3488cf51c34SZachary Turner WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, 3495b74ff33SZachary Turner WritableBinaryStreamRef MsfData, 3509fb9d71dSZachary Turner BumpPtrAllocator &Allocator, 3519fb9d71dSZachary Turner bool AltFpm) { 3529fb9d71dSZachary Turner // We only want to give the user a stream containing the bytes of the FPM that 3539fb9d71dSZachary Turner // are actually valid, but we want to initialize all of the bytes, even those 3549fb9d71dSZachary Turner // that come from reserved FPM blocks where the entire block is unused. To do 3559fb9d71dSZachary Turner // this, we first create the full layout, which gives us a stream with all 3569fb9d71dSZachary Turner // bytes and all blocks, and initialize everything to 0xFF (all blocks in the 3579fb9d71dSZachary Turner // file are unused). Then we create the minimal layout (which contains only a 3589fb9d71dSZachary Turner // subset of the bytes previously initialized), and return that to the user. 3599fb9d71dSZachary Turner MSFStreamLayout MinLayout(getFpmStreamLayout(Layout, false, AltFpm)); 3609fb9d71dSZachary Turner 3619fb9d71dSZachary Turner MSFStreamLayout FullLayout(getFpmStreamLayout(Layout, true, AltFpm)); 3629fb9d71dSZachary Turner auto Result = 3639fb9d71dSZachary Turner createStream(Layout.SB->BlockSize, FullLayout, MsfData, Allocator); 3649fb9d71dSZachary Turner if (!Result) 3659fb9d71dSZachary Turner return Result; 3669fb9d71dSZachary Turner std::vector<uint8_t> InitData(Layout.SB->BlockSize, 0xFF); 3679fb9d71dSZachary Turner BinaryStreamWriter Initializer(*Result); 3689fb9d71dSZachary Turner while (Initializer.bytesRemaining() > 0) 3699fb9d71dSZachary Turner cantFail(Initializer.writeBytes(InitData)); 3709fb9d71dSZachary Turner return createStream(Layout.SB->BlockSize, MinLayout, MsfData, Allocator); 3718cf51c34SZachary Turner } 3728cf51c34SZachary Turner 373a3225b04SZachary Turner Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, 374120faca4SZachary Turner ArrayRef<uint8_t> &Buffer) { 375a3225b04SZachary Turner return ReadInterface.readBytes(Offset, Size, Buffer); 376a3225b04SZachary Turner } 377a3225b04SZachary Turner 378a3225b04SZachary Turner Error WritableMappedBlockStream::readLongestContiguousChunk( 379120faca4SZachary Turner uint32_t Offset, ArrayRef<uint8_t> &Buffer) { 380a3225b04SZachary Turner return ReadInterface.readLongestContiguousChunk(Offset, Buffer); 381a3225b04SZachary Turner } 382a3225b04SZachary Turner 383120faca4SZachary Turner uint32_t WritableMappedBlockStream::getLength() { 384a3225b04SZachary Turner return ReadInterface.getLength(); 385a3225b04SZachary Turner } 386a3225b04SZachary Turner 387a3225b04SZachary Turner Error WritableMappedBlockStream::writeBytes(uint32_t Offset, 388120faca4SZachary Turner ArrayRef<uint8_t> Buffer) { 389a3225b04SZachary Turner // Make sure we aren't trying to write beyond the end of the stream. 39096c6985bSZachary Turner if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) 391d0b44fa7SZachary Turner return EC; 392a3225b04SZachary Turner 393a3225b04SZachary Turner uint32_t BlockNum = Offset / getBlockSize(); 394a3225b04SZachary Turner uint32_t OffsetInBlock = Offset % getBlockSize(); 395a3225b04SZachary Turner 396a3225b04SZachary Turner uint32_t BytesLeft = Buffer.size(); 397a3225b04SZachary Turner uint32_t BytesWritten = 0; 398a3225b04SZachary Turner while (BytesLeft > 0) { 399a3225b04SZachary Turner uint32_t StreamBlockAddr = getStreamLayout().Blocks[BlockNum]; 400a3225b04SZachary Turner uint32_t BytesToWriteInChunk = 401a3225b04SZachary Turner std::min(BytesLeft, getBlockSize() - OffsetInBlock); 402a3225b04SZachary Turner 403a3225b04SZachary Turner const uint8_t *Chunk = Buffer.data() + BytesWritten; 404a3225b04SZachary Turner ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk); 405a3225b04SZachary Turner uint32_t MsfOffset = blockToOffset(StreamBlockAddr, getBlockSize()); 406a3225b04SZachary Turner MsfOffset += OffsetInBlock; 407a3225b04SZachary Turner if (auto EC = WriteInterface.writeBytes(MsfOffset, ChunkData)) 408a3225b04SZachary Turner return EC; 409a3225b04SZachary Turner 410a3225b04SZachary Turner BytesLeft -= BytesToWriteInChunk; 411a3225b04SZachary Turner BytesWritten += BytesToWriteInChunk; 412a3225b04SZachary Turner ++BlockNum; 413a3225b04SZachary Turner OffsetInBlock = 0; 414a3225b04SZachary Turner } 415a3225b04SZachary Turner 416a3225b04SZachary Turner ReadInterface.fixCacheAfterWrite(Offset, Buffer); 417a3225b04SZachary Turner 418a3225b04SZachary Turner return Error::success(); 419a3225b04SZachary Turner } 420a3225b04SZachary Turner 421120faca4SZachary Turner Error WritableMappedBlockStream::commit() { return WriteInterface.commit(); } 422