Index: llvm/include/llvm/Support/BinaryStreamReader.h =================================================================== --- llvm/include/llvm/Support/BinaryStreamReader.h +++ llvm/include/llvm/Support/BinaryStreamReader.h @@ -32,7 +32,22 @@ class BinaryStreamReader { public: BinaryStreamReader() = default; - explicit BinaryStreamReader(BinaryStreamRef Stream); + template + explicit BinaryStreamReader(Ts &&... Args) + : Stream(std::forward(Args)...), Offset(0) {} + + BinaryStreamReader(BinaryStreamReader &Other) + : Stream(Other.Stream), Offset(Other.Offset) {} + + BinaryStreamReader(BinaryStreamReader &&Other) + : Stream(std::move(Other.Stream)), Offset(Other.Offset) {} + + BinaryStreamReader &operator=(const BinaryStreamReader &Other) { + Stream = Other.Stream; + Offset = Other.Offset; + return *this; + } + virtual ~BinaryStreamReader() {} /// Read as much as possible from the underlying string at the current offset Index: llvm/include/llvm/Support/BinaryStreamRef.h =================================================================== --- llvm/include/llvm/Support/BinaryStreamRef.h +++ llvm/include/llvm/Support/BinaryStreamRef.h @@ -16,36 +16,55 @@ #include "llvm/Support/Error.h" #include #include +#include namespace llvm { /// Common stuff for mutable and immutable StreamRefs. -template class BinaryStreamRefBase { -public: - BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} - BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length) - : Stream(&Stream), ViewOffset(Offset), Length(Length) {} +template class BinaryStreamRefBase { +protected: + BinaryStreamRefBase() = default; + BinaryStreamRefBase(std::shared_ptr SharedImpl, uint32_t Offset, + uint32_t Length) + : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()), + ViewOffset(Offset), Length(Length) {} + BinaryStreamRefBase(StreamType &BorrowedImpl, uint32_t Offset, + uint32_t Length) + : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {} + BinaryStreamRefBase(const BinaryStreamRefBase &Other) { + SharedImpl = Other.SharedImpl; + BorrowedImpl = Other.BorrowedImpl; + ViewOffset = Other.ViewOffset; + Length = Other.Length; + } - llvm::support::endianness getEndian() const { return Stream->getEndian(); } +public: + llvm::support::endianness getEndian() const { + return BorrowedImpl->getEndian(); + } uint32_t getLength() const { return Length; } - const StreamType *getStream() const { return Stream; } /// Return a new BinaryStreamRef with the first \p N elements removed. RefType drop_front(uint32_t N) const { - if (!Stream) + if (!BorrowedImpl) return RefType(); N = std::min(N, Length); - return RefType(*Stream, ViewOffset + N, Length - N); + RefType Result(static_cast(*this)); + Result.ViewOffset += N; + Result.Length -= N; + return Result; } /// Return a new BinaryStreamRef with only the first \p N elements remaining. RefType keep_front(uint32_t N) const { - if (!Stream) + if (!BorrowedImpl) return RefType(); N = std::min(N, Length); - return RefType(*Stream, ViewOffset, N); + RefType Result(static_cast(*this)); + Result.Length = N; + return Result; } /// Return a new BinaryStreamRef with the first \p Offset elements removed, @@ -54,8 +73,10 @@ return drop_front(Offset).keep_front(Len); } + bool valid() const { return BorrowedImpl != nullptr; } + bool operator==(const RefType &Other) const { - if (Stream != Other.Stream) + if (BorrowedImpl != Other.BorrowedImpl) return false; if (ViewOffset != Other.ViewOffset) return false; @@ -73,9 +94,10 @@ return Error::success(); } - StreamType *Stream; - uint32_t ViewOffset; - uint32_t Length; + std::shared_ptr SharedImpl; + StreamType *BorrowedImpl = nullptr; + uint32_t ViewOffset = 0; + uint32_t Length = 0; }; /// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It @@ -86,21 +108,27 @@ /// and use inheritance to achieve polymorphism. Instead, you should pass /// around BinaryStreamRefs by value and achieve polymorphism that way. class BinaryStreamRef - : public BinaryStreamRefBase { + : public BinaryStreamRefBase { + friend BinaryStreamRefBase; + friend class WritableBinaryStreamRef; + BinaryStreamRef(std::shared_ptr Impl, uint32_t ViewOffset, + uint32_t Length) + : BinaryStreamRefBase(Impl, ViewOffset, Length) {} + public: BinaryStreamRef() = default; - BinaryStreamRef(BinaryStream &Stream) - : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} - BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length) - : BinaryStreamRefBase(Stream, Offset, Length) {} + BinaryStreamRef(BinaryStream &Stream); + BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length); + explicit BinaryStreamRef(ArrayRef Data, + llvm::support::endianness Endian); + explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian); + + BinaryStreamRef(const BinaryStreamRef &Other); // Use BinaryStreamRef.slice() instead. BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, uint32_t Length) = delete; - /// Check if a Stream is valid. - bool valid() const { return Stream != nullptr; } - /// Given an Offset into this StreamRef and a Size, return a reference to a /// buffer owned by the stream. /// @@ -108,12 +136,7 @@ /// bounds of this BinaryStreamRef's view and the implementation could read /// the data, and an appropriate error code otherwise. Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { - if (auto EC = checkOffset(Offset, Size)) - return EC; - - return Stream->readBytes(ViewOffset + Offset, Size, Buffer); - } + ArrayRef &Buffer) const; /// Given an Offset into this BinaryStreamRef, return a reference to the /// largest buffer the stream could support without necessitating a copy. @@ -121,33 +144,25 @@ /// \returns a success error code if implementation could read the data, /// and an appropriate error code otherwise. Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const { - if (auto EC = checkOffset(Offset, 1)) - return EC; - - if (auto EC = - Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) - return EC; - // This StreamRef might refer to a smaller window over a larger stream. In - // that case we will have read out more bytes than we should return, because - // we should not read past the end of the current view. - uint32_t MaxLength = Length - Offset; - if (Buffer.size() > MaxLength) - Buffer = Buffer.slice(0, MaxLength); - return Error::success(); - } + ArrayRef &Buffer) const; }; class WritableBinaryStreamRef - : public BinaryStreamRefBase { + : public BinaryStreamRefBase { + friend BinaryStreamRefBase; + WritableBinaryStreamRef(std::shared_ptr Impl, + uint32_t ViewOffset, uint32_t Length) + : BinaryStreamRefBase(Impl, ViewOffset, Length) {} + public: WritableBinaryStreamRef() = default; - WritableBinaryStreamRef(WritableBinaryStream &Stream) - : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} + WritableBinaryStreamRef(WritableBinaryStream &Stream); WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, - uint32_t Length) - : BinaryStreamRefBase(Stream, Offset, Length) {} + uint32_t Length); + explicit WritableBinaryStreamRef(MutableArrayRef Data, + llvm::support::endianness Endian); + WritableBinaryStreamRef(const WritableBinaryStreamRef &Other); // Use WritableBinaryStreamRef.slice() instead. WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, @@ -159,17 +174,13 @@ /// \returns a success error code if the data could fit within the underlying /// stream at the specified location and the implementation could write the /// data, and an appropriate error code otherwise. - Error writeBytes(uint32_t Offset, ArrayRef Data) const { - if (auto EC = checkOffset(Offset, Data.size())) - return EC; - - return Stream->writeBytes(ViewOffset + Offset, Data); - } + Error writeBytes(uint32_t Offset, ArrayRef Data) const; - operator BinaryStreamRef() { return BinaryStreamRef(*Stream); } + /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef. + operator BinaryStreamRef() const; /// \brief For buffered streams, commits changes to the backing store. - Error commit() { return Stream->commit(); } + Error commit(); }; } // end namespace llvm Index: llvm/include/llvm/Support/BinaryStreamWriter.h =================================================================== --- llvm/include/llvm/Support/BinaryStreamWriter.h +++ llvm/include/llvm/Support/BinaryStreamWriter.h @@ -32,7 +32,22 @@ class BinaryStreamWriter { public: BinaryStreamWriter() = default; - explicit BinaryStreamWriter(WritableBinaryStreamRef Stream); + template + BinaryStreamWriter(Ts &&... Args) + : Stream(std::forward(Args)...), Offset(0) {} + + BinaryStreamWriter(BinaryStreamWriter &Other) + : Stream(Other.Stream), Offset(Other.Offset) {} + + BinaryStreamWriter(BinaryStreamWriter &&Other) + : Stream(std::move(Other.Stream)), Offset(Other.Offset) {} + + BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) { + Stream = Other.Stream; + Offset = Other.Offset; + return *this; + } + virtual ~BinaryStreamWriter() {} /// Write the bytes specified in \p Buffer to the underlying stream. Index: llvm/lib/Support/BinaryStreamReader.cpp =================================================================== --- llvm/lib/Support/BinaryStreamReader.cpp +++ llvm/lib/Support/BinaryStreamReader.cpp @@ -14,9 +14,6 @@ using namespace llvm; -BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S) - : Stream(S), Offset(0) {} - Error BinaryStreamReader::readLongestContiguousChunk( ArrayRef &Buffer) { if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) Index: llvm/lib/Support/BinaryStreamRef.cpp =================================================================== --- /dev/null +++ llvm/lib/Support/BinaryStreamRef.cpp @@ -0,0 +1,141 @@ +//===- BinaryStreamRef.cpp - ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryByteStream.h" + +using namespace llvm; +using namespace llvm::support; + +namespace { + +class ArrayRefBinaryStreamRefImpl : public BinaryStream { +public: + ArrayRefBinaryStreamRefImpl(ArrayRef Data, endianness Endian) + : BBS(Data, Endian) {} + + llvm::support::endianness getEndian() const override { + return BBS.getEndian(); + } + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + return BBS.readBytes(Offset, Size, Buffer); + } + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + return BBS.readLongestContiguousChunk(Offset, Buffer); + } + uint32_t getLength() override { return BBS.getLength(); } + +private: + BinaryByteStream BBS; +}; + +class MutableArrayRefBinaryStreamRefImpl : public WritableBinaryStream { +public: + MutableArrayRefBinaryStreamRefImpl(MutableArrayRef Data, + endianness Endian) + : BBS(Data, Endian) {} + + // Inherited via WritableBinaryStream + llvm::support::endianness getEndian() const override { + return BBS.getEndian(); + } + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + return BBS.readBytes(Offset, Size, Buffer); + } + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + return BBS.readLongestContiguousChunk(Offset, Buffer); + } + uint32_t getLength() override { return BBS.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef Data) override { + return BBS.writeBytes(Offset, Data); + } + Error commit() override { return BBS.commit(); } + +private: + MutableBinaryByteStream BBS; +}; +} + +BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream) + : BinaryStreamRef(Stream, 0, Stream.getLength()) {} +BinaryStreamRef::BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, + uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} +BinaryStreamRef::BinaryStreamRef(ArrayRef Data, endianness Endian) + : BinaryStreamRefBase( + std::make_shared(Data, Endian), 0, + Data.size()) {} +BinaryStreamRef::BinaryStreamRef(StringRef Data, endianness Endian) + : BinaryStreamRef(makeArrayRef(Data.bytes_begin(), Data.bytes_end()), + Endian) {} + +BinaryStreamRef::BinaryStreamRef(const BinaryStreamRef &Other) + : BinaryStreamRefBase(Other) {} + +Error BinaryStreamRef::readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const { + if (auto EC = checkOffset(Offset, Size)) + return EC; + return BorrowedImpl->readBytes(ViewOffset + Offset, Size, Buffer); +} + +Error BinaryStreamRef::readLongestContiguousChunk( + uint32_t Offset, ArrayRef &Buffer) const { + if (auto EC = checkOffset(Offset, 1)) + return EC; + + if (auto EC = + BorrowedImpl->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) + return EC; + // This StreamRef might refer to a smaller window over a larger stream. In + // that case we will have read out more bytes than we should return, because + // we should not read past the end of the current view. + uint32_t MaxLength = Length - Offset; + if (Buffer.size() > MaxLength) + Buffer = Buffer.slice(0, MaxLength); + return Error::success(); +} + +WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream) + : WritableBinaryStreamRef(Stream, 0, Stream.getLength()) {} + +WritableBinaryStreamRef::WritableBinaryStreamRef(WritableBinaryStream &Stream, + uint32_t Offset, + uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} + +WritableBinaryStreamRef::WritableBinaryStreamRef(MutableArrayRef Data, + endianness Endian) + : BinaryStreamRefBase( + std::make_shared(Data, Endian), 0, + Data.size()) {} + +WritableBinaryStreamRef::WritableBinaryStreamRef( + const WritableBinaryStreamRef &Other) + : BinaryStreamRefBase(Other) {} + +Error WritableBinaryStreamRef::writeBytes(uint32_t Offset, + ArrayRef Data) const { + if (auto EC = checkOffset(Offset, Data.size())) + return EC; + + return BorrowedImpl->writeBytes(ViewOffset + Offset, Data); +} + +WritableBinaryStreamRef::operator BinaryStreamRef() const { + return BinaryStreamRef(*BorrowedImpl, ViewOffset, Length); +} + +/// \brief For buffered streams, commits changes to the backing store. +Error WritableBinaryStreamRef::commit() { return BorrowedImpl->commit(); } Index: llvm/lib/Support/BinaryStreamWriter.cpp =================================================================== --- llvm/lib/Support/BinaryStreamWriter.cpp +++ llvm/lib/Support/BinaryStreamWriter.cpp @@ -15,9 +15,6 @@ using namespace llvm; -BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef S) - : Stream(S), Offset(0) {} - Error BinaryStreamWriter::writeBytes(ArrayRef Buffer) { if (auto EC = Stream.writeBytes(Offset, Buffer)) return EC; Index: llvm/lib/Support/CMakeLists.txt =================================================================== --- llvm/lib/Support/CMakeLists.txt +++ llvm/lib/Support/CMakeLists.txt @@ -39,6 +39,7 @@ Allocator.cpp BinaryStreamError.cpp BinaryStreamReader.cpp + BinaryStreamRef.cpp BinaryStreamWriter.cpp BlockFrequency.cpp BranchProbability.cpp Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/tools/llvm-readobj/COFFDumper.cpp @@ -41,7 +41,6 @@ #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/COFF.h" #include "llvm/Support/ConvertUTF.h" @@ -155,10 +154,8 @@ bool RelocCached = false; RelocMapTy RelocMap; - BinaryByteStream ChecksumContents; VarStreamArray CVFileChecksumTable; - BinaryByteStream StringTableContents; StringTableRef CVStringTable; ScopedPrinter &Writer; @@ -775,14 +772,13 @@ switch (ModuleDebugFragmentKind(SubType)) { case ModuleDebugFragmentKind::FileChecksums: { - ChecksumContents = BinaryByteStream(Contents, support::little); - BinaryStreamReader CSR(ChecksumContents); + BinaryStreamReader CSR(Contents, support::little); error(CSR.readArray(CVFileChecksumTable, CSR.getLength())); break; } case ModuleDebugFragmentKind::StringTable: { - StringTableContents = BinaryByteStream(Contents, support::little); - error(CVStringTable.initialize(StringTableContents)); + BinaryStreamRef ST(Contents, support::little); + error(CVStringTable.initialize(ST)); } break; default: break; @@ -812,8 +808,7 @@ if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); - BinaryByteStream FileAndStrings(Data, support::little); - BinaryStreamReader FSReader(FileAndStrings); + BinaryStreamReader FSReader(Data, support::little); initializeFileAndStringTables(FSReader); // TODO: Convert this over to using ModuleSubstreamVisitor. @@ -889,8 +884,7 @@ } case ModuleDebugFragmentKind::FrameData: { // First four bytes is a relocation against the function. - BinaryByteStream S(Contents, llvm::support::little); - BinaryStreamReader SR(S); + BinaryStreamReader SR(Contents, llvm::support::little); const uint32_t *CodePtr; error(SR.readObject(CodePtr)); StringRef LinkageName; @@ -934,8 +928,7 @@ ListScope S(W, "FunctionLineTable"); W.printString("LinkageName", Name); - BinaryByteStream LineTableInfo(FunctionLineTables[Name], support::little); - BinaryStreamReader Reader(LineTableInfo); + BinaryStreamReader Reader(FunctionLineTables[Name], support::little); ModuleDebugLineFragmentRef LineInfo; error(LineInfo.initialize(Reader)); @@ -985,9 +978,8 @@ CVSymbolDumper CVSD(W, TypeDB, std::move(CODD), opts::CodeViewSubsectionBytes); - BinaryByteStream Stream(BinaryData, llvm::support::little); CVSymbolArray Symbols; - BinaryStreamReader Reader(Stream); + BinaryStreamReader Reader(BinaryData, llvm::support::little); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { consumeError(std::move(EC)); W.flush(); @@ -1002,8 +994,7 @@ } void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { - BinaryByteStream S(Subsection, llvm::support::little); - BinaryStreamReader SR(S); + BinaryStreamReader SR(Subsection, llvm::support::little); ModuleDebugFileChecksumFragmentRef Checksums; error(Checksums.initialize(SR)); @@ -1021,8 +1012,7 @@ } void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { - BinaryByteStream S(Subsection, llvm::support::little); - BinaryStreamReader SR(S); + BinaryStreamReader SR(Subsection, llvm::support::little); ModuleDebugInlineeLineFragmentRef Lines; error(Lines.initialize(SR)); @@ -1072,11 +1062,9 @@ error(consume(Data, Magic)); if (Magic != 4) error(object_error::parse_failed); - ArrayRef Bytes(reinterpret_cast(Data.data()), - Data.size()); - BinaryByteStream Stream(Bytes, llvm::support::little); + CVTypeArray Types; - BinaryStreamReader Reader(Stream); + BinaryStreamReader Reader(Data, llvm::support::little); if (auto EC = Reader.readArray(Types, Reader.getLength())) { consumeError(std::move(EC)); W.flush();