summaryrefslogtreecommitdiff
path: root/lib/Bitcode/Reader/Deserialize.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Bitcode/Reader/Deserialize.cpp')
-rw-r--r--lib/Bitcode/Reader/Deserialize.cpp454
1 files changed, 454 insertions, 0 deletions
diff --git a/lib/Bitcode/Reader/Deserialize.cpp b/lib/Bitcode/Reader/Deserialize.cpp
new file mode 100644
index 000000000000..06da6ce72721
--- /dev/null
+++ b/lib/Bitcode/Reader/Deserialize.cpp
@@ -0,0 +1,454 @@
+//==- Deserialize.cpp - Generic Object Serialization to Bitcode --*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the internal methods used for object serialization.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/Deserialize.h"
+
+#ifdef DEBUG_BACKPATCH
+#include "llvm/Support/Streams.h"
+#endif
+
+using namespace llvm;
+
+Deserializer::Deserializer(BitstreamReader& stream)
+ : Stream(stream), RecIdx(0), FreeList(NULL), AbbrevNo(0), RecordCode(0) {
+
+ StreamStart = Stream.GetCurrentBitNo();
+}
+
+Deserializer::~Deserializer() {
+ assert (RecIdx >= Record.size() &&
+ "Still scanning bitcode record when deserialization completed.");
+
+#ifdef DEBUG_BACKPATCH
+ for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
+ assert (I->first.hasFinalPtr() &&
+ "Some pointers were not backpatched.");
+#endif
+}
+
+
+bool Deserializer::inRecord() {
+ if (Record.size() > 0) {
+ if (RecIdx >= Record.size()) {
+ RecIdx = 0;
+ Record.clear();
+ AbbrevNo = 0;
+ return false;
+ }
+ else
+ return true;
+ }
+
+ return false;
+}
+
+bool Deserializer::AdvanceStream() {
+ assert (!inRecord() &&
+ "Cannot advance stream. Still processing a record.");
+
+ if (AbbrevNo == bitc::ENTER_SUBBLOCK ||
+ AbbrevNo >= bitc::UNABBREV_RECORD)
+ return true;
+
+ while (!Stream.AtEndOfStream()) {
+
+ uint64_t Pos = Stream.GetCurrentBitNo();
+ AbbrevNo = Stream.ReadCode();
+
+ switch (AbbrevNo) {
+ case bitc::ENTER_SUBBLOCK: {
+ unsigned id = Stream.ReadSubBlockID();
+
+ // Determine the extent of the block. This is useful for jumping around
+ // the stream. This is hack: we read the header of the block, save
+ // the length, and then revert the bitstream to a location just before
+ // the block is entered.
+ uint64_t BPos = Stream.GetCurrentBitNo();
+ Stream.ReadVBR(bitc::CodeLenWidth); // Skip the code size.
+ Stream.SkipToWord();
+ unsigned NumWords = Stream.Read(bitc::BlockSizeWidth);
+ Stream.JumpToBit(BPos);
+
+ BlockStack.push_back(Location(Pos,id,NumWords));
+ break;
+ }
+
+ case bitc::END_BLOCK: {
+ bool x = Stream.ReadBlockEnd();
+ assert(!x && "Error at block end."); x=x;
+ BlockStack.pop_back();
+ continue;
+ }
+
+ case bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void Deserializer::ReadRecord() {
+
+ while (AdvanceStream() && AbbrevNo == bitc::ENTER_SUBBLOCK) {
+ assert (!BlockStack.empty());
+ Stream.EnterSubBlock(BlockStack.back().BlockID);
+ AbbrevNo = 0;
+ }
+
+ if (Stream.AtEndOfStream())
+ return;
+
+ assert (Record.empty());
+ assert (AbbrevNo >= bitc::UNABBREV_RECORD);
+ RecordCode = Stream.ReadRecord(AbbrevNo,Record);
+ assert (Record.size() > 0);
+}
+
+void Deserializer::SkipBlock() {
+ assert (!inRecord());
+
+ if (AtEnd())
+ return;
+
+ AdvanceStream();
+
+ assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+ BlockStack.pop_back();
+ Stream.SkipBlock();
+
+ AbbrevNo = 0;
+ AdvanceStream();
+}
+
+bool Deserializer::SkipToBlock(unsigned BlockID) {
+ assert (!inRecord());
+
+ AdvanceStream();
+ assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+
+ unsigned BlockLevel = BlockStack.size();
+
+ while (!AtEnd() &&
+ BlockLevel == BlockStack.size() &&
+ getCurrentBlockID() != BlockID)
+ SkipBlock();
+
+ return !(AtEnd() || BlockLevel != BlockStack.size());
+}
+
+Deserializer::Location Deserializer::getCurrentBlockLocation() {
+ if (!inRecord())
+ AdvanceStream();
+
+ return BlockStack.back();
+}
+
+bool Deserializer::JumpTo(const Location& Loc) {
+
+ assert (!inRecord());
+
+ AdvanceStream();
+
+ assert (!BlockStack.empty() || AtEnd());
+
+ uint64_t LastBPos = StreamStart;
+
+ while (!BlockStack.empty()) {
+
+ LastBPos = BlockStack.back().BitNo;
+
+ // Determine of the current block contains the location of the block
+ // we are looking for.
+ if (BlockStack.back().contains(Loc)) {
+ // We found the enclosing block. We must first POP it off to
+ // destroy any accumulated context within the block scope. We then
+ // jump to the position of the block and enter it.
+ Stream.JumpToBit(LastBPos);
+
+ if (BlockStack.size() == Stream.BlockScope.size())
+ Stream.PopBlockScope();
+
+ BlockStack.pop_back();
+
+ AbbrevNo = 0;
+ AdvanceStream();
+ assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+
+ Stream.EnterSubBlock(BlockStack.back().BlockID);
+ break;
+ }
+
+ // This block does not contain the block we are looking for. Pop it.
+ if (BlockStack.size() == Stream.BlockScope.size())
+ Stream.PopBlockScope();
+
+ BlockStack.pop_back();
+
+ }
+
+ // Check if we have popped our way to the outermost scope. If so,
+ // we need to adjust our position.
+ if (BlockStack.empty()) {
+ assert (Stream.BlockScope.empty());
+
+ Stream.JumpToBit(Loc.BitNo < LastBPos ? StreamStart : LastBPos);
+ AbbrevNo = 0;
+ AdvanceStream();
+ }
+
+ assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
+ assert (!BlockStack.empty());
+
+ while (!AtEnd() && BlockStack.back() != Loc) {
+ if (BlockStack.back().contains(Loc)) {
+ Stream.EnterSubBlock(BlockStack.back().BlockID);
+ AbbrevNo = 0;
+ AdvanceStream();
+ continue;
+ }
+ else
+ SkipBlock();
+ }
+
+ if (AtEnd())
+ return false;
+
+ assert (BlockStack.back() == Loc);
+
+ return true;
+}
+
+void Deserializer::Rewind() {
+ while (!Stream.BlockScope.empty())
+ Stream.PopBlockScope();
+
+ while (!BlockStack.empty())
+ BlockStack.pop_back();
+
+ Stream.JumpToBit(StreamStart);
+ AbbrevNo = 0;
+}
+
+
+unsigned Deserializer::getCurrentBlockID() {
+ if (!inRecord())
+ AdvanceStream();
+
+ return BlockStack.back().BlockID;
+}
+
+unsigned Deserializer::getRecordCode() {
+ if (!inRecord()) {
+ AdvanceStream();
+ assert (AbbrevNo >= bitc::UNABBREV_RECORD);
+ ReadRecord();
+ }
+
+ return RecordCode;
+}
+
+bool Deserializer::FinishedBlock(Location BlockLoc) {
+ if (!inRecord())
+ AdvanceStream();
+
+ for (llvm::SmallVector<Location,8>::reverse_iterator
+ I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
+ if (*I == BlockLoc)
+ return false;
+
+ return true;
+}
+
+unsigned Deserializer::getAbbrevNo() {
+ if (!inRecord())
+ AdvanceStream();
+
+ return AbbrevNo;
+}
+
+bool Deserializer::AtEnd() {
+ if (inRecord())
+ return false;
+
+ if (!AdvanceStream())
+ return true;
+
+ return false;
+}
+
+uint64_t Deserializer::ReadInt() {
+ // FIXME: Any error recovery/handling with incomplete or bad files?
+ if (!inRecord())
+ ReadRecord();
+
+ return Record[RecIdx++];
+}
+
+int64_t Deserializer::ReadSInt() {
+ uint64_t x = ReadInt();
+ int64_t magnitude = x >> 1;
+ return x & 0x1 ? -magnitude : magnitude;
+}
+
+char* Deserializer::ReadCStr(char* cstr, unsigned MaxLen, bool isNullTerm) {
+ if (cstr == NULL)
+ MaxLen = 0; // Zero this just in case someone does something funny.
+
+ unsigned len = ReadInt();
+
+ assert (MaxLen == 0 || (len + (isNullTerm ? 1 : 0)) <= MaxLen);
+
+ if (!cstr)
+ cstr = new char[len + (isNullTerm ? 1 : 0)];
+
+ assert (cstr != NULL);
+
+ for (unsigned i = 0; i < len; ++i)
+ cstr[i] = (char) ReadInt();
+
+ if (isNullTerm)
+ cstr[len] = '\0';
+
+ return cstr;
+}
+
+void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm,
+ unsigned Idx) {
+
+ unsigned len = ReadInt();
+
+ // If Idx is beyond the current before size, reduce Idx to refer to the
+ // element after the last element.
+ if (Idx > buff.size())
+ Idx = buff.size();
+
+ buff.reserve(len+Idx);
+ buff.resize(Idx);
+
+ for (unsigned i = 0; i < len; ++i)
+ buff.push_back((char) ReadInt());
+
+ if (isNullTerm)
+ buff.push_back('\0');
+}
+
+void Deserializer::RegisterPtr(const SerializedPtrID& PtrId,
+ const void* Ptr) {
+
+ MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
+
+ assert (!HasFinalPtr(E) && "Pointer already registered.");
+
+#ifdef DEBUG_BACKPATCH
+ llvm::cerr << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
+#endif
+
+ SetPtr(E,Ptr);
+}
+
+void Deserializer::ReadUIntPtr(uintptr_t& PtrRef,
+ const SerializedPtrID& PtrId,
+ bool AllowBackpatch) {
+ if (PtrId == 0) {
+ PtrRef = 0;
+ return;
+ }
+
+ MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
+
+ if (HasFinalPtr(E)) {
+ PtrRef = GetFinalPtr(E);
+
+#ifdef DEBUG_BACKPATCH
+ llvm::cerr << "ReadUintPtr: " << PtrId
+ << " <-- " << (void*) GetFinalPtr(E) << '\n';
+#endif
+ }
+ else {
+ assert (AllowBackpatch &&
+ "Client forbids backpatching for this pointer.");
+
+#ifdef DEBUG_BACKPATCH
+ llvm::cerr << "ReadUintPtr: " << PtrId << " (NO PTR YET)\n";
+#endif
+
+ // Register backpatch. Check the freelist for a BPNode.
+ BPNode* N;
+
+ if (FreeList) {
+ N = FreeList;
+ FreeList = FreeList->Next;
+ }
+ else // No available BPNode. Allocate one.
+ N = (BPNode*) Allocator.Allocate<BPNode>();
+
+ new (N) BPNode(GetBPNode(E),PtrRef);
+ SetBPNode(E,N);
+ }
+}
+
+uintptr_t Deserializer::ReadInternalRefPtr() {
+ SerializedPtrID PtrId = ReadPtrID();
+
+ assert (PtrId != 0 && "References cannot refer the NULL address.");
+
+ MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
+
+ assert (HasFinalPtr(E) &&
+ "Cannot backpatch references. Object must be already deserialized.");
+
+ return GetFinalPtr(E);
+}
+
+void Deserializer::BPEntry::SetPtr(BPNode*& FreeList, void* P) {
+ BPNode* Last = NULL;
+
+ for (BPNode* N = Head; N != NULL; N=N->Next) {
+ Last = N;
+ N->PtrRef |= reinterpret_cast<uintptr_t>(P);
+ }
+
+ if (Last) {
+ Last->Next = FreeList;
+ FreeList = Head;
+ }
+
+ Ptr = const_cast<void*>(P);
+}
+
+
+#define INT_READ(TYPE)\
+void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
+ X = (TYPE) D.ReadInt(); }
+
+INT_READ(bool)
+INT_READ(unsigned char)
+INT_READ(unsigned short)
+INT_READ(unsigned int)
+INT_READ(unsigned long)
+
+#define SINT_READ(TYPE)\
+void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
+ X = (TYPE) D.ReadSInt(); }
+
+INT_READ(signed char)
+INT_READ(signed short)
+INT_READ(signed int)
+INT_READ(signed long)