Chromium Code Reviews| Index: include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
| diff --git a/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h b/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
| index 97e216441939906f33f1c2d1f48585005bf51e8f..d56018d065421ec82f69fae5001aafd7275343e8 100644 |
| --- a/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
| +++ b/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
| @@ -19,13 +19,13 @@ |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" |
| #include "llvm/Support/Endian.h" |
| -#include "llvm/Support/StreamableMemoryObject.h" |
| +#include "llvm/Support/StreamingMemoryObject.h" |
| #include <climits> |
| #include <vector> |
| namespace llvm { |
| - class Deserializer; |
| +class Deserializer; |
| /// NaClBitstreamReader - This class is used to read from a NaCl |
| /// bitcode wire format stream, maintaining information that is global |
| @@ -41,7 +41,7 @@ public: |
| std::vector<NaClBitCodeAbbrev*> Abbrevs; |
| }; |
| private: |
| - std::unique_ptr<StreamableMemoryObject> BitcodeBytes; |
| + std::unique_ptr<MemoryObject> BitcodeBytes; |
| std::vector<BlockInfo> BlockInfoRecords; |
| @@ -59,10 +59,8 @@ public: |
| init(Start, End); |
| } |
| - NaClBitstreamReader(StreamableMemoryObject *Bytes, |
| - size_t MyInitialAddress=0) |
| - : InitialAddress(MyInitialAddress) |
| - { |
| + NaClBitstreamReader(MemoryObject *Bytes, size_t MyInitialAddress=0) |
| + : InitialAddress(MyInitialAddress) { |
| BitcodeBytes.reset(Bytes); |
| } |
| @@ -71,7 +69,7 @@ public: |
| BitcodeBytes.reset(getNonStreamedMemoryObject(Start, End)); |
| } |
| - StreamableMemoryObject &getBitcodeBytes() { return *BitcodeBytes; } |
| + MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } |
| ~NaClBitstreamReader() { |
| // Free the BlockInfoRecords. |
| @@ -124,7 +122,7 @@ public: |
| } |
| }; |
| - |
| + |
| /// NaClBitstreamEntry - When advancing through a bitstream cursor, |
| /// each advance can discover a few different kinds of entries: |
| /// Error - Malformed bitcode was found. |
| @@ -140,7 +138,7 @@ struct NaClBitstreamEntry { |
| SubBlock, |
| Record |
| } Kind; |
| - |
| + |
| unsigned ID; |
| static NaClBitstreamEntry getError() { |
| @@ -213,6 +211,9 @@ class NaClBitstreamCursor { |
| NaClBitstreamReader *BitStream; |
| size_t NextChar; |
| + // The size of the bitcode. 0 if we don't know it yet. |
| + size_t Size; |
| + |
| /// CurWord/word_t - This is the current data we have pulled from the stream |
| /// but have not returned to the client. This is specifically and |
| /// intentionally defined to follow the word size of the host machine for |
| @@ -235,7 +236,7 @@ class NaClBitstreamCursor { |
| struct Block { |
| NaClBitcodeSelectorAbbrev PrevCodeSize; |
| std::vector<NaClBitCodeAbbrev*> PrevAbbrevs; |
| - explicit Block() : PrevCodeSize() {} |
| + Block() : PrevCodeSize() {} |
| explicit Block(const NaClBitcodeSelectorAbbrev& PCS) |
| : PrevCodeSize(PCS) {} |
| }; |
| @@ -247,7 +248,6 @@ class NaClBitstreamCursor { |
| NaClBitstreamCursor &operator=(const NaClBitstreamCursor &) LLVM_DELETED_FUNCTION; |
| public: |
| - |
| NaClBitstreamCursor() { |
| init(nullptr); |
| } |
| @@ -258,7 +258,7 @@ public: |
| freeState(); |
| BitStream = R; |
| NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); |
| - CurWord = 0; |
| + Size = 0; |
| BitsInCurWord = 0; |
| } |
| @@ -268,10 +268,6 @@ public: |
| void freeState(); |
| - bool isEndPos(size_t pos) { |
| - return BitStream->getBitcodeBytes().isObjectEnd(static_cast<uint64_t>(pos)); |
| - } |
| - |
| bool canSkipToPos(size_t pos) const { |
| // pos can be skipped to if it is a valid address or one byte past the end. |
| return pos == 0 || BitStream->getBitcodeBytes().isValidAddress( |
| @@ -279,7 +275,12 @@ public: |
| } |
| bool AtEndOfStream() { |
| - return BitsInCurWord == 0 && isEndPos(NextChar); |
| + if (BitsInCurWord != 0) |
| + return false; |
| + if (Size != 0 && Size == NextChar) |
| + return true; |
| + fillCurWord(); |
| + return BitsInCurWord == 0; |
| } |
| /// getAbbrevIDWidth - Return the number of bits used to encode an abbrev #. |
| @@ -308,7 +309,7 @@ public: |
| /// returned just like normal records. |
| AF_DontAutoprocessAbbrevs = 2 |
| }; |
| - |
| + |
| /// advance - Advance the current bitstream, returning the next entry in the |
| /// stream. Use the given abbreviation listener (if provided). |
| NaClBitstreamEntry advance(unsigned Flags, NaClAbbrevListener *Listener) { |
| @@ -320,10 +321,10 @@ public: |
| return NaClBitstreamEntry::getError(); |
| return NaClBitstreamEntry::getEndBlock(); |
| } |
| - |
| + |
| if (Code == naclbitc::ENTER_SUBBLOCK) |
| return NaClBitstreamEntry::getSubBlock(ReadSubBlockID()); |
| - |
| + |
| if (Code == naclbitc::DEFINE_ABBREV && |
| !(Flags & AF_DontAutoprocessAbbrevs)) { |
| // We read and accumulate abbrev's, the client can't do anything with |
| @@ -344,7 +345,7 @@ public: |
| NaClBitstreamEntry Entry = advance(Flags, 0); |
| if (Entry.Kind != NaClBitstreamEntry::SubBlock) |
| return Entry; |
| - |
| + |
| // If we found a sub-block, just skip over it and check the next entry. |
| if (SkipBlock()) |
| return NaClBitstreamEntry::getError(); |
| @@ -360,7 +361,6 @@ public: |
| // Move the cursor to the right word. |
| NextChar = ByteNo; |
| BitsInCurWord = 0; |
| - CurWord = 0; |
| // Skip over any bits that are already consumed. |
| if (WordBitNo) { |
| @@ -371,55 +371,65 @@ public: |
| } |
| } |
| + void fillCurWord() { |
| + assert(Size == 0 || NextChar < (unsigned)Size); |
| + |
| + // Read the next word from the stream. |
| + uint8_t Array[sizeof(word_t)] = {0}; |
| + |
| + uint64_t BytesRead = |
| + BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar); |
| + |
| + // If we run out of data, stop at the end of the stream. |
| + if (BytesRead == 0) { |
| + Size = NextChar; |
| + return; |
| + } |
| + assert(BytesRead == sizeof(Array)); |
|
Karl
2015/02/20 17:07:02
Should this be an assert (i.e. has the length been
jvoung (off chromium)
2015/02/20 17:38:21
Hmm looks like the assert is gone in the new Bitst
|
| + |
| + // Handle big-endian byte-swapping if necessary. |
| + support::detail::packed_endian_specific_integral< |
| + word_t, support::little, support::unaligned> EndianValue; |
| + memcpy(&EndianValue, Array, sizeof(Array)); |
| + |
| + CurWord = EndianValue; |
| + NextChar += sizeof(word_t); |
| + BitsInCurWord = sizeof(word_t) * 8; |
| + } |
| + |
| uint32_t Read(unsigned NumBits) { |
| assert(NumBits && NumBits <= 32 && |
| "Cannot return zero or more than 32 bits!"); |
| - |
| + |
| // If the field is fully contained by CurWord, return it quickly. |
| if (BitsInCurWord >= NumBits) { |
| uint32_t R = uint32_t(CurWord) & (~0U >> (32-NumBits)); |
| - CurWord >>= NumBits; |
| + |
| + // Use a mask to avoid undefined behavior. |
| + CurWord >>= (NumBits & 0x1f); |
|
Karl
2015/02/20 17:07:02
Is the mask necessary? Doesn't the assert above gu
jvoung (off chromium)
2015/02/20 17:38:21
Yes, in case asserts are turned off.
Otherwise it
|
| + |
| BitsInCurWord -= NumBits; |
| return R; |
| } |
| + uint32_t R = BitsInCurWord ? uint32_t(CurWord) : 0; |
| + unsigned BitsLeft = NumBits - BitsInCurWord; |
| + |
| + fillCurWord(); |
| + |
| // If we run out of data, stop at the end of the stream. |
| - if (isEndPos(NextChar)) { |
| - CurWord = 0; |
| - BitsInCurWord = 0; |
| + if (BitsLeft > BitsInCurWord) |
| return 0; |
| - } |
| - uint32_t R = uint32_t(CurWord); |
| + uint32_t R2 = uint32_t(CurWord) & (~0U >> (sizeof(word_t) * 8 - BitsLeft)); |
| - // Read the next word from the stream. |
| - uint8_t Array[sizeof(word_t)] = {0}; |
| - |
| - BitStream->getBitcodeBytes().readBytes(NextChar, sizeof(Array), Array); |
| - |
| - // Handle big-endian byte-swapping if necessary. |
| - support::detail::packed_endian_specific_integral |
| - <word_t, support::little, support::unaligned> EndianValue; |
| - memcpy(&EndianValue, Array, sizeof(Array)); |
| - |
| - CurWord = EndianValue; |
| + // Use a mask to avoid undefined behavior. |
| + CurWord >>= (BitsLeft & 0x1f); |
| - NextChar += sizeof(word_t); |
| - |
| - // Extract NumBits-BitsInCurWord from what we just read. |
| - unsigned BitsLeft = NumBits-BitsInCurWord; |
| + BitsInCurWord -= BitsLeft; |
| - // Be careful here, BitsLeft is in the range [1..32]/[1..64] inclusive. |
| - R |= uint32_t((CurWord & (word_t(~0ULL) >> (sizeof(word_t)*8-BitsLeft))) |
| - << BitsInCurWord); |
| + R |= uint32_t(R2 << (NumBits - BitsLeft)); |
| - // BitsLeft bits have just been used up from CurWord. BitsLeft is in the |
| - // range [1..32]/[1..64] so be careful how we shift. |
| - if (BitsLeft != sizeof(word_t)*8) |
| - CurWord >>= BitsLeft; |
| - else |
| - CurWord = 0; |
| - BitsInCurWord = sizeof(word_t)*8-BitsLeft; |
| return R; |
| } |
| @@ -478,9 +488,8 @@ private: |
| BitsInCurWord = 32; |
| return; |
| } |
| - |
| + |
| BitsInCurWord = 0; |
| - CurWord = 0; |
| } |
| public: |
| @@ -522,7 +531,7 @@ public: |
| /// EnterSubBlock - Having read the ENTER_SUBBLOCK abbrevid, enter |
| /// the block, and return true if the block has an error. |
| bool EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = 0); |
| - |
| + |
| bool ReadBlockEnd() { |
| if (BlockScope.empty()) return true; |