Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Side by Side Diff: include/llvm/Bitcode/NaCl/NaClBitstreamReader.h

Issue 1843673003: Modify bitstream reader to allow parallel parses. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Fix nits. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | lib/Bitcode/NaCl/Reader/NaClBitstreamReader.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 class BlockInfoRecordsMap;
137 using SharedBlockInfoMap = std::shared_ptr<BlockInfoRecordsMap>;
138
139 // Holds the global abbreviations in the BlockInfo block of the bitcode file.
140 // Sharing is used to allow parallel parses. Share by using std::share_ptr's
141 // and std::shared_from_this().
142 //
143 // Note: The BlockInfo block must be parsed before sharing of the
144 // BlockInfoRecordsMap. Therefore, before changing to a parallel parse, the
145 // BlockInfoRecordsMap must be frozen. Failure to do so, can lead to
146 // unexpected behaviour.
147 //
148 // In practice, this means that only function blocks can be parsed in
149 // parallel.
150 class BlockInfoRecordsMap :
151 public std::enable_shared_from_this<BlockInfoRecordsMap> {
152 friend class NaClBitstreamReader;
153 BlockInfoRecordsMap(const BlockInfoRecordsMap&) = delete;
154 BlockInfoRecordsMap &operator=(const BlockInfoRecordsMap&) = delete;
155 public:
156 using InfosMap = std::unordered_map<unsigned, std::unique_ptr<BlockInfo>>;
157
158 static SharedBlockInfoMap create() {
159 return SharedBlockInfoMap(new BlockInfoRecordsMap());
160 }
161 ~BlockInfoRecordsMap() = default;
162
163 bool isFrozen() const {
164 return IsFrozen.load();
165 }
166
167 // Returns true if already frozen.
168 bool freeze() {
169 return IsFrozen.exchange(true);
170 }
171
172 BlockInfo *getBlockInfo(unsigned BlockID) {
173 auto Pos = KnownInfos.find(BlockID);
174 if (Pos != KnownInfos.end())
175 return Pos->second.get();
176 return getOrCreateUnknownBlockInfo(BlockID);
177 }
178
179 // Locks the BlockInfoRecordsMap for the lifetime of the UpdateLock. Used
180 // to allow the parsing of a BlockInfo block, and install global
181 // abbreviations.
182 //
183 // Verifies that the BlockInfoRecordsMap didn't get frozen during the
184 // instance's lifetime as a safety precaution. That is, it checks that no
185 // bitstream reader was created to share the global abbreviations before the
186 // global abbreviations are defined.
187 class UpdateLock {
188 UpdateLock() = delete;
189 UpdateLock(const UpdateLock&) = delete;
190 UpdateLock &operator=(const UpdateLock&) = delete;
191 public:
192 explicit UpdateLock(BlockInfoRecordsMap &BlockInfoRecords);
193 ~UpdateLock();
194 private:
195 // The BlockInfoRecordsMap to update.
196 BlockInfoRecordsMap &BlockInfoRecords;
197 // The locked mutex from BlockInfoRecordsMap;
198 std::unique_lock<std::mutex> Lock;
199 };
200
201 private:
202 // The set of known BlockInfo's. This map is prepopulated so that fast
203 // lookup can be performed thread safe (i.e. without using a lock).
204 InfosMap KnownInfos;
205 // The set of unknown BlockInfo's. This map is to handle unknown (and hence,
206 // invalid) PNaCl bitcode files. This map is updated incrementally, and uses
207 // UnknownBlockInfoLock to make it thread safe.
208 InfosMap UnknownInfos;
209 // True if the known BlockInfo blocks are frozen (i.e. the bitstream reader
210 // will ignore the BlockInfo block).
211 std::atomic_bool IsFrozen;
212 // Lock to use to update this data structure.
213 std::mutex UpdateRecordsLock;
214 // Lock to get/create an unknonw block info.
215 std::mutex UnknownBlockInfoLock;
216
217 BlockInfoRecordsMap();
218
219 BlockInfo *getOrCreateUnknownBlockInfo(unsigned BlockID);
220 };
221
133 private: 222 private:
134 friend class NaClBitstreamCursor; 223 friend class NaClBitstreamCursor;
135 224
136 std::unique_ptr<MemoryObject> BitcodeBytes; 225 std::unique_ptr<MemoryObject> BitcodeBytes;
137 226
138 std::vector<BlockInfo> BlockInfoRecords; 227 SharedBlockInfoMap BlockInfoRecords;
139
140 // True if the BlockInfo block has been read.
141 bool HasReadBlockInfoBlock = false;
142 228
143 /// \brief Holds the offset of the first byte after the header. 229 /// \brief Holds the offset of the first byte after the header.
144 size_t InitialAddress; 230 size_t InitialAddress;
145 231
146 // True if filler should be added to byte align records. 232 // True if filler should be added to byte align records.
147 bool AlignBitcodeRecords = false; 233 bool AlignBitcodeRecords = false;
148 NaClBitstreamReader(const NaClBitstreamReader&) = delete; 234 NaClBitstreamReader(const NaClBitstreamReader&) = delete;
149 void operator=(const NaClBitstreamReader&) = delete; 235 void operator=(const NaClBitstreamReader&) = delete;
150 236
151 237
152 void initFromHeader(NaClBitcodeHeader &Header) { 238 void initFromHeader(NaClBitcodeHeader &Header) {
153 InitialAddress = Header.getHeaderSize(); 239 InitialAddress = Header.getHeaderSize();
154 AlignBitcodeRecords = Header.getAlignBitcodeRecords(); 240 AlignBitcodeRecords = Header.getAlignBitcodeRecords();
155 } 241 }
156 242
157 public: 243 public:
158 /// Read stream from sequence of bytes [Start .. End) after parsing 244 /// Read stream from sequence of bytes [Start .. End) after parsing
159 /// the given bitcode header. 245 /// the given bitcode header.
160 NaClBitstreamReader(const unsigned char *Start, const unsigned char *End, 246 NaClBitstreamReader(const unsigned char *Start, const unsigned char *End,
161 NaClBitcodeHeader &Header) 247 NaClBitcodeHeader &Header)
162 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)) { 248 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)),
249 BlockInfoRecords(BlockInfoRecordsMap::create()) {
163 initFromHeader(Header); 250 initFromHeader(Header);
164 } 251 }
165 252
166 /// Read stream from Bytes, after parsing the given bitcode header. 253 /// Read stream from Bytes, after parsing the given bitcode header.
167 NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header) 254 NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header)
168 : BitcodeBytes(Bytes) { 255 : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()) {
169 initFromHeader(Header); 256 initFromHeader(Header);
170 } 257 }
171 258
172 /// Read stream from bytes, starting at the given initial address. 259 /// Read stream from bytes, starting at the given initial address.
173 /// Provides simple API for unit testing. 260 /// Provides simple API for unit testing.
174 NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress) 261 NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress)
175 : BitcodeBytes(Bytes), InitialAddress(InitialAddress) { 262 : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()),
263 InitialAddress(InitialAddress) {
176 } 264 }
177 265
266 /// Read stream from sequence of bytes [Start .. End), using the global
267 /// abbreviations of the given bitstream reader. Assumes that [Start .. End)
268 /// is copied from Reader's memory object.
269 NaClBitstreamReader(const unsigned char *Start,
270 const unsigned char *End, NaClBitstreamReader *Reader)
271 : BitcodeBytes(getNonStreamedMemoryObject(Start, End)),
272 BlockInfoRecords(Reader->BlockInfoRecords), InitialAddress(0)
273 { BlockInfoRecords->freeze(); }
274
178 // Returns the memory object that is being read. 275 // Returns the memory object that is being read.
179 MemoryObject &getBitcodeBytes() { return *BitcodeBytes; } 276 MemoryObject &getBitcodeBytes() { return *BitcodeBytes; }
180 277
181 ~NaClBitstreamReader() {} 278 ~NaClBitstreamReader() {}
182 279
183 /// \brief Returns the initial address (after the header) of the input stream. 280 /// \brief Returns the initial address (after the header) of the input stream.
184 size_t getInitialAddress() const { 281 size_t getInitialAddress() const {
185 return InitialAddress; 282 return InitialAddress;
186 } 283 }
187 284
188 //===--------------------------------------------------------------------===// 285 //===--------------------------------------------------------------------===//
189 // Block Manipulation 286 // Block Manipulation
190 //===--------------------------------------------------------------------===// 287 //===--------------------------------------------------------------------===//
191 288
192 /// If there is block info for the specified ID, return it, otherwise return 289 BlockInfo *getBlockInfo(unsigned BlockID) {
193 /// null. 290 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 } 291 }
215 }; 292 };
216 293
217 /// When advancing through a bitstream cursor, each advance can discover a few 294 /// When advancing through a bitstream cursor, each advance can discover a few
218 /// different kinds of entries: 295 /// different kinds of entries:
219 struct NaClBitstreamEntry { 296 struct NaClBitstreamEntry {
220 enum { 297 enum {
221 Error, // Malformed bitcode was found. 298 Error, // Malformed bitcode was found.
222 EndBlock, // We've reached the end of the current block, (or the end of the 299 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. 300 // file, which is treated like a series of EndBlock records.
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 : ErrHandler(new ErrorHandler(*this)) { init(&R); } 483 : ErrHandler(new ErrorHandler(*this)) { init(&R); }
407 484
408 void init(NaClBitstreamReader *R) { 485 void init(NaClBitstreamReader *R) {
409 freeState(); 486 freeState();
410 BitStream = R; 487 BitStream = R;
411 NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress(); 488 NextChar = (BitStream == nullptr) ? 0 : BitStream->getInitialAddress();
412 Size = 0; 489 Size = 0;
413 BitsInCurWord = 0; 490 BitsInCurWord = 0;
414 if (BitStream) { 491 if (BitStream) {
415 BlockScope.push_back( 492 BlockScope.push_back(
416 Block(&BitStream->getOrCreateBlockInfo(naclbitc::TOP_LEVEL_BLOCKID))); 493 Block(BitStream->getBlockInfo(naclbitc::TOP_LEVEL_BLOCKID)));
417 } 494 }
418 } 495 }
419 496
420 ~NaClBitstreamCursor() { 497 ~NaClBitstreamCursor() {
421 freeState(); 498 freeState();
422 } 499 }
423 500
424 void freeState() { 501 void freeState() {
425 while (!BlockScope.empty()) 502 while (!BlockScope.empty())
426 BlockScope.pop_back(); 503 BlockScope.pop_back();
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 NaClBitstreamEntry Entry = advance(Flags, 0); 593 NaClBitstreamEntry Entry = advance(Flags, 0);
517 if (Entry.Kind != NaClBitstreamEntry::SubBlock) 594 if (Entry.Kind != NaClBitstreamEntry::SubBlock)
518 return Entry; 595 return Entry;
519 596
520 // If we found a sub-block, just skip over it and check the next entry. 597 // If we found a sub-block, just skip over it and check the next entry.
521 if (SkipBlock()) 598 if (SkipBlock())
522 return NaClBitstreamEntry::getError(); 599 return NaClBitstreamEntry::getError();
523 } 600 }
524 } 601 }
525 602
603 /// Returns the starting byte of the word containing BitNo.
604 uintptr_t getStartWordByteForBit(uint64_t BitNo) const {
605 return uintptr_t(BitNo/CHAR_BIT) & ~(sizeof(word_t)-1);
606 }
607
608 /// Returns the index of BitNo within the word it appears in.
609 unsigned getWordBitNo(uint64_t BitNo) const {
610 return unsigned(BitNo & (sizeof(word_t)*CHAR_BIT-1));
611 }
612
613 /// Returns the ending byte of the word containing BitNo.
614 uintptr_t getEndWordByteForBit(uint64_t BitNo) const {
615 return getStartWordByteForBit(BitNo) +
616 (getWordBitNo(BitNo)
617 ? sizeof(word_t)
618 : 0);
619 }
620
621 /// Fills Buffer[Size] using bytes at Address (in the memory object being
622 /// read). Returns number of bytes filled (less than Size if at end of memory
623 /// object).
624 uint64_t fillBuffer(uint8_t *Buffer, size_t Size, size_t Address) const {
625 return BitStream->getBitcodeBytes().readBytes(Buffer, Size, Address);
626 }
627
526 /// Reset the stream to the specified bit number. 628 /// Reset the stream to the specified bit number.
527 void JumpToBit(uint64_t BitNo) { 629 void JumpToBit(uint64_t BitNo) {
528 uintptr_t ByteNo = uintptr_t(BitNo/8) & ~(sizeof(word_t)-1); 630 const uintptr_t ByteNo = getStartWordByteForBit(BitNo);
529 unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1)); 631 const unsigned WordBitNo = getWordBitNo(BitNo);
530 if (!canSkipToPos(ByteNo)) 632 if (!canSkipToPos(ByteNo))
531 reportInvalidJumpToBit(BitNo); 633 reportInvalidJumpToBit(BitNo);
532 634
533 // Move the cursor to the right word. 635 // Move the cursor to the right word.
534 NextChar = ByteNo; 636 NextChar = ByteNo;
535 BitsInCurWord = 0; 637 BitsInCurWord = 0;
536 638
537 // Skip over any bits that are already consumed. 639 // Skip over any bits that are already consumed.
538 if (WordBitNo) 640 if (WordBitNo)
539 Read(WordBitNo); 641 Read(WordBitNo);
540 } 642 }
541 643
542 void fillCurWord() { 644 void fillCurWord() {
543 assert(Size == 0 || NextChar < (unsigned)Size); 645 assert(Size == 0 || NextChar < (unsigned)Size);
544 646
545 // Read the next word from the stream. 647 // Read the next word from the stream.
546 uint8_t Array[sizeof(word_t)] = {0}; 648 uint8_t Array[sizeof(word_t)] = {0};
547 649
548 uint64_t BytesRead = 650 uint64_t BytesRead = fillBuffer(Array, sizeof(Array), NextChar);
549 BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar);
550 651
551 // If we run out of data, stop at the end of the stream. 652 // If we run out of data, stop at the end of the stream.
552 if (BytesRead == 0) { 653 if (BytesRead == 0) {
553 Size = NextChar; 654 Size = NextChar;
554 return; 655 return;
555 } 656 }
556 657
557 CurWord = 658 CurWord =
558 support::endian::read<word_t, support::little, support::unaligned>( 659 support::endian::read<word_t, support::little, support::unaligned>(
559 Array); 660 Array);
560 NextChar += BytesRead; 661 NextChar += BytesRead;
561 BitsInCurWord = BytesRead * 8; 662 BitsInCurWord = BytesRead * CHAR_BIT;
562 } 663 }
563 664
564 word_t Read(unsigned NumBits) { 665 word_t Read(unsigned NumBits) {
565 static const unsigned BitsInWord = sizeof(word_t) * 8; 666 static const unsigned BitsInWord = sizeof(word_t) * CHAR_BIT;
566 667
567 assert(NumBits && NumBits <= BitsInWord && 668 assert(NumBits && NumBits <= BitsInWord &&
568 "Cannot return zero or more than BitsInWord bits!"); 669 "Cannot return zero or more than BitsInWord bits!");
569 670
570 static const unsigned Mask = sizeof(word_t) > 4 ? 0x3f : 0x1f; 671 static const unsigned Mask = sizeof(word_t) > 4 ? 0x3f : 0x1f;
571 672
572 // If the field is fully contained by CurWord, return it quickly. 673 // If the field is fully contained by CurWord, return it quickly.
573 if (BitsInCurWord >= NumBits) { 674 if (BitsInCurWord >= NumBits) {
574 word_t R = CurWord & (~word_t(0) >> (BitsInWord - NumBits)); 675 word_t R = CurWord & (~word_t(0) >> (BitsInWord - NumBits));
575 676
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 /// of this block. If the block record is malformed, return true. 788 /// of this block. If the block record is malformed, return true.
688 bool SkipBlock() { 789 bool SkipBlock() {
689 // Read and ignore the codelen value. Since we are skipping this block, we 790 // Read and ignore the codelen value. Since we are skipping this block, we
690 // don't care what code widths are used inside of it. 791 // don't care what code widths are used inside of it.
691 ReadVBR(naclbitc::CodeLenWidth); 792 ReadVBR(naclbitc::CodeLenWidth);
692 SkipToFourByteBoundary(); 793 SkipToFourByteBoundary();
693 unsigned NumFourBytes = Read(naclbitc::BlockSizeWidth); 794 unsigned NumFourBytes = Read(naclbitc::BlockSizeWidth);
694 795
695 // Check that the block wasn't partially defined, and that the offset isn't 796 // Check that the block wasn't partially defined, and that the offset isn't
696 // bogus. 797 // bogus.
697 size_t SkipTo = GetCurrentBitNo() + NumFourBytes*4*8; 798 size_t SkipTo = GetCurrentBitNo() + NumFourBytes*4*CHAR_BIT;
698 if (AtEndOfStream() || !canSkipToPos(SkipTo/8)) 799 if (AtEndOfStream() || !canSkipToPos(SkipTo/CHAR_BIT))
699 return true; 800 return true;
700 801
701 JumpToBit(SkipTo); 802 JumpToBit(SkipTo);
702 return false; 803 return false;
703 } 804 }
704 805
705 /// Having read the ENTER_SUBBLOCK abbrevid, enter the block, and return true 806 /// Having read the ENTER_SUBBLOCK abbrevid, enter the block, and return true
706 /// if the block has an error. 807 /// if the block has an error.
707 bool EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr); 808 bool EnterSubBlock(unsigned BlockID, unsigned *NumWordsP = nullptr);
708 809
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord, 886 // Skips over an abbreviation record. Duplicates code of ReadAbbrevRecord,
786 // except that no abbreviation is built. 887 // except that no abbreviation is built.
787 void SkipAbbrevRecord(); 888 void SkipAbbrevRecord();
788 889
789 bool ReadBlockInfoBlock(NaClAbbrevListener *Listener); 890 bool ReadBlockInfoBlock(NaClAbbrevListener *Listener);
790 }; 891 };
791 892
792 } // End llvm namespace 893 } // End llvm namespace
793 894
794 #endif 895 #endif
OLDNEW
« no previous file with comments | « no previous file | lib/Bitcode/NaCl/Reader/NaClBitstreamReader.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698