BitstreamReader *BitStream;
size_t NextChar;
+ // The size of the bicode. 0 if we don't know it yet.
+ size_t Size;
+
/// 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 efficiency. We use word_t in
BitStream = R;
NextChar = 0;
- CurWord = 0;
+ Size = 0;
BitsInCurWord = 0;
CurCodeSize = 2;
}
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(
}
bool AtEndOfStream() {
- return BitsInCurWord == 0 && isEndPos(NextChar);
+ if (BitsInCurWord != 0)
+ return false;
+ if (Size == NextChar)
+ return true;
+ fillCurWord();
+ return BitsInCurWord == 0;
}
/// Return the number of bits used to encode an abbrev #.
// Move the cursor to the right word.
NextChar = ByteNo;
BitsInCurWord = 0;
- CurWord = 0;
// Skip over any bits that are already consumed.
if (WordBitNo) {
}
}
+ 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));
+
+ // 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 &&
// 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);
+
BitsInCurWord -= NumBits;
return R;
}
- // If we run out of data, stop at the end of the stream.
- if (isEndPos(NextChar)) {
- CurWord = 0;
- BitsInCurWord = 0;
- return 0;
- }
+ uint32_t R = BitsInCurWord ? uint32_t(CurWord) : 0;
+ unsigned BitsLeft = NumBits - BitsInCurWord;
- uint32_t R = uint32_t(CurWord);
+ fillCurWord();
- // Read the next word from the stream.
- uint8_t Array[sizeof(word_t)] = {0};
-
- BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar);
-
- // 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));
+ // If we run out of data, stop at the end of the stream.
+ if (BitsLeft > BitsInCurWord)
+ return 0;
- CurWord = EndianValue;
+ uint32_t R2 = uint32_t(CurWord) & (~0U >> (sizeof(word_t) * 8 - BitsLeft));
- NextChar += sizeof(word_t);
+ // Use a mask to avoid undefined behavior.
+ CurWord >>= (BitsLeft & 0x1f);
- // 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;
}
}
BitsInCurWord = 0;
- CurWord = 0;
}
public:
/// to return the right result, getExtent must also wait for all the data to
/// arrive; therefore it should not be called on objects which are actually
/// streamed (this would defeat the purpose of streaming). Instead,
-/// isValidAddress and isObjectEnd can be used to test addresses without knowing
-/// the exact size of the stream. Finally, getPointer can be used instead of
-/// readBytes to avoid extra copying.
+/// isValidAddress can be used to test addresses without knowing the exact size
+/// of the stream. Finally, getPointer can be used instead of readBytes to avoid
+/// extra copying.
class MemoryObject {
public:
virtual ~MemoryObject();
/// @param address - address of the byte, in the same space as getBase()
/// @result - true if the address may be read with readByte()
virtual bool isValidAddress(uint64_t address) const = 0;
-
- /// Returns true if the address is one past the end of the object (i.e. if it
- /// is equal to base + extent). May block until (address - base) bytes have
- /// been read
- /// @param address - address of the byte, in the same space as getBase()
- /// @result - true if the address is equal to base + extent
- virtual bool isObjectEnd(uint64_t address) const = 0;
};
}
bool isValidAddress(uint64_t address) const override {
return validAddress(address);
}
- bool isObjectEnd(uint64_t address) const override {
- return objectEnd(address);
- }
private:
const uint8_t* const FirstChar;
bool validAddress(uint64_t address) const {
return static_cast<std::ptrdiff_t>(address) < LastChar - FirstChar;
}
- bool objectEnd(uint64_t address) const {
- return static_cast<std::ptrdiff_t>(address) == LastChar - FirstChar;
- }
RawMemoryObject(const RawMemoryObject&) LLVM_DELETED_FUNCTION;
void operator=(const RawMemoryObject&) LLVM_DELETED_FUNCTION;
return fetchToPos(address);
}
-bool StreamingMemoryObject::isObjectEnd(uint64_t address) const {
- if (ObjectSize) return address == ObjectSize;
- fetchToPos(address);
- return address == ObjectSize && address != 0;
-}
-
uint64_t StreamingMemoryObject::getExtent() const {
if (ObjectSize) return ObjectSize;
size_t pos = BytesRead + kChunkSize;