mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	state out of the BitstreamReader class into a BitstreamCursor class. Doing this allows the client to have multiple cursors into the same file, each with potentially different live block stacks and abbreviation records. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@70157 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			455 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			455 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //==- 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)
 |