| 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
|
|
|