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 <unordered_map> | |
John
2016/03/29 16:27:10
alphabetize?
Karl
2016/03/29 20:10:47
Done.
| |
27 #include <mutex> | |
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 | |
137 // file. Sharing is used to allow parallel parses. Share by using | |
138 // std::share_ptr's 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()); | |
John
2016/03/29 16:27:10
perhaps you could use std::make_shared? you'll pro
Karl
2016/03/29 20:10:47
I followed the advice of "Effective Modern C++" by
| |
157 } | |
158 ~BlockInfoRecordsMap() = default; | |
159 | |
160 bool isFrozen() { | |
John
2016/03/29 16:27:10
can this method be marked const?
Karl
2016/03/29 20:10:47
Done.
| |
161 return IsFrozen.load(); | |
162 } | |
163 | |
164 // Returns false if already frozen. | |
John
2016/03/29 16:27:10
returns true if already frozen, no?
Karl
2016/03/29 20:10:47
Good catch. Forgot to update the comment when I ch
| |
165 bool freeze() { | |
166 return IsFrozen.exchange(true); | |
167 } | |
168 | |
169 BlockInfo &getBlockInfo(unsigned BlockID) { | |
John
2016/03/29 16:27:10
can this method be marked const?
Karl
2016/03/29 20:10:47
Unfortunately no. The way that the code updates th
| |
170 InfosMap::iterator Pos = Infos.find(BlockID); | |
John
2016/03/29 16:27:10
auto? I believe this is one of the few cases where
Karl
2016/03/29 20:10:47
Done.
| |
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 BlockInfoAbbrev for the instance's lifetime, allowing updates | |
177 // to the BlockInfoRecordsMap. Also verifies that the BlockInfoRecordsMap | |
178 // didn't get frozen during the instance's lifetime. | |
179 class UpdateLock { | |
180 UpdateLock() = delete; | |
181 UpdateLock &operator=(const UpdateLock&) = delete; | |
182 public: | |
183 explicit UpdateLock(BlockInfoRecordsMap &BlockInfoRecords); | |
184 ~UpdateLock(); | |
185 private: | |
186 // The BlockInfoRecordsMap to update. | |
187 BlockInfoRecordsMap &BlockInfoRecords; | |
188 // The locked mutex from BlockInfoRecordsMap; | |
189 std::unique_lock<std::mutex> Lock; | |
190 }; | |
191 | |
192 private: | |
193 // The set of known BlockInfo's. | |
194 InfosMap Infos; | |
195 // True if the known BlockInfo blocks are frozen (i.e. the bitstream reader | |
196 // will ignore the BlockInfo block). | |
197 std::atomic_bool IsFrozen; | |
198 // Lock to use to update this data structure. | |
199 std::mutex Lock; | |
200 | |
201 BlockInfoRecordsMap(); | |
202 }; | |
203 | |
133 private: | 204 private: |
134 friend class NaClBitstreamCursor; | 205 friend class NaClBitstreamCursor; |
135 | 206 |
136 std::unique_ptr<MemoryObject> BitcodeBytes; | 207 std::unique_ptr<MemoryObject> BitcodeBytes; |
137 | 208 |
138 std::vector<BlockInfo> BlockInfoRecords; | 209 std::shared_ptr<BlockInfoRecordsMap> BlockInfoRecords; |
139 | |
140 // True if the BlockInfo block has been read. | |
141 bool HasReadBlockInfoBlock = false; | |
142 | 210 |
143 /// \brief Holds the offset of the first byte after the header. | 211 /// \brief Holds the offset of the first byte after the header. |
144 size_t InitialAddress; | 212 size_t InitialAddress; |
145 | 213 |
146 // True if filler should be added to byte align records. | 214 // True if filler should be added to byte align records. |
147 bool AlignBitcodeRecords = false; | 215 bool AlignBitcodeRecords = false; |
148 NaClBitstreamReader(const NaClBitstreamReader&) = delete; | 216 NaClBitstreamReader(const NaClBitstreamReader&) = delete; |
149 void operator=(const NaClBitstreamReader&) = delete; | 217 void operator=(const NaClBitstreamReader&) = delete; |
150 | 218 |
151 | 219 |
152 void initFromHeader(NaClBitcodeHeader &Header) { | 220 void initFromHeader(NaClBitcodeHeader &Header) { |
153 InitialAddress = Header.getHeaderSize(); | 221 InitialAddress = Header.getHeaderSize(); |
154 AlignBitcodeRecords = Header.getAlignBitcodeRecords(); | 222 AlignBitcodeRecords = Header.getAlignBitcodeRecords(); |
155 } | 223 } |
156 | 224 |
157 public: | 225 public: |
158 /// Read stream from sequence of bytes [Start .. End) after parsing | 226 /// Read stream from sequence of bytes [Start .. End) after parsing |
159 /// the given bitcode header. | 227 /// the given bitcode header. |
160 NaClBitstreamReader(const unsigned char *Start, const unsigned char *End, | 228 NaClBitstreamReader(const unsigned char *Start, const unsigned char *End, |
161 NaClBitcodeHeader &Header) | 229 NaClBitcodeHeader &Header) |
162 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)) { | 230 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)), |
231 BlockInfoRecords(BlockInfoRecordsMap::create()) { | |
163 initFromHeader(Header); | 232 initFromHeader(Header); |
164 } | 233 } |
165 | 234 |
166 /// Read stream from Bytes, after parsing the given bitcode header. | 235 /// Read stream from Bytes, after parsing the given bitcode header. |
167 NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header) | 236 NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header) |
168 : BitcodeBytes(Bytes) { | 237 : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()) { |
169 initFromHeader(Header); | 238 initFromHeader(Header); |
170 } | 239 } |
171 | 240 |
172 /// Read stream from bytes, starting at the given initial address. | 241 /// Read stream from bytes, starting at the given initial address. |
173 /// Provides simple API for unit testing. | 242 /// Provides simple API for unit testing. |
174 NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress) | 243 NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress) |
175 : BitcodeBytes(Bytes), InitialAddress(InitialAddress) { | 244 : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()), |
245 InitialAddress(InitialAddress) { | |
176 } | 246 } |
177 | 247 |
248 /// Read stream from sequence of bytes [Start .. End), using the global | |
249 /// abbreviations of the given bitstream reader. Assumes that [Start .. End) | |
250 /// is copied from Reader's memory object. | |
251 NaClBitstreamReader(const unsigned char *Start, | |
252 const unsigned char *End, NaClBitstreamReader *Reader) | |
253 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)), | |
254 BlockInfoRecords(Reader->BlockInfoRecords), InitialAddress(0) | |
255 { BlockInfoRecords->freeze(); } | |
256 | |
178 // Returns the memory object that is being read. | 257 // Returns the memory object that is being read. |
179 MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } | 258 MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } |
180 | 259 |
181 ~NaClBitstreamReader() {} | 260 ~NaClBitstreamReader() {} |
182 | 261 |
183 /// \brief Returns the initial address (after the header) of the input stream. | 262 /// \brief Returns the initial address (after the header) of the input stream. |
184 size_t getInitialAddress() const { | 263 size_t getInitialAddress() const { |
185 return InitialAddress; | 264 return InitialAddress; |
186 } | 265 } |
187 | 266 |
188 //===--------------------------------------------------------------------===// | 267 //===--------------------------------------------------------------------===// |
189 // Block Manipulation | 268 // Block Manipulation |
190 //===--------------------------------------------------------------------===// | 269 //===--------------------------------------------------------------------===// |
191 | 270 |
192 /// If there is block info for the specified ID, return it, otherwise return | 271 BlockInfo &getBlockInfo(unsigned BlockID) { |
193 /// null. | 272 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 } | 273 } |
215 }; | 274 }; |
216 | 275 |
217 /// When advancing through a bitstream cursor, each advance can discover a few | 276 /// When advancing through a bitstream cursor, each advance can discover a few |
218 /// different kinds of entries: | 277 /// different kinds of entries: |
219 struct NaClBitstreamEntry { | 278 struct NaClBitstreamEntry { |
220 enum { | 279 enum { |
221 Error, // Malformed bitcode was found. | 280 Error, // Malformed bitcode was found. |
222 EndBlock, // We've reached the end of the current block, (or the end of the | 281 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. | 282 // 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); } | 465 : ErrHandler(new ErrorHandler(*this)) { init(&R); } |
407 | 466 |
408 void init(NaClBitstreamReader *R) { | 467 void init(NaClBitstreamReader *R) { |
409 freeState(); | 468 freeState(); |
410 BitStream = R; | 469 BitStream = R; |
411 NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); | 470 NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); |
412 Size = 0; | 471 Size = 0; |
413 BitsInCurWord = 0; | 472 BitsInCurWord = 0; |
414 if (BitStream) { | 473 if (BitStream) { |
415 BlockScope.push_back( | 474 BlockScope.push_back( |
416 Block(&BitStream->getOrCreateBlockInfo(naclbitc::TOP_LEVEL_BLOCKID))); | 475 Block(&BitStream->getBlockInfo(naclbitc::TOP_LEVEL_BLOCKID))); |
417 } | 476 } |
418 } | 477 } |
419 | 478 |
420 ~NaClBitstreamCursor() { | 479 ~NaClBitstreamCursor() { |
421 freeState(); | 480 freeState(); |
422 } | 481 } |
423 | 482 |
424 void freeState() { | 483 void freeState() { |
425 while (!BlockScope.empty()) | 484 while (!BlockScope.empty()) |
426 BlockScope.pop_back(); | 485 BlockScope.pop_back(); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
516 NaClBitstreamEntry Entry = advance(Flags, 0); | 575 NaClBitstreamEntry Entry = advance(Flags, 0); |
517 if (Entry.Kind != NaClBitstreamEntry::SubBlock) | 576 if (Entry.Kind != NaClBitstreamEntry::SubBlock) |
518 return Entry; | 577 return Entry; |
519 | 578 |
520 // If we found a sub-block, just skip over it and check the next entry. | 579 // If we found a sub-block, just skip over it and check the next entry. |
521 if (SkipBlock()) | 580 if (SkipBlock()) |
522 return NaClBitstreamEntry::getError(); | 581 return NaClBitstreamEntry::getError(); |
523 } | 582 } |
524 } | 583 } |
525 | 584 |
585 /// Returns the starting byte of the word containing BitNo. | |
586 uintptr_t getStartWordByteForBit(uint64_t BitNo) const { | |
587 return uintptr_t(BitNo/8) & ~(sizeof(word_t)-1); | |
588 } | |
589 | |
590 /// Returns the index of BitNo within the word it appears in. | |
591 unsigned getWordBitNo(uint64_t BitNo) const { | |
592 return unsigned(BitNo & (sizeof(word_t)*8-1)); | |
593 } | |
594 | |
595 /// Returns the ending byte of the word containing BitNo. | |
596 uintptr_t getEndWordByteForBit(uint64_t BitNo) const { | |
597 return getStartWordByteForBit(BitNo) + | |
598 (getWordBitNo(BitNo) | |
599 ? sizeof(word_t) | |
600 : 0); | |
601 } | |
602 | |
603 /// Fills Buffer[Size] using bytes at Address (in the memory object being | |
604 /// read). Returns number of bytes filled (less than Size if at end of memory | |
605 /// object). | |
606 uint64_t fillBuffer(uint8_t *Buffer, size_t Size, size_t Address) const { | |
607 return BitStream->getBitcodeBytes().readBytes(Buffer, Size, Address); | |
608 } | |
609 | |
526 /// Reset the stream to the specified bit number. | 610 /// Reset the stream to the specified bit number. |
527 void JumpToBit(uint64_t BitNo) { | 611 void JumpToBit(uint64_t BitNo) { |
528 uintptr_t ByteNo = uintptr_t(BitNo/8) & ~(sizeof(word_t)-1); | 612 uintptr_t ByteNo = getStartWordByteForBit(BitNo); |
529 unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1)); | 613 unsigned WordBitNo = getWordBitNo(BitNo); |
530 if (!canSkipToPos(ByteNo)) | 614 if (!canSkipToPos(ByteNo)) |
531 reportInvalidJumpToBit(BitNo); | 615 reportInvalidJumpToBit(BitNo); |
532 | 616 |
533 // Move the cursor to the right word. | 617 // Move the cursor to the right word. |
534 NextChar = ByteNo; | 618 NextChar = ByteNo; |
535 BitsInCurWord = 0; | 619 BitsInCurWord = 0; |
536 | 620 |
537 // Skip over any bits that are already consumed. | 621 // Skip over any bits that are already consumed. |
538 if (WordBitNo) | 622 if (WordBitNo) |
539 Read(WordBitNo); | 623 Read(WordBitNo); |
540 } | 624 } |
541 | 625 |
542 void fillCurWord() { | 626 void fillCurWord() { |
543 assert(Size == 0 || NextChar < (unsigned)Size); | 627 assert(Size == 0 || NextChar < (unsigned)Size); |
544 | 628 |
545 // Read the next word from the stream. | 629 // Read the next word from the stream. |
546 uint8_t Array[sizeof(word_t)] = {0}; | 630 uint8_t Array[sizeof(word_t)] = {0}; |
547 | 631 |
548 uint64_t BytesRead = | 632 uint64_t BytesRead = fillBuffer(Array, sizeof(Array), NextChar); |
549 BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar); | |
550 | 633 |
551 // If we run out of data, stop at the end of the stream. | 634 // If we run out of data, stop at the end of the stream. |
552 if (BytesRead == 0) { | 635 if (BytesRead == 0) { |
553 Size = NextChar; | 636 Size = NextChar; |
554 return; | 637 return; |
555 } | 638 } |
556 | 639 |
557 CurWord = | 640 CurWord = |
558 support::endian::read<word_t, support::little, support::unaligned>( | 641 support::endian::read<word_t, support::little, support::unaligned>( |
559 Array); | 642 Array); |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
785 // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord, | 868 // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord, |
786 // except that no abbreviation is built. | 869 // except that no abbreviation is built. |
787 void SkipAbbrevRecord(); | 870 void SkipAbbrevRecord(); |
788 | 871 |
789 bool ReadBlockInfoBlock(NaClAbbrevListener *Listener); | 872 bool ReadBlockInfoBlock(NaClAbbrevListener *Listener); |
790 }; | 873 }; |
791 | 874 |
792 } // End llvm namespace | 875 } // End llvm namespace |
793 | 876 |
794 #endif | 877 #endif |
OLD | NEW |