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

Unified 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 InfosMap in BlockInfoRecordsMap. Created 4 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/Bitcode/NaCl/Reader/NaClBitstreamReader.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: include/llvm/Bitcode/NaCl/NaClBitstreamReader.h
diff --git a/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h b/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h
index 1a981ae117dab156c27e4b3058b089af9e6eea92..e59b0cb27e0e4ad6b21790bd69d90649a1d7ea52 100644
--- a/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h
+++ b/include/llvm/Bitcode/NaCl/NaClBitstreamReader.h
@@ -21,7 +21,10 @@
#include "llvm/Bitcode/NaCl/NaClLLVMBitCodes.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/StreamingMemoryObject.h"
+#include <atomic>
#include <climits>
+#include <mutex>
+#include <unordered_map>
#include <vector>
namespace llvm {
@@ -130,15 +133,94 @@ public:
AbbrevList Abbrevs;
};
+ // Holds the global abbreviations in the BlockInfo block of the bitcode file.
+ // Sharing is used to allow parallel parses. Share by using std::share_ptr's
+ // and std::shared_from_this().
+ //
+ // Note: The BlockInfo block must be parsed before sharing of the
+ // BlockInfoRecordsMap. Therefore, before changing to a parallel parse, the
+ // BlockInfoRecordsMap must be frozen. Failure to do so, can lead to
+ // unexpected behaviour.
+ //
+ // In practice, this means that only function blocks can be parsed in
+ // parallel.
+ class BlockInfoRecordsMap :
+ public std::enable_shared_from_this<BlockInfoRecordsMap> {
+ friend class NaClBitstreamReader;
+ BlockInfoRecordsMap(const BlockInfoRecordsMap&) = delete;
+ BlockInfoRecordsMap &operator=(const BlockInfoRecordsMap&) = delete;
+ public:
+ using InfosMap = std::unordered_map<unsigned, std::unique_ptr<BlockInfo>>;
+
+ static std::shared_ptr<BlockInfoRecordsMap> create() {
Jim Stichnoth 2016/03/30 17:57:02 The somewhat unwieldy "std::shared_ptr<BlockInfoRe
Karl 2016/03/30 19:47:30 Done.
+ return std::shared_ptr<BlockInfoRecordsMap>(new BlockInfoRecordsMap());
+ }
+ ~BlockInfoRecordsMap() = default;
+
+ bool isFrozen() const {
+ return IsFrozen.load();
+ }
+
+ // Returns true if already frozen.
+ bool freeze() {
+ return IsFrozen.exchange(true);
+ }
+
+ BlockInfo *getBlockInfo(unsigned BlockID) {
+ auto Pos = KnownInfos.find(BlockID);
+ if (Pos != KnownInfos.end())
+ return Pos->second.get();
+ return getOrCreateUnknownBlockInfo(BlockID);
+ }
+
+ // Locks the BlockInfoRecordsMap for the lifetime of the UpdateLock. Used
+ // to allow the parsing of a BlockInfo block, and install global
+ // abbreviations.
+ //
+ // Verifies that the BlockInfoRecordsMap didn't get frozen during the
+ // instance's lifetime as a safety precaution. That is, it checks that no
+ // bitstream reader was created to share the global abbreviations before the
+ // global abbreviations are defined.
+ class UpdateLock {
+ UpdateLock() = delete;
+ UpdateLock &operator=(const UpdateLock&) = delete;
Jim Stichnoth 2016/03/30 17:57:02 Delete the default copy ctor?
Karl 2016/03/30 19:47:30 Done.
+ public:
+ explicit UpdateLock(BlockInfoRecordsMap &BlockInfoRecords);
+ ~UpdateLock();
+ private:
+ // The BlockInfoRecordsMap to update.
+ BlockInfoRecordsMap &BlockInfoRecords;
+ // The locked mutex from BlockInfoRecordsMap;
+ std::unique_lock<std::mutex> Lock;
+ };
+
+ private:
+ // The set of known BlockInfo's. This map is prepopulated so that fast
+ // lookup can be performed thread safe (i.e. without using a lock).
+ InfosMap KnownInfos;
+ // The set of unknown BlockInfo's. This map is to handle unknown (and hence,
+ // invalid) PNaCl bitcode files. This map is updated incrementally, and uses
+ // UnknownLock to make it thread safe.
+ InfosMap UnknownInfos;
+ // True if the known BlockInfo blocks are frozen (i.e. the bitstream reader
+ // will ignore the BlockInfo block).
+ std::atomic_bool IsFrozen;
+ // Lock to use to update this data structure.
+ std::mutex UpdateRecordsLock;
+ // Lock to get/create an unknonw block info.
+ std::mutex UnknownBlockInfoLock;
+
+ BlockInfoRecordsMap();
+
+ BlockInfo *getOrCreateUnknownBlockInfo(unsigned BlockID);
+ };
+
private:
friend class NaClBitstreamCursor;
std::unique_ptr<MemoryObject> BitcodeBytes;
- std::vector<BlockInfo> BlockInfoRecords;
-
- // True if the BlockInfo block has been read.
- bool HasReadBlockInfoBlock = false;
+ std::shared_ptr<BlockInfoRecordsMap> BlockInfoRecords;
/// \brief Holds the offset of the first byte after the header.
size_t InitialAddress;
@@ -159,22 +241,33 @@ public:
/// the given bitcode header.
NaClBitstreamReader(const unsigned char *Start, const unsigned char *End,
NaClBitcodeHeader &Header)
- : BitcodeBytes(getNonStreamedMemoryObject(Start, End)) {
+ : BitcodeBytes(getNonStreamedMemoryObject(Start, End)),
+ BlockInfoRecords(BlockInfoRecordsMap::create()) {
initFromHeader(Header);
}
/// Read stream from Bytes, after parsing the given bitcode header.
NaClBitstreamReader(MemoryObject *Bytes, NaClBitcodeHeader &Header)
- : BitcodeBytes(Bytes) {
+ : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()) {
initFromHeader(Header);
}
/// Read stream from bytes, starting at the given initial address.
/// Provides simple API for unit testing.
NaClBitstreamReader(MemoryObject *Bytes, size_t InitialAddress)
- : BitcodeBytes(Bytes), InitialAddress(InitialAddress) {
+ : BitcodeBytes(Bytes), BlockInfoRecords(BlockInfoRecordsMap::create()),
+ InitialAddress(InitialAddress) {
}
+ /// Read stream from sequence of bytes [Start .. End), using the global
+ /// abbreviations of the given bitstream reader. Assumes that [Start .. End)
+ /// is copied from Reader's memory object.
+ NaClBitstreamReader(const unsigned char *Start,
+ const unsigned char *End, NaClBitstreamReader *Reader)
+ : BitcodeBytes(getNonStreamedMemoryObject(Start, End)),
+ BlockInfoRecords(Reader->BlockInfoRecords), InitialAddress(0)
+ { BlockInfoRecords->freeze(); }
+
// Returns the memory object that is being read.
MemoryObject &getBitcodeBytes() { return *BitcodeBytes; }
@@ -189,28 +282,8 @@ public:
// Block Manipulation
//===--------------------------------------------------------------------===//
- /// If there is block info for the specified ID, return it, otherwise return
- /// null.
- const BlockInfo *getBlockInfo(unsigned BlockID) const {
- // Common case, the most recent entry matches BlockID.
- if (!BlockInfoRecords.empty() &&
- BlockInfoRecords.back().getBlockID() == BlockID)
- return &BlockInfoRecords.back();
-
- for (unsigned i = 0, e = static_cast<unsigned>(BlockInfoRecords.size());
- i != e; ++i)
- if (BlockInfoRecords[i].getBlockID() == BlockID)
- return &BlockInfoRecords[i];
- return nullptr;
- }
-
- BlockInfo &getOrCreateBlockInfo(unsigned BlockID) {
- if (const BlockInfo *BI = getBlockInfo(BlockID))
- return *const_cast<BlockInfo*>(BI);
-
- // Otherwise, add a new record.
- BlockInfoRecords.push_back(BlockInfo(BlockID));
- return BlockInfoRecords.back();
+ BlockInfo *getBlockInfo(unsigned BlockID) {
+ return BlockInfoRecords->getBlockInfo(BlockID);
}
};
@@ -413,7 +486,7 @@ public:
BitsInCurWord = 0;
if (BitStream) {
BlockScope.push_back(
- Block(&BitStream->getOrCreateBlockInfo(naclbitc::TOP_LEVEL_BLOCKID)));
+ Block(BitStream->getBlockInfo(naclbitc::TOP_LEVEL_BLOCKID)));
}
}
@@ -523,10 +596,35 @@ public:
}
}
+ /// Returns the starting byte of the word containing BitNo.
+ uintptr_t getStartWordByteForBit(uint64_t BitNo) const {
+ return uintptr_t(BitNo/8) & ~(sizeof(word_t)-1);
Jim Stichnoth 2016/03/30 17:57:02 Can these "8" magic constants be replaced with CHA
Karl 2016/03/30 19:47:30 Fixed all occurrences in file.
+ }
+
+ /// Returns the index of BitNo within the word it appears in.
+ unsigned getWordBitNo(uint64_t BitNo) const {
+ return unsigned(BitNo & (sizeof(word_t)*8-1));
+ }
+
+ /// Returns the ending byte of the word containing BitNo.
+ uintptr_t getEndWordByteForBit(uint64_t BitNo) const {
+ return getStartWordByteForBit(BitNo) +
+ (getWordBitNo(BitNo)
+ ? sizeof(word_t)
+ : 0);
+ }
+
+ /// Fills Buffer[Size] using bytes at Address (in the memory object being
+ /// read). Returns number of bytes filled (less than Size if at end of memory
+ /// object).
+ uint64_t fillBuffer(uint8_t *Buffer, size_t Size, size_t Address) const {
+ return BitStream->getBitcodeBytes().readBytes(Buffer, Size, Address);
+ }
+
/// Reset the stream to the specified bit number.
void JumpToBit(uint64_t BitNo) {
- uintptr_t ByteNo = uintptr_t(BitNo/8) & ~(sizeof(word_t)-1);
- unsigned WordBitNo = unsigned(BitNo & (sizeof(word_t)*8-1));
+ uintptr_t ByteNo = getStartWordByteForBit(BitNo);
Jim Stichnoth 2016/03/30 17:57:02 const?
Karl 2016/03/30 19:47:30 Done.
+ unsigned WordBitNo = getWordBitNo(BitNo);
if (!canSkipToPos(ByteNo))
reportInvalidJumpToBit(BitNo);
@@ -545,8 +643,7 @@ public:
// Read the next word from the stream.
uint8_t Array[sizeof(word_t)] = {0};
- uint64_t BytesRead =
- BitStream->getBitcodeBytes().readBytes(Array, sizeof(Array), NextChar);
+ uint64_t BytesRead = fillBuffer(Array, sizeof(Array), NextChar);
// If we run out of data, stop at the end of the stream.
if (BytesRead == 0) {
« 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