diff options
author | Derek Schuff <dschuff@google.com> | 2012-02-06 22:30:29 +0000 |
---|---|---|
committer | Derek Schuff <dschuff@google.com> | 2012-02-06 22:30:29 +0000 |
commit | 2ea93875b2f2900b9d244dfd7649c9ed02a34cd7 (patch) | |
tree | 3e2851a6033c574bbd73e97aa7fcad8501759a76 /lib | |
parent | 06d7e1b52b412bd1ad307606496d7a4dc66ab751 (diff) |
Enable streaming of bitcode
This CL delays reading of function bodies from initial parse until
materialization, allowing overlap of compilation with bitcode download.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@149918 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 205 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.h | 29 | ||||
-rw-r--r-- | lib/Bitcode/Writer/BitcodeWriter.cpp | 10 | ||||
-rw-r--r-- | lib/MC/MCDisassembler/Disassembler.cpp | 4 | ||||
-rw-r--r-- | lib/MC/MCDisassembler/EDDisassembler.cpp | 4 | ||||
-rw-r--r-- | lib/Support/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Support/DataStream.cpp | 96 | ||||
-rw-r--r-- | lib/Support/MemoryObject.cpp | 2 | ||||
-rw-r--r-- | lib/Support/StreamableMemoryObject.cpp | 137 | ||||
-rw-r--r-- | lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 8 | ||||
-rw-r--r-- | lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp | 2 | ||||
-rw-r--r-- | lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h | 2 | ||||
-rw-r--r-- | lib/Target/X86/Disassembler/X86Disassembler.cpp | 2 | ||||
-rw-r--r-- | lib/Target/X86/Disassembler/X86Disassembler.h | 2 |
14 files changed, 415 insertions, 90 deletions
diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index ace3042eb6..899154971b 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -22,6 +22,7 @@ #include "llvm/AutoUpgrade.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataStream.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/OperandTraits.h" @@ -1409,8 +1410,36 @@ bool BitcodeReader::RememberAndSkipFunctionBody() { return false; } -bool BitcodeReader::ParseModule() { - if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) +bool BitcodeReader::GlobalCleanup() { + // Patch the initializers for globals and aliases up. + ResolveGlobalAndAliasInits(); + if (!GlobalInits.empty() || !AliasInits.empty()) + return Error("Malformed global initializer set"); + + // Look for intrinsic functions which need to be upgraded at some point + for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); + FI != FE; ++FI) { + Function *NewFn; + if (UpgradeIntrinsicFunction(FI, NewFn)) + UpgradedIntrinsics.push_back(std::make_pair(FI, NewFn)); + } + + // Look for global variables which need to be renamed. + for (Module::global_iterator + GI = TheModule->global_begin(), GE = TheModule->global_end(); + GI != GE; ++GI) + UpgradeGlobalVariable(GI); + // Force deallocation of memory for these vectors to favor the client that + // want lazy deserialization. + std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); + std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits); + return false; +} + +bool BitcodeReader::ParseModule(bool Resume) { + if (Resume) + Stream.JumpToBit(NextUnreadBit); + else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return Error("Malformed block record"); SmallVector<uint64_t, 64> Record; @@ -1424,33 +1453,7 @@ bool BitcodeReader::ParseModule() { if (Stream.ReadBlockEnd()) return Error("Error at end of module block"); - // Patch the initializers for globals and aliases up. - ResolveGlobalAndAliasInits(); - if (!GlobalInits.empty() || !AliasInits.empty()) - return Error("Malformed global initializer set"); - if (!FunctionsWithBodies.empty()) - return Error("Too few function bodies found"); - - // Look for intrinsic functions which need to be upgraded at some point - for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); - FI != FE; ++FI) { - Function* NewFn; - if (UpgradeIntrinsicFunction(FI, NewFn)) - UpgradedIntrinsics.push_back(std::make_pair(FI, NewFn)); - } - - // Look for global variables which need to be renamed. - for (Module::global_iterator - GI = TheModule->global_begin(), GE = TheModule->global_end(); - GI != GE; ++GI) - UpgradeGlobalVariable(GI); - - // Force deallocation of memory for these vectors to favor the client that - // want lazy deserialization. - std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); - std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits); - std::vector<Function*>().swap(FunctionsWithBodies); - return false; + return GlobalCleanup(); } if (Code == bitc::ENTER_SUBBLOCK) { @@ -1474,6 +1477,7 @@ bool BitcodeReader::ParseModule() { case bitc::VALUE_SYMTAB_BLOCK_ID: if (ParseValueSymbolTable()) return true; + SeenValueSymbolTable = true; break; case bitc::CONSTANTS_BLOCK_ID: if (ParseConstants() || ResolveGlobalAndAliasInits()) @@ -1486,13 +1490,25 @@ bool BitcodeReader::ParseModule() { case bitc::FUNCTION_BLOCK_ID: // If this is the first function body we've seen, reverse the // FunctionsWithBodies list. - if (!HasReversedFunctionsWithBodies) { + if (!SeenFirstFunctionBody) { std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); - HasReversedFunctionsWithBodies = true; + if (GlobalCleanup()) + return true; + SeenFirstFunctionBody = true; } if (RememberAndSkipFunctionBody()) return true; + // For streaming bitcode, suspend parsing when we reach the function + // bodies. Subsequent materialization calls will resume it when + // necessary. For streaming, the function bodies must be at the end of + // the bitcode. If the bitcode file is old, the symbol table will be + // at the end instead and will not have been seen yet. In this case, + // just finish the parse now. + if (LazyStreamer && SeenValueSymbolTable) { + NextUnreadBit = Stream.GetCurrentBitNo(); + return false; + } break; case bitc::USELIST_BLOCK_ID: if (ParseUseLists()) @@ -1651,8 +1667,10 @@ bool BitcodeReader::ParseModule() { // If this is a function with a body, remember the prototype we are // creating now, so that we can match up the body with them later. - if (!isProto) + if (!isProto) { FunctionsWithBodies.push_back(Func); + if (LazyStreamer) DeferredFunctionInfo[Func] = 0; + } break; } // ALIAS: [alias type, aliasee val#, linkage] @@ -1691,24 +1709,7 @@ bool BitcodeReader::ParseModule() { bool BitcodeReader::ParseBitcodeInto(Module *M) { TheModule = 0; - unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart(); - unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); - - if (Buffer->getBufferSize() & 3) { - if (!isRawBitcode(BufPtr, BufEnd) && !isBitcodeWrapper(BufPtr, BufEnd)) - return Error("Invalid bitcode signature"); - else - return Error("Bitcode stream should be a multiple of 4 bytes in length"); - } - - // If we have a wrapper header, parse it and ignore the non-bc file contents. - // The magic number is 0x0B17C0DE stored in little endian. - if (isBitcodeWrapper(BufPtr, BufEnd)) - if (SkipBitcodeWrapperHeader(BufPtr, BufEnd)) - return Error("Invalid bitcode wrapper header"); - - StreamFile.init(BufPtr, BufEnd); - Stream.init(StreamFile); + if (InitStream()) return true; // Sniff for the signature. if (Stream.Read(8) != 'B' || @@ -1750,8 +1751,9 @@ bool BitcodeReader::ParseBitcodeInto(Module *M) { if (TheModule) return Error("Multiple MODULE_BLOCKs in same stream"); TheModule = M; - if (ParseModule()) + if (ParseModule(false)) return true; + if (LazyStreamer) return false; break; default: if (Stream.SkipBlock()) @@ -1819,20 +1821,7 @@ bool BitcodeReader::ParseModuleTriple(std::string &Triple) { } bool BitcodeReader::ParseTriple(std::string &Triple) { - if (Buffer->getBufferSize() & 3) - return Error("Bitcode stream should be a multiple of 4 bytes in length"); - - unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart(); - unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); - - // If we have a wrapper header, parse it and ignore the non-bc file contents. - // The magic number is 0x0B17C0DE stored in little endian. - if (isBitcodeWrapper(BufPtr, BufEnd)) - if (SkipBitcodeWrapperHeader(BufPtr, BufEnd)) - return Error("Invalid bitcode wrapper header"); - - StreamFile.init(BufPtr, BufEnd); - Stream.init(StreamFile); + if (InitStream()) return true; // Sniff for the signature. if (Stream.Read(8) != 'B' || @@ -2708,6 +2697,19 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { return false; } +/// FindFunctionInStream - Find the function body in the bitcode stream +bool BitcodeReader::FindFunctionInStream(Function *F, + DenseMap<Function*, uint64_t>::iterator DeferredFunctionInfoIterator) { + while (DeferredFunctionInfoIterator->second == 0) { + if (Stream.AtEndOfStream()) + return Error("Could not find Function in stream"); + // ParseModule will parse the next body in the stream and set its + // position in the DeferredFunctionInfo map. + if (ParseModule(true)) return true; + } + return false; +} + //===----------------------------------------------------------------------===// // GVMaterializer implementation //===----------------------------------------------------------------------===// @@ -2728,6 +2730,10 @@ bool BitcodeReader::Materialize(GlobalValue *GV, std::string *ErrInfo) { DenseMap<Function*, uint64_t>::iterator DFII = DeferredFunctionInfo.find(F); assert(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); + // If its position is recorded as 0, its body is somewhere in the stream + // but we haven't seen it yet. + if (DFII->second == 0) + if (LazyStreamer && FindFunctionInStream(F, DFII)) return true; // Move the bit stream to the saved position of the deferred function body. Stream.JumpToBit(DFII->second); @@ -2805,6 +2811,57 @@ bool BitcodeReader::MaterializeModule(Module *M, std::string *ErrInfo) { return false; } +bool BitcodeReader::InitStream() { + if (LazyStreamer) return InitLazyStream(); + return InitStreamFromBuffer(); +} + +bool BitcodeReader::InitStreamFromBuffer() { + const unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart(); + const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); + + if (Buffer->getBufferSize() & 3) { + if (!isRawBitcode(BufPtr, BufEnd) && !isBitcodeWrapper(BufPtr, BufEnd)) + return Error("Invalid bitcode signature"); + else + return Error("Bitcode stream should be a multiple of 4 bytes in length"); + } + + // If we have a wrapper header, parse it and ignore the non-bc file contents. + // The magic number is 0x0B17C0DE stored in little endian. + if (isBitcodeWrapper(BufPtr, BufEnd)) + if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) + return Error("Invalid bitcode wrapper header"); + + StreamFile.reset(new BitstreamReader(BufPtr, BufEnd)); + Stream.init(*StreamFile); + + return false; +} + +bool BitcodeReader::InitLazyStream() { + // Check and strip off the bitcode wrapper; BitstreamReader expects never to + // see it. + StreamingMemoryObject *Bytes = new StreamingMemoryObject(LazyStreamer); + StreamFile.reset(new BitstreamReader(Bytes)); + Stream.init(*StreamFile); + + unsigned char buf[16]; + if (Bytes->readBytes(0, 16, buf, NULL) == -1) + return Error("Bitcode stream must be at least 16 bytes in length"); + + if (!isBitcode(buf, buf + 16)) + return Error("Invalid bitcode signature"); + + if (isBitcodeWrapper(buf, buf + 4)) { + const unsigned char *bitcodeStart = buf; + const unsigned char *bitcodeEnd = buf + 16; + SkipBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false); + Bytes->dropLeadingBytes(bitcodeStart - buf); + Bytes->setKnownObjectSize(bitcodeEnd - bitcodeStart); + } + return false; +} //===----------------------------------------------------------------------===// // External interface @@ -2833,6 +2890,24 @@ Module *llvm::getLazyBitcodeModule(MemoryBuffer *Buffer, return M; } + +Module *llvm::getStreamedBitcodeModule(const std::string &name, + DataStreamer *streamer, + LLVMContext &Context, + std::string *ErrMsg) { + Module *M = new Module(name, Context); + BitcodeReader *R = new BitcodeReader(streamer, Context); + M->setMaterializer(R); + if (R->ParseBitcodeInto(M)) { + if (ErrMsg) + *ErrMsg = R->getErrorString(); + delete M; // Also deletes R. + return 0; + } + R->setBufferOwned(false); // no buffer to delete + return M; +} + /// ParseBitcodeFile - Read the specified bitcode file, returning the module. /// If an error occurs, return null and fill in *ErrMsg if non-null. Module *llvm::ParseBitcodeFile(MemoryBuffer *Buffer, LLVMContext& Context, diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 952d645a4c..ad7baa732d 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -126,8 +126,11 @@ class BitcodeReader : public GVMaterializer { Module *TheModule; MemoryBuffer *Buffer; bool BufferOwned; - BitstreamReader StreamFile; + OwningPtr<BitstreamReader> StreamFile; BitstreamCursor Stream; + DataStreamer *LazyStreamer; + uint64_t NextUnreadBit; + bool SeenValueSymbolTable; const char *ErrorString; @@ -161,9 +164,10 @@ class BitcodeReader : public GVMaterializer { // Map the bitcode's custom MDKind ID to the Module's MDKind ID. DenseMap<unsigned, unsigned> MDKindMap; - // After the module header has been read, the FunctionsWithBodies list is - // reversed. This keeps track of whether we've done this yet. - bool HasReversedFunctionsWithBodies; + // Several operations happen after the module header has been read, but + // before function bodies are processed. This keeps track of whether + // we've done this yet. + bool SeenFirstFunctionBody; /// DeferredFunctionInfo - When function bodies are initially scanned, this /// map contains info about where to find deferred function body in the @@ -178,8 +182,13 @@ class BitcodeReader : public GVMaterializer { public: explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C) : Context(C), TheModule(0), Buffer(buffer), BufferOwned(false), - ErrorString(0), ValueList(C), MDValueList(C) { - HasReversedFunctionsWithBodies = false; + LazyStreamer(0), SeenValueSymbolTable(false), ErrorString(0), + ValueList(C), MDValueList(C), SeenFirstFunctionBody(false) { + } + explicit BitcodeReader(DataStreamer *streamer, LLVMContext &C) + : Context(C), TheModule(0), Buffer(0), BufferOwned(false), + LazyStreamer(streamer), SeenValueSymbolTable(false), ErrorString(0), + ValueList(C), MDValueList(C), SeenFirstFunctionBody(false) { } ~BitcodeReader() { FreeState(); @@ -258,7 +267,7 @@ private: } - bool ParseModule(); + bool ParseModule(bool Resume); bool ParseAttributeBlock(); bool ParseTypeTable(); bool ParseTypeTableBody(); @@ -267,11 +276,17 @@ private: bool ParseConstants(); bool RememberAndSkipFunctionBody(); bool ParseFunctionBody(Function *F); + bool GlobalCleanup(); bool ResolveGlobalAndAliasInits(); bool ParseMetadata(); bool ParseMetadataAttachment(); bool ParseModuleTriple(std::string &Triple); bool ParseUseLists(); + bool InitStream(); + bool InitStreamFromBuffer(); + bool InitLazyStream(); + bool FindFunctionInStream(Function *F, + DenseMap<Function*, uint64_t>::iterator DeferredFunctionInfoIterator); }; } // End llvm namespace diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 0e2f0ec783..0e8d3acfd8 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1738,11 +1738,6 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream) { // Emit metadata. WriteModuleMetadata(M, VE, Stream); - // Emit function bodies. - for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) - if (!F->isDeclaration()) - WriteFunction(*F, VE, Stream); - // Emit metadata. WriteModuleMetadataStore(M, Stream); @@ -1753,6 +1748,11 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream) { if (EnablePreserveUseListOrdering) WriteModuleUseLists(M, VE, Stream); + // Emit function bodies. + for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) + if (!F->isDeclaration()) + WriteFunction(*F, VE, Stream); + Stream.ExitBlock(); } diff --git a/lib/MC/MCDisassembler/Disassembler.cpp b/lib/MC/MCDisassembler/Disassembler.cpp index 9eb99d28e7..dee576ef3b 100644 --- a/lib/MC/MCDisassembler/Disassembler.cpp +++ b/lib/MC/MCDisassembler/Disassembler.cpp @@ -100,9 +100,9 @@ public: Bytes(bytes), Size(size), BasePC(basePC) {} uint64_t getBase() const { return BasePC; } - uint64_t getExtent() const { return Size; } + uint64_t getExtent() { return Size; } - int readByte(uint64_t Addr, uint8_t *Byte) const { + int readByte(uint64_t Addr, uint8_t *Byte) { if (Addr - BasePC >= Size) return -1; *Byte = Bytes[Addr - BasePC]; diff --git a/lib/MC/MCDisassembler/EDDisassembler.cpp b/lib/MC/MCDisassembler/EDDisassembler.cpp index c7221d86a8..9edf50579e 100644 --- a/lib/MC/MCDisassembler/EDDisassembler.cpp +++ b/lib/MC/MCDisassembler/EDDisassembler.cpp @@ -207,8 +207,8 @@ namespace { void *arg) : Callback(callback), Arg(arg) { } ~EDMemoryObject() { } uint64_t getBase() const { return 0x0; } - uint64_t getExtent() const { return (uint64_t)-1; } - int readByte(uint64_t address, uint8_t *ptr) const { + uint64_t getExtent() { return (uint64_t)-1; } + int readByte(uint64_t address, uint8_t *ptr) { if (!Callback) return -1; diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 322d32f876..6cec47df67 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -16,6 +16,7 @@ add_llvm_library(LLVMSupport ConstantRange.cpp CrashRecoveryContext.cpp DataExtractor.cpp + DataStream.cpp Debug.cpp DeltaAlgorithm.cpp DAGDeltaAlgorithm.cpp @@ -42,6 +43,7 @@ add_llvm_library(LLVMSupport SmallVector.cpp SourceMgr.cpp Statistic.cpp + StreamableMemoryObject.cpp StringExtras.cpp StringMap.cpp StringPool.cpp diff --git a/lib/Support/DataStream.cpp b/lib/Support/DataStream.cpp new file mode 100644 index 0000000000..fa8edc729c --- /dev/null +++ b/lib/Support/DataStream.cpp @@ -0,0 +1,96 @@ +//===--- llvm/Support/DataStream.cpp - Lazy streamed Data ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements DataStreamer, which fetches bytes of Data from +// a stream source. It provides support for streaming (lazy reading) of +// bitcode. An example implementation of streaming from a file or stdin +// is included. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "Data-stream" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/DataStream.h" +#include "llvm/Support/system_error.h" +#include <string> +#include <cerrno> +#include <cstdio> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif +#include <fcntl.h> +using namespace llvm; + +// Interface goals: +// * StreamableMemoryObject doesn't care about complexities like using +// threads/async callbacks to actually overlap download+compile +// * Don't want to duplicate Data in memory +// * Don't need to know total Data len in advance +// Non-goals: +// StreamableMemoryObject already has random access so this interface only does +// in-order streaming (no arbitrary seeking, else we'd have to buffer all the +// Data here in addition to MemoryObject). This also means that if we want +// to be able to to free Data, BitstreamBytes/BitcodeReader will implement it + +STATISTIC(NumStreamFetches, "Number of calls to Data stream fetch"); + +namespace llvm { +DataStreamer::~DataStreamer() {} +} + +namespace { + +const static error_code success; + +// Very simple stream backed by a file. Mostly useful for stdin and debugging; +// actual file access is probably still best done with mmap. +class DataFileStreamer : public DataStreamer { + int Fd; +public: + DataFileStreamer() : Fd(0) {} + virtual ~DataFileStreamer() { + close(Fd); + } + virtual size_t GetBytes(unsigned char *buf, size_t len) { + NumStreamFetches++; + return read(Fd, buf, len); + } + + error_code OpenFile(const std::string &Filename) { + int OpenFlags = O_RDONLY; +#ifdef O_BINARY + OpenFlags |= O_BINARY; // Open input file in binary mode on win32. +#endif + if (Filename == "-") + Fd = 0; + else + Fd = ::open(Filename.c_str(), OpenFlags); + if (Fd == -1) return error_code(errno, posix_category()); + return success; + } +}; + +} + +namespace llvm { +DataStreamer *getDataFileStreamer(const std::string &Filename, + std::string *StrError) { + DataFileStreamer *s = new DataFileStreamer(); + error_code e = s->OpenFile(Filename); + if (e != success) { + *StrError = std::string("Could not open ") + Filename + ": " + + e.message() + "\n"; + return NULL; + } + return s; +} + +} diff --git a/lib/Support/MemoryObject.cpp b/lib/Support/MemoryObject.cpp index b20ab89238..c82f46ae79 100644 --- a/lib/Support/MemoryObject.cpp +++ b/lib/Support/MemoryObject.cpp @@ -16,7 +16,7 @@ MemoryObject::~MemoryObject() { int MemoryObject::readBytes(uint64_t address, uint64_t size, uint8_t* buf, - uint64_t* copied) const { + uint64_t* copied) { uint64_t current = address; uint64_t limit = getBase() + getExtent(); diff --git a/lib/Support/StreamableMemoryObject.cpp b/lib/Support/StreamableMemoryObject.cpp new file mode 100644 index 0000000000..2b9d7adc44 --- /dev/null +++ b/lib/Support/StreamableMemoryObject.cpp @@ -0,0 +1,137 @@ +//===- StreamableMemoryObject.cpp - Streamable data interface - -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/StreamableMemoryObject.h" +#include <cassert> +#include <cstring> + + +using namespace llvm; + +namespace { + +class RawMemoryObject : public StreamableMemoryObject { +public: + RawMemoryObject(const unsigned char *Start, const unsigned char *End) : + FirstChar(Start), LastChar(End) { + assert(LastChar > FirstChar && "Invalid start/end range"); + } + + virtual uint64_t getBase() const { return 0; } + virtual uint64_t getExtent() { return LastChar - FirstChar; } + virtual int readByte(uint64_t address, uint8_t* ptr); + virtual int readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied); + virtual const uint8_t *getPointer(uint64_t address, uint64_t size); + virtual bool isValidAddress(uint64_t address) {return validAddress(address);} + virtual bool isObjectEnd(uint64_t address) {return objectEnd(address);} + +private: + const uint8_t* const FirstChar; + const uint8_t* const LastChar; + + // These are implemented as inline functions here to avoid multiple virtual + // calls per public function + bool validAddress(uint64_t address) { + return static_cast<ptrdiff_t>(address) < LastChar - FirstChar; + } + bool objectEnd(uint64_t address) { + return static_cast<ptrdiff_t>(address) == LastChar - FirstChar; + } + + RawMemoryObject(const RawMemoryObject&); // DO NOT IMPLEMENT + void operator=(const RawMemoryObject&); // DO NOT IMPLEMENT +}; + +int RawMemoryObject::readByte(uint64_t address, uint8_t* ptr) { + if (!validAddress(address)) return -1; + *ptr = *((uint8_t *)(uintptr_t)(address + FirstChar)); + return 0; +} + +int RawMemoryObject::readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied) { + if (!validAddress(address) || !validAddress(address + size - 1)) return -1; + memcpy(buf, (uint8_t *)(uintptr_t)(address + FirstChar), size); + if (copied) *copied = size; + return size; +} + +const uint8_t *RawMemoryObject::getPointer(uint64_t address, uint64_t size) { + return FirstChar + address; +} +} // anonymous namespace + +namespace llvm { +// If the bitcode has a header, then its size is known, and we don't have to +// block until we actually want to read it. +bool StreamingMemoryObject::isValidAddress(uint64_t address) { + if (ObjectSize && address < ObjectSize) return true; + return fetchToPos(address); +} + +bool StreamingMemoryObject::isObjectEnd(uint64_t address) { + if (ObjectSize) return address == ObjectSize; + fetchToPos(address); + return address == ObjectSize && address != 0; +} + +uint64_t StreamingMemoryObject::getExtent() { + if (ObjectSize) return ObjectSize; + size_t pos = BytesRead + kChunkSize; + // keep fetching until we run out of bytes + while (fetchToPos(pos)) pos += kChunkSize; + return ObjectSize; +} + +int StreamingMemoryObject::readByte(uint64_t address, uint8_t* ptr) { + if (!fetchToPos(address)) return -1; + *ptr = Bytes[address + BytesSkipped]; + return 0; +} + +int StreamingMemoryObject::readBytes(uint64_t address, + uint64_t size, + uint8_t* buf, + uint64_t* copied) { + if (!fetchToPos(address + size - 1)) return -1; + memcpy(buf, &Bytes[address + BytesSkipped], size); + if (copied) *copied = size; + return 0; +} + +bool StreamingMemoryObject::dropLeadingBytes(size_t s) { + if (BytesRead < s) return true; + BytesSkipped = s; + BytesRead -= s; + return false; +} + +void StreamingMemoryObject::setKnownObjectSize(size_t size) { + ObjectSize = size; + Bytes.reserve(size); +} + +StreamableMemoryObject *getNonStreamedMemoryObject( + const unsigned char *Start, const unsigned char *End) { + return new RawMemoryObject(Start, End); +} + +StreamableMemoryObject::~StreamableMemoryObject() { } + +StreamingMemoryObject::StreamingMemoryObject(DataStreamer *streamer) : + Bytes(kChunkSize), Streamer(streamer), BytesRead(0), BytesSkipped(0), + ObjectSize(0), EOFReached(false) { + BytesRead = streamer->GetBytes(&Bytes[0], kChunkSize); +} +} diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index c5d2ea2ca5..222cb30ac7 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -46,7 +46,7 @@ public: /// getInstruction - See MCDisassembler. DecodeStatus getInstruction(MCInst &instr, uint64_t &size, - const MemoryObject ®ion, + MemoryObject ®ion, uint64_t address, raw_ostream &vStream, raw_ostream &cStream) const; @@ -71,7 +71,7 @@ public: /// getInstruction - See MCDisassembler. DecodeStatus getInstruction(MCInst &instr, uint64_t &size, - const MemoryObject ®ion, + MemoryObject ®ion, uint64_t address, raw_ostream &vStream, raw_ostream &cStream) const; @@ -341,7 +341,7 @@ EDInstInfo *ThumbDisassembler::getEDInfo() const { } DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size, - const MemoryObject &Region, + MemoryObject &Region, uint64_t Address, raw_ostream &os, raw_ostream &cs) const { @@ -691,7 +691,7 @@ void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const { } DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size, - const MemoryObject &Region, + MemoryObject &Region, uint64_t Address, raw_ostream &os, raw_ostream &cs) const { diff --git a/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp b/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp index ccc3a05f50..269219a606 100644 --- a/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp +++ b/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp @@ -502,7 +502,7 @@ EDInstInfo *MBlazeDisassembler::getEDInfo() const { MCDisassembler::DecodeStatus MBlazeDisassembler::getInstruction(MCInst &instr, uint64_t &size, - const MemoryObject ®ion, + MemoryObject ®ion, uint64_t address, raw_ostream &vStream, raw_ostream &cStream) const { diff --git a/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h b/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h index 16943826fc..5aec8bcb6a 100644 --- a/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h +++ b/lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h @@ -40,7 +40,7 @@ public: /// getInstruction - See MCDisassembler. MCDisassembler::DecodeStatus getInstruction(MCInst &instr, uint64_t &size, - const MemoryObject ®ion, + MemoryObject ®ion, uint64_t address, raw_ostream &vStream, raw_ostream &cStream) const; diff --git a/lib/Target/X86/Disassembler/X86Disassembler.cpp b/lib/Target/X86/Disassembler/X86Disassembler.cpp index eda5206a32..f57075f105 100644 --- a/lib/Target/X86/Disassembler/X86Disassembler.cpp +++ b/lib/Target/X86/Disassembler/X86Disassembler.cpp @@ -112,7 +112,7 @@ static void logger(void* arg, const char* log) { MCDisassembler::DecodeStatus X86GenericDisassembler::getInstruction(MCInst &instr, uint64_t &size, - const MemoryObject ®ion, + MemoryObject ®ion, uint64_t address, raw_ostream &vStream, raw_ostream &cStream) const { diff --git a/lib/Target/X86/Disassembler/X86Disassembler.h b/lib/Target/X86/Disassembler/X86Disassembler.h index 38c7084672..588a81a0fc 100644 --- a/lib/Target/X86/Disassembler/X86Disassembler.h +++ b/lib/Target/X86/Disassembler/X86Disassembler.h @@ -114,7 +114,7 @@ public: /// getInstruction - See MCDisassembler. DecodeStatus getInstruction(MCInst &instr, uint64_t &size, - const MemoryObject ®ion, + MemoryObject ®ion, uint64_t address, raw_ostream &vStream, raw_ostream &cStream) const; |