[PDB] General improvements to Stream library.
This adds various new functionality and cleanup surrounding the
use of the Stream library. Major changes include:
* Renaming of all classes for more consistency / meaningfulness
* Addition of some new methods for reading multiple values at once.
* Full suite of unit tests for reader / writer functionality.
* Full set of doxygen comments for all classes.
* Streams now store their own endianness.
* Fixed some bugs in a few of the classes that were discovered
by the unit tests.
llvm-svn: 296215
diff --git a/llvm/lib/DebugInfo/MSF/BinaryStreamReader.cpp b/llvm/lib/DebugInfo/MSF/BinaryStreamReader.cpp
index 567e6b1..ba5fd21 100644
--- a/llvm/lib/DebugInfo/MSF/BinaryStreamReader.cpp
+++ b/llvm/lib/DebugInfo/MSF/BinaryStreamReader.cpp
@@ -1,4 +1,4 @@
-//===- StreamReader.cpp - Reads bytes and objects from a stream -----------===//
+//===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,53 +10,79 @@
#include "llvm/DebugInfo/MSF/BinaryStreamReader.h"
#include "llvm/DebugInfo/MSF/BinaryStreamRef.h"
-#include "llvm/DebugInfo/MSF/MSFError.h"
using namespace llvm;
-using namespace llvm::msf;
-StreamReader::StreamReader(ReadableStreamRef S) : Stream(S), Offset(0) {}
+BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S)
+ : Stream(S), Offset(0) {}
-Error StreamReader::readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer) {
+Error BinaryStreamReader::readLongestContiguousChunk(
+ ArrayRef<uint8_t> &Buffer) {
if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer))
return EC;
Offset += Buffer.size();
return Error::success();
}
-Error StreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
+Error BinaryStreamReader::readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size) {
if (auto EC = Stream.readBytes(Offset, Size, Buffer))
return EC;
Offset += Size;
return Error::success();
}
-Error StreamReader::readZeroString(StringRef &Dest) {
+Error BinaryStreamReader::readInteger(uint64_t &Dest, uint32_t ByteSize) {
+ assert(ByteSize == 1 || ByteSize == 2 || ByteSize == 4 || ByteSize == 8);
+ ArrayRef<uint8_t> Bytes;
+
+ if (auto EC = readBytes(Bytes, ByteSize))
+ return EC;
+ switch (ByteSize) {
+ case 1:
+ Dest = Bytes[0];
+ return Error::success();
+ case 2:
+ Dest = llvm::support::endian::read16(Bytes.data(), Stream.getEndian());
+ return Error::success();
+ case 4:
+ Dest = llvm::support::endian::read32(Bytes.data(), Stream.getEndian());
+ return Error::success();
+ case 8:
+ Dest = llvm::support::endian::read64(Bytes.data(), Stream.getEndian());
+ return Error::success();
+ }
+ llvm_unreachable("Unreachable!");
+ return Error::success();
+}
+
+Error BinaryStreamReader::readCString(StringRef &Dest) {
+ // TODO: This could be made more efficient by using readLongestContiguousChunk
+ // and searching for null terminators in the resulting buffer.
+
uint32_t Length = 0;
// First compute the length of the string by reading 1 byte at a time.
uint32_t OriginalOffset = getOffset();
const char *C;
- do {
+ while (true) {
if (auto EC = readObject(C))
return EC;
- if (*C != '\0')
- ++Length;
- } while (*C != '\0');
+ if (*C == '\0')
+ break;
+ ++Length;
+ }
// Now go back and request a reference for that many bytes.
uint32_t NewOffset = getOffset();
setOffset(OriginalOffset);
- ArrayRef<uint8_t> Data;
- if (auto EC = readBytes(Data, Length))
+ if (auto EC = readFixedString(Dest, Length))
return EC;
- Dest = StringRef(reinterpret_cast<const char *>(Data.begin()), Data.size());
// Now set the offset back to where it was after we calculated the length.
setOffset(NewOffset);
return Error::success();
}
-Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
+Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) {
ArrayRef<uint8_t> Bytes;
if (auto EC = readBytes(Bytes, Length))
return EC;
@@ -64,26 +90,26 @@
return Error::success();
}
-Error StreamReader::readStreamRef(ReadableStreamRef &Ref) {
+Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) {
return readStreamRef(Ref, bytesRemaining());
}
-Error StreamReader::readStreamRef(ReadableStreamRef &Ref, uint32_t Length) {
+Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) {
if (bytesRemaining() < Length)
- return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ return errorCodeToError(make_error_code(std::errc::no_buffer_space));
Ref = Stream.slice(Offset, Length);
Offset += Length;
return Error::success();
}
-Error StreamReader::skip(uint32_t Amount) {
+Error BinaryStreamReader::skip(uint32_t Amount) {
if (Amount > bytesRemaining())
- return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ return errorCodeToError(make_error_code(std::errc::no_buffer_space));
Offset += Amount;
return Error::success();
}
-uint8_t StreamReader::peek() const {
+uint8_t BinaryStreamReader::peek() const {
ArrayRef<uint8_t> Buffer;
auto EC = Stream.readBytes(Offset, 1, Buffer);
assert(!EC && "Cannot peek an empty buffer!");
diff --git a/llvm/lib/DebugInfo/MSF/BinaryStreamWriter.cpp b/llvm/lib/DebugInfo/MSF/BinaryStreamWriter.cpp
index 54415b9..08e4aef 100644
--- a/llvm/lib/DebugInfo/MSF/BinaryStreamWriter.cpp
+++ b/llvm/lib/DebugInfo/MSF/BinaryStreamWriter.cpp
@@ -1,4 +1,4 @@
-//===- StreamWrite.cpp - Writes bytes and objects to a stream -------------===//
+//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,21 +11,42 @@
#include "llvm/DebugInfo/MSF/BinaryStreamReader.h"
#include "llvm/DebugInfo/MSF/BinaryStreamRef.h"
-#include "llvm/DebugInfo/MSF/MSFError.h"
using namespace llvm;
-using namespace llvm::msf;
-StreamWriter::StreamWriter(WritableStreamRef S) : Stream(S), Offset(0) {}
+BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef S)
+ : Stream(S), Offset(0) {}
-Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
+Error BinaryStreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) {
if (auto EC = Stream.writeBytes(Offset, Buffer))
return EC;
Offset += Buffer.size();
return Error::success();
}
-Error StreamWriter::writeZeroString(StringRef Str) {
+Error BinaryStreamWriter::writeInteger(uint64_t Value, uint32_t ByteSize) {
+ assert(ByteSize == 1 || ByteSize == 2 || ByteSize == 4 || ByteSize == 8);
+ uint8_t Bytes[8];
+ MutableArrayRef<uint8_t> Buffer(Bytes);
+ Buffer = Buffer.take_front(ByteSize);
+ switch (ByteSize) {
+ case 1:
+ Buffer[0] = static_cast<uint8_t>(Value);
+ break;
+ case 2:
+ llvm::support::endian::write16(Buffer.data(), Value, Stream.getEndian());
+ break;
+ case 4:
+ llvm::support::endian::write32(Buffer.data(), Value, Stream.getEndian());
+ break;
+ case 8:
+ llvm::support::endian::write64(Buffer.data(), Value, Stream.getEndian());
+ break;
+ }
+ return writeBytes(Buffer);
+}
+
+Error BinaryStreamWriter::writeCString(StringRef Str) {
if (auto EC = writeFixedString(Str))
return EC;
if (auto EC = writeObject('\0'))
@@ -34,31 +55,21 @@
return Error::success();
}
-Error StreamWriter::writeFixedString(StringRef Str) {
- ArrayRef<uint8_t> Bytes(Str.bytes_begin(), Str.bytes_end());
- if (auto EC = Stream.writeBytes(Offset, Bytes))
- return EC;
-
- Offset += Str.size();
- return Error::success();
+Error BinaryStreamWriter::writeFixedString(StringRef Str) {
+ return writeBytes(ArrayRef<uint8_t>(Str.bytes_begin(), Str.bytes_end()));
}
-Error StreamWriter::writeStreamRef(ReadableStreamRef Ref) {
- if (auto EC = writeStreamRef(Ref, Ref.getLength()))
- return EC;
- // Don't increment Offset here, it is done by the overloaded call to
- // writeStreamRef.
- return Error::success();
+Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) {
+ return writeStreamRef(Ref, Ref.getLength());
}
-Error StreamWriter::writeStreamRef(ReadableStreamRef Ref, uint32_t Length) {
- Ref = Ref.slice(0, Length);
-
- StreamReader SrcReader(Ref);
+Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) {
+ BinaryStreamReader SrcReader(Ref.slice(0, Length));
// This is a bit tricky. If we just call readBytes, we are requiring that it
- // return us the entire stream as a contiguous buffer. For large streams this
- // will allocate a huge amount of space from the pool. Instead, iterate over
- // each contiguous chunk until we've consumed the entire stream.
+ // return us the entire stream as a contiguous buffer. There is no guarantee
+ // this can be satisfied by returning a reference straight from the buffer, as
+ // an implementation may not store all data in a single contiguous buffer. So
+ // we iterate over each contiguous chunk, writing each one in succession.
while (SrcReader.bytesRemaining() > 0) {
ArrayRef<uint8_t> Chunk;
if (auto EC = SrcReader.readLongestContiguousChunk(Chunk))
diff --git a/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp b/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp
index e52c88a..c9ba25c 100644
--- a/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp
+++ b/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp
@@ -47,22 +47,20 @@
MappedBlockStream::MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks,
const MSFStreamLayout &Layout,
- const ReadableStream &MsfData)
+ BinaryStreamRef MsfData)
: BlockSize(BlockSize), NumBlocks(NumBlocks), StreamLayout(Layout),
MsfData(MsfData) {}
std::unique_ptr<MappedBlockStream>
MappedBlockStream::createStream(uint32_t BlockSize, uint32_t NumBlocks,
const MSFStreamLayout &Layout,
- const ReadableStream &MsfData) {
+ BinaryStreamRef MsfData) {
return llvm::make_unique<MappedBlockStreamImpl<MappedBlockStream>>(
BlockSize, NumBlocks, Layout, MsfData);
}
-std::unique_ptr<MappedBlockStream>
-MappedBlockStream::createIndexedStream(const MSFLayout &Layout,
- const ReadableStream &MsfData,
- uint32_t StreamIndex) {
+std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream(
+ const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex) {
assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index");
MSFStreamLayout SL;
SL.Blocks = Layout.StreamMap[StreamIndex];
@@ -73,7 +71,7 @@
std::unique_ptr<MappedBlockStream>
MappedBlockStream::createDirectoryStream(const MSFLayout &Layout,
- const ReadableStream &MsfData) {
+ BinaryStreamRef MsfData) {
MSFStreamLayout SL;
SL.Blocks = Layout.DirectoryBlocks;
SL.Length = Layout.SB->NumDirectoryBytes;
@@ -82,14 +80,14 @@
std::unique_ptr<MappedBlockStream>
MappedBlockStream::createFpmStream(const MSFLayout &Layout,
- const ReadableStream &MsfData) {
+ BinaryStreamRef MsfData) {
MSFStreamLayout SL;
initializeFpmStreamLayout(Layout, SL);
return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData);
}
Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
- ArrayRef<uint8_t> &Buffer) const {
+ ArrayRef<uint8_t> &Buffer) {
// Make sure we aren't trying to read beyond the end of the stream.
if (Size > StreamLayout.Length)
return make_error<MSFError>(msf_error_code::insufficient_buffer);
@@ -168,8 +166,8 @@
return Error::success();
}
-Error MappedBlockStream::readLongestContiguousChunk(
- uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
+Error MappedBlockStream::readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) {
// Make sure we aren't trying to read beyond the end of the stream.
if (Offset >= StreamLayout.Length)
return make_error<MSFError>(msf_error_code::insufficient_buffer);
@@ -197,10 +195,10 @@
return Error::success();
}
-uint32_t MappedBlockStream::getLength() const { return StreamLayout.Length; }
+uint32_t MappedBlockStream::getLength() { return StreamLayout.Length; }
bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size,
- ArrayRef<uint8_t> &Buffer) const {
+ ArrayRef<uint8_t> &Buffer) {
if (Size == 0) {
Buffer = ArrayRef<uint8_t>();
return true;
@@ -241,7 +239,7 @@
}
Error MappedBlockStream::readBytes(uint32_t Offset,
- MutableArrayRef<uint8_t> Buffer) const {
+ MutableArrayRef<uint8_t> Buffer) {
uint32_t BlockNum = Offset / BlockSize;
uint32_t OffsetInBlock = Offset % BlockSize;
@@ -319,21 +317,21 @@
WritableMappedBlockStream::WritableMappedBlockStream(
uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout,
- const WritableStream &MsfData)
+ WritableBinaryStreamRef MsfData)
: ReadInterface(BlockSize, NumBlocks, Layout, MsfData),
WriteInterface(MsfData) {}
std::unique_ptr<WritableMappedBlockStream>
WritableMappedBlockStream::createStream(uint32_t BlockSize, uint32_t NumBlocks,
const MSFStreamLayout &Layout,
- const WritableStream &MsfData) {
+ WritableBinaryStreamRef MsfData) {
return llvm::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>(
BlockSize, NumBlocks, Layout, MsfData);
}
std::unique_ptr<WritableMappedBlockStream>
WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout,
- const WritableStream &MsfData,
+ WritableBinaryStreamRef MsfData,
uint32_t StreamIndex) {
assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index");
MSFStreamLayout SL;
@@ -344,7 +342,7 @@
std::unique_ptr<WritableMappedBlockStream>
WritableMappedBlockStream::createDirectoryStream(
- const MSFLayout &Layout, const WritableStream &MsfData) {
+ const MSFLayout &Layout, WritableBinaryStreamRef MsfData) {
MSFStreamLayout SL;
SL.Blocks = Layout.DirectoryBlocks;
SL.Length = Layout.SB->NumDirectoryBytes;
@@ -353,28 +351,28 @@
std::unique_ptr<WritableMappedBlockStream>
WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout,
- const WritableStream &MsfData) {
+ WritableBinaryStreamRef MsfData) {
MSFStreamLayout SL;
initializeFpmStreamLayout(Layout, SL);
return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData);
}
Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,
- ArrayRef<uint8_t> &Buffer) const {
+ ArrayRef<uint8_t> &Buffer) {
return ReadInterface.readBytes(Offset, Size, Buffer);
}
Error WritableMappedBlockStream::readLongestContiguousChunk(
- uint32_t Offset, ArrayRef<uint8_t> &Buffer) const {
+ uint32_t Offset, ArrayRef<uint8_t> &Buffer) {
return ReadInterface.readLongestContiguousChunk(Offset, Buffer);
}
-uint32_t WritableMappedBlockStream::getLength() const {
+uint32_t WritableMappedBlockStream::getLength() {
return ReadInterface.getLength();
}
Error WritableMappedBlockStream::writeBytes(uint32_t Offset,
- ArrayRef<uint8_t> Buffer) const {
+ ArrayRef<uint8_t> Buffer) {
// Make sure we aren't trying to write beyond the end of the stream.
if (Buffer.size() > getStreamLength())
return make_error<MSFError>(msf_error_code::insufficient_buffer);
@@ -410,6 +408,4 @@
return Error::success();
}
-Error WritableMappedBlockStream::commit() const {
- return WriteInterface.commit();
-}
+Error WritableMappedBlockStream::commit() { return WriteInterface.commit(); }