Index: include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
diff --git a/include/llvm/Bitcode/BitstreamReader.h b/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
similarity index 57% |
copy from include/llvm/Bitcode/BitstreamReader.h |
copy to include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
index ecf82352779e2037c5574dabf94de83a1bba2b7f..dd53fd041db0a648068125fc3bd875f87a333835 100644 |
--- a/include/llvm/Bitcode/BitstreamReader.h |
+++ b/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h |
@@ -1,4 +1,5 @@ |
-//===- BitstreamReader.h - Low-level bitstream reader interface -*- C++ -*-===// |
+//===- NaClBitstreamReader.h -----------------------------------*- C++ -*-===// |
+// Low-level bitstream reader interface |
// |
// The LLVM Compiler Infrastructure |
// |
@@ -12,69 +13,55 @@ |
// |
//===----------------------------------------------------------------------===// |
-#ifndef LLVM_BITCODE_BITSTREAMREADER_H |
-#define LLVM_BITCODE_BITSTREAMREADER_H |
+#ifndef LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H |
+#define LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H |
-#include "llvm/Bitcode/BitCodes.h" |
+#include "llvm/ADT/SmallVector.h" |
+#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" |
#include "llvm/Support/Endian.h" |
#include "llvm/Support/StreamingMemoryObject.h" |
#include <climits> |
-#include <string> |
#include <vector> |
namespace llvm { |
class Deserializer; |
-/// This class is used to read from an LLVM bitcode stream, maintaining |
-/// information that is global to decoding the entire file. While a file is |
-/// being read, multiple cursors can be independently advanced or skipped around |
-/// within the file. These are represented by the BitstreamCursor class. |
-class BitstreamReader { |
+/// This class is used to read from a NaCl bitcode wire format stream, |
+/// maintaining information that is global to decoding the entire file. |
+/// While a file is being read, multiple cursors can be independently |
+/// advanced or skipped around within the file. These are represented by |
+/// the NaClBitstreamCursor class. |
+class NaClBitstreamReader { |
public: |
/// This contains information emitted to BLOCKINFO_BLOCK blocks. These |
/// describe abbreviations that all blocks of the specified ID inherit. |
struct BlockInfo { |
unsigned BlockID; |
- std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> Abbrevs; |
- std::string Name; |
- |
- std::vector<std::pair<unsigned, std::string> > RecordNames; |
+ std::vector<NaClBitCodeAbbrev*> Abbrevs; |
}; |
private: |
std::unique_ptr<MemoryObject> BitcodeBytes; |
std::vector<BlockInfo> BlockInfoRecords; |
- /// This is set to true if we don't care about the block/record name |
- /// information in the BlockInfo block. Only llvm-bcanalyzer uses this. |
- bool IgnoreBlockInfoNames; |
+ /// \brief Holds the offset of the first byte after the header. |
+ size_t InitialAddress; |
- BitstreamReader(const BitstreamReader&) LLVM_DELETED_FUNCTION; |
- void operator=(const BitstreamReader&) LLVM_DELETED_FUNCTION; |
+ NaClBitstreamReader(const NaClBitstreamReader&) LLVM_DELETED_FUNCTION; |
+ void operator=(const NaClBitstreamReader&) LLVM_DELETED_FUNCTION; |
public: |
- BitstreamReader() : IgnoreBlockInfoNames(true) { |
- } |
+ NaClBitstreamReader() : InitialAddress(0) {} |
- BitstreamReader(const unsigned char *Start, const unsigned char *End) |
- : IgnoreBlockInfoNames(true) { |
+ NaClBitstreamReader(const unsigned char *Start, const unsigned char *End, |
+ size_t MyInitialAddress=0) { |
+ InitialAddress = MyInitialAddress; |
init(Start, End); |
} |
- BitstreamReader(MemoryObject *bytes) : IgnoreBlockInfoNames(true) { |
- BitcodeBytes.reset(bytes); |
- } |
- |
- BitstreamReader(BitstreamReader &&Other) { |
- *this = std::move(Other); |
- } |
- |
- BitstreamReader &operator=(BitstreamReader &&Other) { |
- BitcodeBytes = std::move(Other.BitcodeBytes); |
- // Explicitly swap block info, so that nothing gets destroyed twice. |
- std::swap(BlockInfoRecords, Other.BlockInfoRecords); |
- IgnoreBlockInfoNames = Other.IgnoreBlockInfoNames; |
- return *this; |
+ NaClBitstreamReader(MemoryObject *Bytes, size_t MyInitialAddress=0) |
+ : InitialAddress(MyInitialAddress) { |
+ BitcodeBytes.reset(Bytes); |
} |
void init(const unsigned char *Start, const unsigned char *End) { |
@@ -84,9 +71,22 @@ public: |
MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } |
- /// This is called by clients that want block/record name information. |
- void CollectBlockInfoNames() { IgnoreBlockInfoNames = false; } |
- bool isIgnoringBlockInfoNames() { return IgnoreBlockInfoNames; } |
+ ~NaClBitstreamReader() { |
+ // Free the BlockInfoRecords. |
+ while (!BlockInfoRecords.empty()) { |
+ BlockInfo &Info = BlockInfoRecords.back(); |
+ // Free blockinfo abbrev info. |
+ for (unsigned i = 0, e = static_cast<unsigned>(Info.Abbrevs.size()); |
+ i != e; ++i) |
+ Info.Abbrevs[i]->dropRef(); |
+ BlockInfoRecords.pop_back(); |
+ } |
+ } |
+ |
+ /// \brief Returns the initial address (after the header) of the input stream. |
+ size_t getInitialAddress() const { |
+ return InitialAddress; |
+ } |
//===--------------------------------------------------------------------===// |
// Block Manipulation |
@@ -120,20 +120,11 @@ public: |
BlockInfoRecords.back().BlockID = BlockID; |
return BlockInfoRecords.back(); |
} |
- |
- /// Takes block info from the other bitstream reader. |
- /// |
- /// This is a "take" operation because BlockInfo records are non-trivial, and |
- /// indeed rather expensive. |
- void takeBlockInfo(BitstreamReader &&Other) { |
- assert(!hasBlockInfoRecords()); |
- BlockInfoRecords = std::move(Other.BlockInfoRecords); |
- } |
}; |
/// When advancing through a bitstream cursor, each advance can discover a few |
/// different kinds of entries: |
-struct BitstreamEntry { |
+struct NaClBitstreamEntry { |
enum { |
Error, // Malformed bitcode was found. |
EndBlock, // We've reached the end of the current block, (or the end of the |
@@ -144,32 +135,77 @@ struct BitstreamEntry { |
unsigned ID; |
- static BitstreamEntry getError() { |
- BitstreamEntry E; E.Kind = Error; return E; |
+ static NaClBitstreamEntry getError() { |
+ NaClBitstreamEntry E; E.Kind = Error; return E; |
} |
- static BitstreamEntry getEndBlock() { |
- BitstreamEntry E; E.Kind = EndBlock; return E; |
+ static NaClBitstreamEntry getEndBlock() { |
+ NaClBitstreamEntry E; E.Kind = EndBlock; return E; |
} |
- static BitstreamEntry getSubBlock(unsigned ID) { |
- BitstreamEntry E; E.Kind = SubBlock; E.ID = ID; return E; |
+ static NaClBitstreamEntry getSubBlock(unsigned ID) { |
+ NaClBitstreamEntry E; E.Kind = SubBlock; E.ID = ID; return E; |
} |
- static BitstreamEntry getRecord(unsigned AbbrevID) { |
- BitstreamEntry E; E.Kind = Record; E.ID = AbbrevID; return E; |
+ static NaClBitstreamEntry getRecord(unsigned AbbrevID) { |
+ NaClBitstreamEntry E; E.Kind = Record; E.ID = AbbrevID; return E; |
} |
}; |
+/// Models default view of a bitcode record. |
+typedef SmallVector<uint64_t, 8> NaClBitcodeRecordVector; |
+ |
+/// Class NaClAbbrevListener is used to allow instances of class |
+/// NaClBitcodeParser to listen to record details when processing |
+/// abbreviations. The major reason for using a listener is that the |
+/// NaCl bitcode reader would require a major rewrite (including the |
+/// introduction of more overhead) if we were to lift abbreviations up |
+/// to the bitcode reader. That is, not only would we have to lift the |
+/// block processing up into the readers (i.e. many blocks in |
+/// NaClBitcodeReader and NaClBitcodeParser), but add many new API's |
+/// to allow the readers to update internals of the bit stream reader |
+/// appropriately. |
+class NaClAbbrevListener { |
+ NaClAbbrevListener(const NaClAbbrevListener&) LLVM_DELETED_FUNCTION; |
+ void operator=(const NaClAbbrevListener&) LLVM_DELETED_FUNCTION; |
+public: |
+ NaClAbbrevListener() {} |
+ virtual ~NaClAbbrevListener() {} |
+ |
+ /// Called to process the read abbreviation. |
+ virtual void ProcessAbbreviation(NaClBitCodeAbbrev *Abbrev, |
+ bool IsLocal) = 0; |
+ |
+ /// Called after entering block. NumWords is the number of words |
+ /// in the block. |
+ virtual void BeginBlockInfoBlock(unsigned NumWords) = 0; |
+ |
+ /// Called if a naclbitc::BLOCKINFO_CODE_SETBID record is found in |
+ /// NaClBitstreamCursor::ReadBlockInfoBlock. |
+ virtual void SetBID() = 0; |
+ |
+ /// Called just before an EndBlock record is processed by |
+ /// NaClBitstreamCursor::ReadBlockInfoBlock |
+ virtual void EndBlockInfoBlock() = 0; |
+ |
+ /// The values of the bitcode record associated with the called |
+ /// virtual function. |
+ NaClBitcodeRecordVector Values; |
+ |
+ /// Start bit for current record being processed in |
+ /// NaClBitstreamCursor::ReadBlockInfoBlock. |
+ uint64_t StartBit; |
+}; |
+ |
/// This represents a position within a bitcode file. There may be multiple |
-/// independent cursors reading within one bitstream, each maintaining their own |
-/// local state. |
+/// independent cursors reading within one bitstream, each maintaining their |
+/// own local state. |
/// |
-/// Unlike iterators, BitstreamCursors are heavy-weight objects that should not |
-/// be passed by value. |
-class BitstreamCursor { |
+/// Unlike iterators, NaClBitstreamCursors are heavy-weight objects |
+/// that should not be passed by value. |
+class NaClBitstreamCursor { |
friend class Deserializer; |
- BitstreamReader *BitStream; |
+ NaClBitstreamReader *BitStream; |
size_t NextChar; |
- // The size of the bicode. 0 if we don't know it yet. |
+ // The size of the bitcode. 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 |
@@ -180,40 +216,46 @@ class BitstreamCursor { |
typedef size_t word_t; |
word_t CurWord; |
- /// This is the number of bits in CurWord that are valid. This is always from |
- /// [0...bits_of(size_t)-1] inclusive. |
+ /// This is the number of bits in CurWord that are valid. This |
+ /// is always from [0...bits_of(word_t)-1] inclusive. |
unsigned BitsInCurWord; |
- // This is the declared size of code values used for the current block, in |
- // bits. |
- unsigned CurCodeSize; |
+ /// This is the declared size of code values used for the current |
+ /// block, in bits. |
+ NaClBitcodeSelectorAbbrev CurCodeSize; |
- /// Abbrevs installed at in this block. |
- std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> CurAbbrevs; |
+ /// Abbrevs installed in this block. |
+ std::vector<NaClBitCodeAbbrev*> CurAbbrevs; |
struct Block { |
- unsigned PrevCodeSize; |
- std::vector<IntrusiveRefCntPtr<BitCodeAbbrev>> PrevAbbrevs; |
- explicit Block(unsigned PCS) : PrevCodeSize(PCS) {} |
+ NaClBitcodeSelectorAbbrev PrevCodeSize; |
+ std::vector<NaClBitCodeAbbrev*> PrevAbbrevs; |
+ Block() : PrevCodeSize() {} |
+ explicit Block(const NaClBitcodeSelectorAbbrev& PCS) |
+ : PrevCodeSize(PCS) {} |
}; |
/// This tracks the codesize of parent blocks. |
SmallVector<Block, 8> BlockScope; |
+ NaClBitstreamCursor(const NaClBitstreamCursor &) LLVM_DELETED_FUNCTION; |
+ NaClBitstreamCursor &operator=(const NaClBitstreamCursor &) LLVM_DELETED_FUNCTION; |
public: |
- BitstreamCursor() { init(nullptr); } |
+ NaClBitstreamCursor() { init(nullptr); } |
- explicit BitstreamCursor(BitstreamReader &R) { init(&R); } |
+ explicit NaClBitstreamCursor(NaClBitstreamReader &R) { init(&R); } |
- void init(BitstreamReader *R) { |
+ void init(NaClBitstreamReader *R) { |
freeState(); |
- |
BitStream = R; |
- NextChar = 0; |
+ NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); |
Size = 0; |
BitsInCurWord = 0; |
- CurCodeSize = 2; |
+ } |
+ |
+ ~NaClBitstreamCursor() { |
+ freeState(); |
} |
void freeState(); |
@@ -234,17 +276,17 @@ public: |
} |
/// Return the number of bits used to encode an abbrev #. |
- unsigned getAbbrevIDWidth() const { return CurCodeSize; } |
+ unsigned getAbbrevIDWidth() const { return CurCodeSize.NumBits; } |
/// Return the bit # of the bit we are reading. |
uint64_t GetCurrentBitNo() const { |
return NextChar*CHAR_BIT - BitsInCurWord; |
} |
- BitstreamReader *getBitStreamReader() { |
+ NaClBitstreamReader *getBitStreamReader() { |
return BitStream; |
} |
- const BitstreamReader *getBitStreamReader() const { |
+ const NaClBitstreamReader *getBitStreamReader() const { |
return BitStream; |
} |
@@ -259,44 +301,45 @@ public: |
AF_DontAutoprocessAbbrevs = 2 |
}; |
- /// Advance the current bitstream, returning the next entry in the stream. |
- BitstreamEntry advance(unsigned Flags = 0) { |
+ /// Advance the current bitstream, returning the next entry in the stream. |
+ /// Use the given abbreviation listener (if provided). |
+ NaClBitstreamEntry advance(unsigned Flags, NaClAbbrevListener *Listener) { |
while (1) { |
unsigned Code = ReadCode(); |
- if (Code == bitc::END_BLOCK) { |
+ if (Code == naclbitc::END_BLOCK) { |
// Pop the end of the block unless Flags tells us not to. |
if (!(Flags & AF_DontPopBlockAtEnd) && ReadBlockEnd()) |
- return BitstreamEntry::getError(); |
- return BitstreamEntry::getEndBlock(); |
+ return NaClBitstreamEntry::getError(); |
+ return NaClBitstreamEntry::getEndBlock(); |
} |
- if (Code == bitc::ENTER_SUBBLOCK) |
- return BitstreamEntry::getSubBlock(ReadSubBlockID()); |
+ if (Code == naclbitc::ENTER_SUBBLOCK) |
+ return NaClBitstreamEntry::getSubBlock(ReadSubBlockID()); |
- if (Code == bitc::DEFINE_ABBREV && |
+ if (Code == naclbitc::DEFINE_ABBREV && |
!(Flags & AF_DontAutoprocessAbbrevs)) { |
// We read and accumulate abbrev's, the client can't do anything with |
// them anyway. |
- ReadAbbrevRecord(); |
+ ReadAbbrevRecord(true, Listener); |
continue; |
} |
- return BitstreamEntry::getRecord(Code); |
+ return NaClBitstreamEntry::getRecord(Code); |
} |
} |
/// This is a convenience function for clients that don't expect any |
/// subblocks. This just skips over them automatically. |
- BitstreamEntry advanceSkippingSubblocks(unsigned Flags = 0) { |
+ NaClBitstreamEntry advanceSkippingSubblocks(unsigned Flags = 0) { |
while (1) { |
// If we found a normal entry, return it. |
- BitstreamEntry Entry = advance(Flags); |
- if (Entry.Kind != BitstreamEntry::SubBlock) |
+ 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 BitstreamEntry::getError(); |
+ return NaClBitstreamEntry::getError(); |
} |
} |
@@ -431,16 +474,17 @@ private: |
public: |
unsigned ReadCode() { |
- return Read(CurCodeSize); |
+ return CurCodeSize.IsFixed |
+ ? Read(CurCodeSize.NumBits) |
+ : ReadVBR(CurCodeSize.NumBits); |
} |
- |
// Block header: |
// [ENTER_SUBBLOCK, blockid, newcodelen, <align4bytes>, blocklen] |
/// Having read the ENTER_SUBBLOCK code, read the BlockID for the block. |
unsigned ReadSubBlockID() { |
- return ReadVBR(bitc::BlockIDWidth); |
+ return ReadVBR(naclbitc::BlockIDWidth); |
} |
/// Having read the ENTER_SUBBLOCK abbrevid and a BlockID, skip over the body |
@@ -448,9 +492,9 @@ public: |
bool SkipBlock() { |
// Read and ignore the codelen value. Since we are skipping this block, we |
// don't care what code widths are used inside of it. |
- ReadVBR(bitc::CodeLenWidth); |
+ ReadVBR(naclbitc::CodeLenWidth); |
SkipToFourByteBoundary(); |
- unsigned NumFourBytes = Read(bitc::BlockSizeWidth); |
+ unsigned NumFourBytes = Read(naclbitc::BlockSizeWidth); |
// Check that the block wasn't partially defined, and that the offset isn't |
// bogus. |
@@ -482,7 +526,12 @@ private: |
void popBlockScope() { |
CurCodeSize = BlockScope.back().PrevCodeSize; |
- CurAbbrevs = std::move(BlockScope.back().PrevAbbrevs); |
+ // Delete abbrevs from popped scope. |
+ for (unsigned i = 0, e = static_cast<unsigned>(CurAbbrevs.size()); |
+ i != e; ++i) |
+ CurAbbrevs[i]->dropRef(); |
+ |
+ BlockScope.back().PrevAbbrevs.swap(CurAbbrevs); |
BlockScope.pop_back(); |
} |
@@ -490,27 +539,53 @@ private: |
// Record Processing |
//===--------------------------------------------------------------------===// |
+private: |
+ void skipAbbreviatedField(const NaClBitCodeAbbrevOp &Op); |
+ |
+ // Reads the next Value using the abbreviation Op. Returns true only |
+ // if Op is an array (and sets Value to the number of elements in the |
+ // array). |
+ inline bool readRecordAbbrevField(const NaClBitCodeAbbrevOp &Op, |
+ uint64_t &Value); |
+ |
+ // Reads and returns the next value using the abbreviation Op, |
+ // assuming Op appears after an array abbreviation. |
+ inline uint64_t readArrayAbbreviatedField(const NaClBitCodeAbbrevOp &Op); |
+ |
+ // Reads the array abbreviation Op, NumArrayElements times, putting |
+ // the read values in Vals. |
+ inline void readArrayAbbrev(const NaClBitCodeAbbrevOp &Op, |
+ unsigned NumArrayElements, |
+ SmallVectorImpl<uint64_t> &Vals); |
+ |
public: |
/// Return the abbreviation for the specified AbbrevId. |
- const BitCodeAbbrev *getAbbrev(unsigned AbbrevID) { |
- unsigned AbbrevNo = AbbrevID-bitc::FIRST_APPLICATION_ABBREV; |
+ const NaClBitCodeAbbrev *getAbbrev(unsigned AbbrevID) const { |
+ unsigned AbbrevNo = AbbrevID-naclbitc::FIRST_APPLICATION_ABBREV; |
assert(AbbrevNo < CurAbbrevs.size() && "Invalid abbrev #!"); |
- return CurAbbrevs[AbbrevNo].get(); |
+ return CurAbbrevs[AbbrevNo]; |
} |
/// Read the current record and discard it. |
void skipRecord(unsigned AbbrevID); |
- |
- unsigned readRecord(unsigned AbbrevID, SmallVectorImpl<uint64_t> &Vals, |
- StringRef *Blob = nullptr); |
+ |
+ unsigned readRecord(unsigned AbbrevID, SmallVectorImpl<uint64_t> &Vals); |
//===--------------------------------------------------------------------===// |
// Abbrev Processing |
//===--------------------------------------------------------------------===// |
- void ReadAbbrevRecord(); |
- |
- bool ReadBlockInfoBlock(); |
+ // IsLocal indicates where the abbreviation occurs. If it is in the |
+ // BlockInfo block, IsLocal is false. In all other cases, IsLocal is |
+ // true. |
+ void ReadAbbrevRecord(bool IsLocal, |
+ NaClAbbrevListener *Listener); |
+ |
+ // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord, |
+ // except that no abbreviation is built. |
+ void SkipAbbrevRecord(); |
+ |
+ bool ReadBlockInfoBlock(NaClAbbrevListener *Listener); |
}; |
} // End llvm namespace |