//
// The LLVM Compiler Infrastructure
//
-// This file was developed by Ted Kremenek and is distributed under the
-// University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "llvm/Bitcode/Deserialize.h"
-
-#ifdef DEBUG_BACKPATCH
-#include "llvm/Support/Streams.h"
-#endif
-
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
Deserializer::Deserializer(BitstreamReader& stream)
- : Stream(stream), RecIdx(0), FreeList(NULL) {
+ : 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 NDEBUG
+#ifdef DEBUG_BACKPATCH
for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
assert (I->first.hasFinalPtr() &&
"Some pointers were not backpatched.");
if (RecIdx >= Record.size()) {
RecIdx = 0;
Record.clear();
+ AbbrevNo = 0;
return false;
}
- else return true;
+ else
+ return true;
}
- else return false;
+
+ 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() {
- // FIXME: Check if we haven't run off the edge of the stream.
- // FIXME: Handle abbreviations.
- assert (Record.size() == 0);
+ 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 Code;
+ unsigned BlockLevel = BlockStack.size();
- while (true) {
+ 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) {
- if (Stream.AtEndOfStream())
- return;
+ assert (!inRecord());
+
+ AdvanceStream();
+
+ assert (!BlockStack.empty() || AtEnd());
- Code = Stream.ReadCode();
+ uint64_t LastBPos = StreamStart;
- if (Code == bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- unsigned id = Stream.ReadSubBlockID();
- Stream.EnterSubBlock(id);
- continue;
- }
+ 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();
- if (Code == bitc::END_BLOCK) {
- bool x = Stream.ReadBlockEnd();
- assert (!x && "Error at block end.");
- continue;
+ 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());
- if (Code == bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
+ 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;
}
-
- break;
+ else
+ SkipBlock();
}
- assert (Record.size() == 0);
- Stream.ReadRecord(Code,Record);
- assert (Record.size() > 0 || Stream.AtEndOfStream());
+ 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;
- ReadRecord();
+ if (!AdvanceStream())
+ return true;
- return Stream.AtEndOfStream();
+ return false;
}
uint64_t Deserializer::ReadInt() {
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.
cstr[i] = (char) ReadInt();
if (isNullTerm)
- cstr[len+1] = '\0';
+ cstr[len] = '\0';
return cstr;
}
-void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm) {
+void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm,
+ unsigned Idx) {
+
unsigned len = ReadInt();
- buff.clear();
- buff.reserve(len);
+ // 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());
buff.push_back('\0');
}
-void Deserializer::RegisterPtr(unsigned PtrId, const void* Ptr) {
+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";
+ errs() << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
#endif
SetPtr(E,Ptr);
}
-void Deserializer::ReadUIntPtr(uintptr_t& PtrRef) {
- unsigned PtrId = ReadInt();
-
+void Deserializer::ReadUIntPtr(uintptr_t& PtrRef,
+ const SerializedPtrID& PtrId,
+ bool AllowBackpatch) {
if (PtrId == 0) {
PtrRef = 0;
return;
}
-#ifdef DEBUG_BACKPATCH
- llvm::cerr << "ReadUintPtr: " << PtrId << "\n";
-#endif
-
MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));
- if (HasFinalPtr(E))
+ if (HasFinalPtr(E)) {
PtrRef = GetFinalPtr(E);
+
+#ifdef DEBUG_BACKPATCH
+ errs() << "ReadUintPtr: " << PtrId
+ << " <-- " << (void*) GetFinalPtr(E) << '\n';
+#endif
+ }
else {
+ assert (AllowBackpatch &&
+ "Client forbids backpatching for this pointer.");
+
+#ifdef DEBUG_BACKPATCH
+ errs() << "ReadUintPtr: " << PtrId << " (NO PTR YET)\n";
+#endif
+
// Register backpatch. Check the freelist for a BPNode.
BPNode* N;
}
uintptr_t Deserializer::ReadInternalRefPtr() {
- unsigned PtrId = ReadInt();
+ SerializedPtrID PtrId = ReadPtrID();
assert (PtrId != 0 && "References cannot refer the NULL address.");
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)