| OLD | NEW |
| 1 //===- NaClBitstreamReader.h -----------------------------------*- C++ -*-===// | 1 //===- NaClBitstreamReader.h -----------------------------------*- C++ -*-===// |
| 2 // Low-level bitstream reader interface | 2 // Low-level bitstream reader interface |
| 3 // | 3 // |
| 4 // The LLVM Compiler Infrastructure | 4 // The LLVM Compiler Infrastructure |
| 5 // | 5 // |
| 6 // This file is distributed under the University of Illinois Open Source | 6 // This file is distributed under the University of Illinois Open Source |
| 7 // License. See LICENSE.TXT for details. | 7 // License. See LICENSE.TXT for details. |
| 8 // | 8 // |
| 9 //===----------------------------------------------------------------------===// | 9 //===----------------------------------------------------------------------===// |
| 10 // | 10 // |
| 11 // This header defines the BitstreamReader class. This class can be used to | 11 // This header defines the BitstreamReader class. This class can be used to |
| 12 // read an arbitrary bitstream, regardless of its contents. | 12 // read an arbitrary bitstream, regardless of its contents. |
| 13 // | 13 // |
| 14 //===----------------------------------------------------------------------===// | 14 //===----------------------------------------------------------------------===// |
| 15 | 15 |
| 16 #ifndef LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H | 16 #ifndef LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H |
| 17 #define LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H | 17 #define LLVM_BITCODE_NACL_NACLBITSTREAMREADER_H |
| 18 | 18 |
| 19 #include "llvm/ADT/SmallVector.h" | 19 #include "llvm/ADT/SmallVector.h" |
| 20 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" | 20 #include "llvm/Bitcode/NaCl/NaClBitcodeHeader.h" |
| 21 #include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" | 21 #include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h" |
| 22 #include "llvm/Support/Endian.h" | 22 #include "llvm/Support/Endian.h" |
| 23 #include "llvm/Support/StreamingMemoryObject.h" | 23 #include "llvm/Support/StreamingMemoryObject.h" |
| 24 #include <atomic> |
| 24 #include <climits> | 25 #include <climits> |
| 26 #include <mutex> |
| 27 #include <unordered_map> |
| 25 #include <vector> | 28 #include <vector> |
| 26 | 29 |
| 27 namespace llvm { | 30 namespace llvm { |
| 28 | 31 |
| 29 class Deserializer; | 32 class Deserializer; |
| 30 class NaClBitstreamCursor; | 33 class NaClBitstreamCursor; |
| 31 | 34 |
| 32 namespace naclbitc { | 35 namespace naclbitc { |
| 33 | 36 |
| 34 /// Returns the Bit as a Byte:BitInByte string. | 37 /// Returns the Bit as a Byte:BitInByte string. |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 BlockInfo(const BlockInfo&) = default; | 126 BlockInfo(const BlockInfo&) = default; |
| 124 unsigned getBlockID() const { return BlockID; } | 127 unsigned getBlockID() const { return BlockID; } |
| 125 void setBlockID(unsigned ID) { BlockID = ID; } | 128 void setBlockID(unsigned ID) { BlockID = ID; } |
| 126 AbbrevList &getAbbrevs() { return Abbrevs; } | 129 AbbrevList &getAbbrevs() { return Abbrevs; } |
| 127 ~BlockInfo() {} | 130 ~BlockInfo() {} |
| 128 private: | 131 private: |
| 129 unsigned BlockID; | 132 unsigned BlockID; |
| 130 AbbrevList Abbrevs; | 133 AbbrevList Abbrevs; |
| 131 }; | 134 }; |
| 132 | 135 |
| 136 // Holds the global abbreviations in the BlockInfo block of the bitcode file. |
| 137 // Sharing is used to allow parallel parses. Share by using std::share_ptr's |
| 138 // and std::shared_from_this(). |
| 139 // |
| 140 // Note: The BlockInfo block must be parsed before sharing of the |
| 141 // BlockInfoRecordsMap. Therefore, before changing to a parallel parse, the |
| 142 // BlockInfoRecordsMap must be frozen. Failure to do so, can lead to |
| 143 // unexpected behaviour. |
| 144 // |
| 145 // In practice, this means that only function blocks can be parsed in |
| 146 // parallel. |
| 147 class BlockInfoRecordsMap : |
| 148 public std::enable_shared_from_this<BlockInfoRecordsMap> { |
| 149 friend class NaClBitstreamReader; |
| 150 BlockInfoRecordsMap(const BlockInfoRecordsMap&) = delete; |
| 151 BlockInfoRecordsMap &operator=(const BlockInfoRecordsMap&) = delete; |
| 152 public: |
| 153 using InfosMap = std::unordered_map<unsigned, BlockInfo>; |
| 154 |
| 155 static std::shared_ptr<BlockInfoRecordsMap> create() { |
| 156 return std::shared_ptr<BlockInfoRecordsMap>(new BlockInfoRecordsMap()); |
| 157 } |
| 158 ~BlockInfoRecordsMap() = default; |
| 159 |
| 160 bool isFrozen() const { |
| 161 return IsFrozen.load(); |
| 162 } |
| 163 |
| 164 // Returns true if already frozen. |
| 165 bool freeze() { |
| 166 return IsFrozen.exchange(true); |
| 167 } |
| 168 |
| 169 BlockInfo &getBlockInfo(unsigned BlockID) { |
| 170 auto Pos = Infos.find(BlockID); |
| 171 if (Pos != Infos.end()) |
| 172 return Pos->second; |
| 173 report_fatal_error("Invalid block ID: " + std::to_string(BlockID)); |
| 174 } |
| 175 |
| 176 // Locks the BlockInfoRecordsMap for the lifetime of the UpdateLock. Used |
| 177 // to allow the parsing of a BlockInfo block, and install global |
| 178 // abbreviations. |
| 179 // |
| 180 // Verifies that the BlockInfoRecordsMap didn't get frozen during the |
| 181 // instance's lifetime as a safety precaution. That is, it checks that no |
| 182 // bitstream reader was created to share the global abbreviations before the |
| 183 // global abbreviations are defined. |
| 184 class UpdateLock { |
| 185 UpdateLock() = delete; |
| 186 UpdateLock &operator=(const UpdateLock&) = delete; |
| 187 public: |
| 188 explicit UpdateLock(BlockInfoRecordsMap &BlockInfoRecords); |
| 189 ~UpdateLock(); |
| 190 private: |
| 191 // The BlockInfoRecordsMap to update. |
| 192 BlockInfoRecordsMap &BlockInfoRecords; |
| 193 // The locked mutex from BlockInfoRecordsMap; |
| 194 std::unique_lock<std::mutex> Lock; |
| 195 }; |
| 196 |
| 197 private: |
| 198 // The set of known BlockInfo's. |
| 199 InfosMap Infos; |
| 200 // True if the known BlockInfo blocks are frozen (i.e. the bitstream reader |
| 201 // will ignore the BlockInfo block). |
| 202 std::atomic_bool IsFrozen; |
| 203 // Lock to use to update this data structure. |
| 204 std::mutex Lock; |
| 205 |
| 206 BlockInfoRecordsMap(); |
| 207 }; |
| 208 |
| 133 private: | 209 private: |
| 134 friend class NaClBitstreamCursor; | 210 friend class NaClBitstreamCursor; |
| 135 | 211 |
| 136 std::unique_ptr<MemoryObject> BitcodeBytes; | 212 std::unique_ptr<MemoryObject> BitcodeBytes; |
| 137 | 213 |
| 138 std::vector<BlockInfo> BlockInfoRecords; | 214 std::shared_ptr<BlockInfoRecordsMap> BlockInfoRecords; |
| 139 | |
| 140 // True if the BlockInfo block has been read. | |
| 141 bool HasReadBlockInfoBlock = false; | |
| 142 | 215 |
| 143 /// \brief Holds the offset of the first byte after the header. | 216 /// \brief Holds the offset of the first byte after the header. |
| 144 size_t InitialAddress; | 217 size_t InitialAddress; |
| 145 | 218 |
| 146 // True if filler should be added to byte align records. | 219 // True if filler should be added to byte align records. |
| 147 bool AlignBitcodeRecords = false; | 220 bool AlignBitcodeRecords = false; |
| 148 NaClBitstreamReader(const NaClBitstreamReader&) = delete; | 221 NaClBitstreamReader(const NaClBitstreamReader&) = delete; |
| 149 void operator=(const NaClBitstreamReader&) = delete; | 222 void operator=(const NaClBitstreamReader&) = delete; |
| 150 | 223 |
| 151 | 224 |
| 152 void initFromHeader(NaClBitcodeHeader &Header) { | 225 void initFromHeader(NaClBitcodeHeader &Header) { |
| 153 InitialAddress = Header.getHeaderSize(); | 226 InitialAddress = Header.getHeaderSize(); |
| 154 AlignBitcodeRecords = Header.getAlignBitcodeRecords(); | 227 AlignBitcodeRecords = Header.getAlignBitcodeRecords(); |
| 155 } | 228 } |
| 156 | 229 |
| 157 public: | 230 public: |
| 158 /// Read stream from sequence of bytes [Start .. End) after parsing | 231 /// Read stream from sequence of bytes [Start .. End) after parsing |
| 159 /// the given bitcode header. | 232 /// the given bitcode header. |
| 160 NaClBitstreamReader(const unsigned char *Start, const unsigned char *End, | 233 NaClBitstreamReader(const unsigned char *Start, const unsigned char *End, |
| 161 NaClBitcodeHeader &Header) | 234 NaClBitcodeHeader &Header) |
| 162 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)) { | 235 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)), |
| 236 BlockInfoRecords(BlockInfoRecordsMap::create()) { |
| 163 initFromHeader(Header); | 237 initFromHeader(Header); |
| 164 } | 238 } |
| 165 | 239 |
| 166 /// Read stream from Bytes, after parsing the given bitcode header. | 240 /// Read stream from Bytes, after parsing the given bitcode header. |
| 167 NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header) | 241 NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header) |
| 168 : BitcodeBytes(Bytes) { | 242 : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()) { |
| 169 initFromHeader(Header); | 243 initFromHeader(Header); |
| 170 } | 244 } |
| 171 | 245 |
| 172 /// Read stream from bytes, starting at the given initial address. | 246 /// Read stream from bytes, starting at the given initial address. |
| 173 /// Provides simple API for unit testing. | 247 /// Provides simple API for unit testing. |
| 174 NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress) | 248 NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress) |
| 175 : BitcodeBytes(Bytes), InitialAddress(InitialAddress) { | 249 : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()), |
| 250 InitialAddress(InitialAddress) { |
| 176 } | 251 } |
| 177 | 252 |
| 253 /// Read stream from sequence of bytes [Start .. End), using the global |
| 254 /// abbreviations of the given bitstream reader. Assumes that [Start .. End) |
| 255 /// is copied from Reader's memory object. |
| 256 NaClBitstreamReader(const unsigned char *Start, |
| 257 const unsigned char *End, NaClBitstreamReader *Reader) |
| 258 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)), |
| 259 BlockInfoRecords(Reader->BlockInfoRecords), InitialAddress(0) |
| 260 { BlockInfoRecords->freeze(); } |
| 261 |
| 178 // Returns the memory object that is being read. | 262 // Returns the memory object that is being read. |
| 179 MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } | 263 MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } |
| 180 | 264 |
| 181 ~NaClBitstreamReader() {} | 265 ~NaClBitstreamReader() {} |
| 182 | 266 |
| 183 /// \brief Returns the initial address (after the header) of the input stream. | 267 /// \brief Returns the initial address (after the header) of the input stream. |
| 184 size_t getInitialAddress() const { | 268 size_t getInitialAddress() const { |
| 185 return InitialAddress; | 269 return InitialAddress; |
| 186 } | 270 } |
| 187 | 271 |
| 188 //===--------------------------------------------------------------------===// | 272 //===--------------------------------------------------------------------===// |
| 189 // Block Manipulation | 273 // Block Manipulation |
| 190 //===--------------------------------------------------------------------===// | 274 //===--------------------------------------------------------------------===// |
| 191 | 275 |
| 192 /// If there is block info for the specified ID, return it, otherwise return | 276 BlockInfo &getBlockInfo(unsigned BlockID) { |
| 193 /// null. | 277 return BlockInfoRecords->getBlockInfo(BlockID); |
| 194 const BlockInfo *getBlockInfo(unsigned BlockID) const { | |
| 195 // Common case, the most recent entry matches BlockID. | |
| 196 if (!BlockInfoRecords.empty() && | |
| 197 BlockInfoRecords.back().getBlockID() == BlockID) | |
| 198 return &BlockInfoRecords.back(); | |
| 199 | |
| 200 for (unsigned i = 0, e = static_cast<unsigned>(BlockInfoRecords.size()); | |
| 201 i != e; ++i) | |
| 202 if (BlockInfoRecords[i].getBlockID() == BlockID) | |
| 203 return &BlockInfoRecords[i]; | |
| 204 return nullptr; | |
| 205 } | |
| 206 | |
| 207 BlockInfo &getOrCreateBlockInfo(unsigned BlockID) { | |
| 208 if (const BlockInfo *BI = getBlockInfo(BlockID)) | |
| 209 return *const_cast<BlockInfo*>(BI); | |
| 210 | |
| 211 // Otherwise, add a new record. | |
| 212 BlockInfoRecords.push_back(BlockInfo(BlockID)); | |
| 213 return BlockInfoRecords.back(); | |
| 214 } | 278 } |
| 215 }; | 279 }; |
| 216 | 280 |
| 217 /// When advancing through a bitstream cursor, each advance can discover a few | 281 /// When advancing through a bitstream cursor, each advance can discover a few |
| 218 /// different kinds of entries: | 282 /// different kinds of entries: |
| 219 struct NaClBitstreamEntry { | 283 struct NaClBitstreamEntry { |
| 220 enum { | 284 enum { |
| 221 Error, // Malformed bitcode was found. | 285 Error, // Malformed bitcode was found. |
| 222 EndBlock, // We've reached the end of the current block, (or the end of the | 286 EndBlock, // We've reached the end of the current block, (or the end of the |
| 223 // file, which is treated like a series of EndBlock records. | 287 // file, which is treated like a series of EndBlock records. |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 : ErrHandler(new ErrorHandler(*this)) { init(&R); } | 470 : ErrHandler(new ErrorHandler(*this)) { init(&R); } |
| 407 | 471 |
| 408 void init(NaClBitstreamReader *R) { | 472 void init(NaClBitstreamReader *R) { |
| 409 freeState(); | 473 freeState(); |
| 410 BitStream = R; | 474 BitStream = R; |
| 411 NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); | 475 NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); |
| 412 Size = 0; | 476 Size = 0; |
| 413 BitsInCurWord = 0; | 477 BitsInCurWord = 0; |
| 414 if (BitStream) { | 478 if (BitStream) { |
| 415 BlockScope.push_back( | 479 BlockScope.push_back( |
| 416 Block(&BitStream->getOrCreateBlockInfo(naclbitc::TOP_LEVEL_BLOCKID))); | 480 Block(&BitStream->getBlockInfo(naclbitc::TOP_LEVEL_BLOCKID))); |
| 417 } | 481 } |
| 418 } | 482 } |
| 419 | 483 |
| 420 ~NaClBitstreamCursor() { | 484 ~NaClBitstreamCursor() { |
| 421 freeState(); | 485 freeState(); |
| 422 } | 486 } |
| 423 | 487 |
| 424 void freeState() { | 488 void freeState() { |
| 425 while (!BlockScope.empty()) | 489 while (!BlockScope.empty()) |
| 426 BlockScope.pop_back(); | 490 BlockScope.pop_back(); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 NaClBitstreamEntry Entry = advance(Flags, 0); | 580 NaClBitstreamEntry Entry = advance(Flags, 0); |
| 517 if (Entry.Kind != NaClBitstreamEntry::SubBlock) | 581 if (Entry.Kind != NaClBitstreamEntry::SubBlock) |
| 518 return Entry; | 582 return Entry; |
| 519 | 583 |
| 520 // If we found a sub-block, just skip over it and check the next entry. | 584 // If we found a sub-block, just skip over it and check the next entry. |
| 521 if (SkipBlock()) | 585 if (SkipBlock()) |
| 522 return NaClBitstreamEntry::getError(); | 586 return NaClBitstreamEntry::getError(); |
| 523 } | 587 } |
| 524 } | 588 } |
| 525 | 589 |
| 590 /// Returns the starting byte of the word containing BitNo. |
| 591 uintptr_t getStartWordByteForBit(uint64_t BitNo) const { |
| 592 return uintptr_t(BitNo/8) & ~(sizeof(word_t)-1); |
| 593 } |
| 594 |
| 595 /// Returns the index of BitNo within the word it appears in. |
| 596 unsigned getWordBitNo(uint64_t BitNo) const { |
| 597 return unsigned(BitNo & (sizeof(word_t)*8-1)); |
| 598 } |
| 599 |
| 600 /// Returns the ending byte of the word containing BitNo. |
| 601 uintptr_t getEndWordByteForBit(uint64_t BitNo) const { |
| 602 return getStartWordByteForBit(BitNo) + |
| 603 (getWordBitNo(BitNo) |
| 604 ? sizeof(word_t) |
| 605 : 0); |
| 606 } |
| 607 |
| 608 /// Fills Buffer[Size] using bytes at Address (in the memory object being |
| 609 /// read). Returns number of bytes filled (less than Size if at end of memory |
| 610 /// object). |
| 611 uint64_t fillBuffer(uint8_t *Buffer, size_t Size, size_t Address) const { |
| 612 return BitStream->getBitcodeBytes().readBytes(Buffer, Size, Address); |
| 613 } |
| 614 |
| 526 /// Reset the stream to the specified bit number. | 615 /// Reset the stream to the specified bit number. |
| 527 void JumpToBit(uint64_t BitNo) { | 616 void JumpToBit(uint64_t BitNo) { |
| 528 uintptr_t ByteNo = uintptr_t(BitNo/8) & ~(sizeof(word_t)-1); | 617 uintptr_t ByteNo = getStartWordByteForBit(BitNo); |
| 529 unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1)); | 618 unsigned WordBitNo = getWordBitNo(BitNo); |
| 530 if (!canSkipToPos(ByteNo)) | 619 if (!canSkipToPos(ByteNo)) |
| 531 reportInvalidJumpToBit(BitNo); | 620 reportInvalidJumpToBit(BitNo); |
| 532 | 621 |
| 533 // Move the cursor to the right word. | 622 // Move the cursor to the right word. |
| 534 NextChar = ByteNo; | 623 NextChar = ByteNo; |
| 535 BitsInCurWord = 0; | 624 BitsInCurWord = 0; |
| 536 | 625 |
| 537 // Skip over any bits that are already consumed. | 626 // Skip over any bits that are already consumed. |
| 538 if (WordBitNo) | 627 if (WordBitNo) |
| 539 Read(WordBitNo); | 628 Read(WordBitNo); |
| 540 } | 629 } |
| 541 | 630 |
| 542 void fillCurWord() { | 631 void fillCurWord() { |
| 543 assert(Size == 0 || NextChar < (unsigned)Size); | 632 assert(Size == 0 || NextChar < (unsigned)Size); |
| 544 | 633 |
| 545 // Read the next word from the stream. | 634 // Read the next word from the stream. |
| 546 uint8_t Array[sizeof(word_t)] = {0}; | 635 uint8_t Array[sizeof(word_t)] = {0}; |
| 547 | 636 |
| 548 uint64_t BytesRead = | 637 uint64_t BytesRead = fillBuffer(Array, sizeof(Array), NextChar); |
| 549 BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar); | |
| 550 | 638 |
| 551 // If we run out of data, stop at the end of the stream. | 639 // If we run out of data, stop at the end of the stream. |
| 552 if (BytesRead == 0) { | 640 if (BytesRead == 0) { |
| 553 Size = NextChar; | 641 Size = NextChar; |
| 554 return; | 642 return; |
| 555 } | 643 } |
| 556 | 644 |
| 557 CurWord = | 645 CurWord = |
| 558 support::endian::read<word_t, support::little, support::unaligned>( | 646 support::endian::read<word_t, support::little, support::unaligned>( |
| 559 Array); | 647 Array); |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord, | 873 // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord, |
| 786 // except that no abbreviation is built. | 874 // except that no abbreviation is built. |
| 787 void SkipAbbrevRecord(); | 875 void SkipAbbrevRecord(); |
| 788 | 876 |
| 789 bool ReadBlockInfoBlock(NaClAbbrevListener *Listener); | 877 bool ReadBlockInfoBlock(NaClAbbrevListener *Listener); |
| 790 }; | 878 }; |
| 791 | 879 |
| 792 } // End llvm namespace | 880 } // End llvm namespace |
| 793 | 881 |
| 794 #endif | 882 #endif |
| OLD | NEW |