llvm-6502/lib/Bitcode/Reader/Deserialize.cpp
Ted Kremenek 48a396948f Updated Deserializer class to provide more information about the current
block that is being visited in the bitstream.  The client can also now
skip blocks before reading them, and query the current abbreviation number
as seen from the perspective of the Deserializer.  This allows the client
to be more interactive in the deserialization process (if they so choose).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@43916 91177308-0d34-0410-b5e6-96231b3b80d8
2007-11-09 00:43:51 +00:00

314 lines
7.0 KiB
C++

//==- Deserialize.cpp - Generic Object Serialization to Bitcode --*- C++ -*-==//
//
// 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 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) {
}
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()) {
AbbrevNo = Stream.ReadCode();
switch (AbbrevNo) {
case bitc::ENTER_SUBBLOCK: {
unsigned id = Stream.ReadSubBlockID();
BlockStack.push_back(std::make_pair(Stream.GetCurrentBitNo(),id));
break;
}
case bitc::END_BLOCK: {
bool x = Stream.ReadBlockEnd();
assert (!x && "Error at block end.");
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().second);
AbbrevNo = 0;
}
if (Stream.AtEndOfStream())
return;
assert (Record.size() == 0);
assert (AbbrevNo >= bitc::UNABBREV_RECORD);
RecordCode = Stream.ReadRecord(AbbrevNo,Record);
assert (Record.size() > 0);
}
void Deserializer::SkipBlock() {
assert (!inRecord());
assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
Stream.SkipBlock();
AbbrevNo = 0;
}
Deserializer::Location Deserializer::getCurrentBlockLocation() {
if (!inRecord())
AdvanceStream();
return BlockStack.back().first;
}
unsigned Deserializer::getCurrentBlockID() {
if (!inRecord())
AdvanceStream();
return BlockStack.back().second;
}
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<std::pair<Location,unsigned>,5>::reverse_iterator
I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
if (I->first == 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+1] = '\0';
return cstr;
}
void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm) {
unsigned len = ReadInt();
buff.clear();
buff.reserve(len);
for (unsigned i = 0; i < len; ++i)
buff.push_back((char) ReadInt());
if (isNullTerm)
buff.push_back('\0');
}
void Deserializer::RegisterPtr(unsigned 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, bool AllowBackpatch) {
SerializedPtrID PtrId = ReadPtrID();
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))
PtrRef = GetFinalPtr(E);
else {
assert (AllowBackpatch &&
"Client forbids backpatching for this pointer.");
// 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)