| Index: lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
|
| diff --git a/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d356985c8e51ed97cf536a086969d964243dd464
|
| --- /dev/null
|
| +++ b/lib/Bitcode/NaCl/Reader/NaClBitcodeReader.cpp
|
| @@ -0,0 +1,1944 @@
|
| +//===- NaClBitcodeReader.cpp ----------------------------------------------===//
|
| +// Internal NaClBitcodeReader implementation
|
| +//
|
| +// The LLVM Compiler Infrastructure
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#define DEBUG_TYPE "NaClBitcodeReader"
|
| +
|
| +#include "NaClBitcodeReader.h"
|
| +#include "llvm/ADT/SmallString.h"
|
| +#include "llvm/ADT/SmallVector.h"
|
| +#include "llvm/Analysis/NaCl/PNaClABITypeChecker.h"
|
| +#include "llvm/Bitcode/NaCl/NaClBitcodeDecoders.h"
|
| +#include "llvm/Bitcode/NaCl/NaClReaderWriter.h"
|
| +#include "llvm/IR/AutoUpgrade.h"
|
| +#include "llvm/IR/Constants.h"
|
| +#include "llvm/IR/DerivedTypes.h"
|
| +#include "llvm/IR/InlineAsm.h"
|
| +#include "llvm/IR/IntrinsicInst.h"
|
| +#include "llvm/IR/Module.h"
|
| +#include "llvm/IR/OperandTraits.h"
|
| +#include "llvm/IR/Operator.h"
|
| +#include "llvm/Support/DataStream.h"
|
| +#include "llvm/Support/Debug.h"
|
| +#include "llvm/Support/MathExtras.h"
|
| +#include "llvm/Support/MemoryBuffer.h"
|
| +#include "llvm/Support/raw_ostream.h"
|
| +using namespace llvm;
|
| +
|
| +
|
| +cl::opt<bool>
|
| +llvm::PNaClAllowLocalSymbolTables(
|
| + "allow-local-symbol-tables",
|
| + cl::desc("Allow (function) local symbol tables in PNaCl bitcode files"),
|
| + cl::init(false));
|
| +
|
| +void NaClBitcodeReader::FreeState() {
|
| + std::vector<Type*>().swap(TypeList);
|
| + ValueList.clear();
|
| +
|
| + std::vector<Function*>().swap(FunctionsWithBodies);
|
| + DeferredFunctionInfo.clear();
|
| +}
|
| +
|
| +//===----------------------------------------------------------------------===//
|
| +// Helper functions to implement forward reference resolution, etc.
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +/// ConvertToString - Convert a string from a record into an std::string, return
|
| +/// true on failure.
|
| +template<typename StrTy>
|
| +static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx,
|
| + StrTy &Result) {
|
| + if (Idx > Record.size())
|
| + return true;
|
| +
|
| + for (unsigned i = Idx, e = Record.size(); i != e; ++i)
|
| + Result += (char)Record[i];
|
| + return false;
|
| +}
|
| +
|
| +void NaClBitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) {
|
| + assert(V);
|
| + if (Idx == size()) {
|
| + push_back(V);
|
| + return;
|
| + }
|
| +
|
| + if (Idx >= size())
|
| + resize(Idx+1);
|
| +
|
| + WeakVH &OldV = ValuePtrs[Idx];
|
| + if (OldV == 0) {
|
| + OldV = V;
|
| + return;
|
| + }
|
| +
|
| + // If there was a forward reference to this value, replace it.
|
| + Value *PrevVal = OldV;
|
| + OldV->replaceAllUsesWith(V);
|
| + delete PrevVal;
|
| +}
|
| +
|
| +void NaClBitcodeReaderValueList::OverwriteValue(Value *V, unsigned Idx) {
|
| + ValuePtrs[Idx] = V;
|
| +}
|
| +
|
| +Value *NaClBitcodeReaderValueList::getValueFwdRef(unsigned Idx) {
|
| + if (Idx >= size())
|
| + return 0;
|
| +
|
| + if (Value *V = ValuePtrs[Idx])
|
| + return V;
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +bool NaClBitcodeReaderValueList::createValueFwdRef(unsigned Idx, Type *Ty) {
|
| + if (Idx >= size())
|
| + resize(Idx + 1);
|
| +
|
| + // Return an error if this a duplicate definition of Idx.
|
| + if (ValuePtrs[Idx])
|
| + return true;
|
| +
|
| + // No type specified, must be invalid reference.
|
| + if (Ty == 0)
|
| + return true;
|
| +
|
| + // Create a placeholder, which will later be RAUW'd.
|
| + ValuePtrs[Idx] = new Argument(Ty);
|
| + return false;
|
| +}
|
| +
|
| +namespace {
|
| +class NaClBitcodeErrorCategoryType : public std::error_category {
|
| + const char *name() const LLVM_NOEXCEPT override {
|
| + return "pnacl.bitcode";
|
| + }
|
| + std::string message(int IndexError) const override {
|
| + switch(static_cast<NaClBitcodeReader::ErrorType>(IndexError)) {
|
| + case NaClBitcodeReader::CouldNotFindFunctionInStream:
|
| + return "Unable to find function in bitcode stream.";
|
| + case NaClBitcodeReader::InsufficientFunctionProtos:
|
| + return "Insufficient function protos";
|
| + case NaClBitcodeReader::InvalidBitstream:
|
| + return "Error in bitstream format";
|
| + case NaClBitcodeReader::InvalidBlock:
|
| + return "Invalid block found in bitcode file";
|
| + case NaClBitcodeReader::InvalidConstantReference:
|
| + return "Bad constant reference";
|
| + case NaClBitcodeReader::InvalidDataAfterModule:
|
| + return "Invalid data after module";
|
| + case NaClBitcodeReader::InvalidInstructionWithNoBB:
|
| + return "No basic block for instruction";
|
| + case NaClBitcodeReader::InvalidMultipleBlocks:
|
| + return "Multiple blocks for a kind of block that should have only one";
|
| + case NaClBitcodeReader::InvalidRecord:
|
| + return "Record doesn't have expected size or structure";
|
| + case NaClBitcodeReader::InvalidSkippedBlock:
|
| + return "Unable to skip unknown block in bitcode file";
|
| + case NaClBitcodeReader::InvalidType:
|
| + return "Invalid type in record";
|
| + case NaClBitcodeReader::InvalidTypeForValue:
|
| + return "Type of value in record incorrect";
|
| + case NaClBitcodeReader::InvalidValue:
|
| + return "Invalid value in record";
|
| + case NaClBitcodeReader::MalformedBlock:
|
| + return "Malformed block. Unable to advance over block";
|
| + }
|
| + llvm_unreachable("Unknown error type!");
|
| + }
|
| +};
|
| +} // end of anonomous namespace.
|
| +
|
| +const std::error_category &NaClBitcodeReader::BitcodeErrorCategory() {
|
| + static NaClBitcodeErrorCategoryType ErrCat;
|
| + return ErrCat;
|
| +}
|
| +
|
| +Type *NaClBitcodeReader::getTypeByID(unsigned ID) {
|
| + // The type table size is always specified correctly.
|
| + if (ID >= TypeList.size())
|
| + return 0;
|
| +
|
| + if (Type *Ty = TypeList[ID])
|
| + return Ty;
|
| +
|
| + // If we have a forward reference, the only possible case is when it is to a
|
| + // named struct. Just create a placeholder for now.
|
| + return TypeList[ID] = StructType::create(Context);
|
| +}
|
| +
|
| +
|
| +//===----------------------------------------------------------------------===//
|
| +// Functions for parsing blocks from the bitcode file
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +
|
| +namespace {
|
| +
|
| +static const unsigned MaxAlignmentExponent = 29;
|
| +static_assert(
|
| + (1u << MaxAlignmentExponent) == Value::MaximumAlignment,
|
| + "Inconsistency between Value.MaxAlignment and PNaCl alignment limit");
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::Error(ErrorType E,
|
| + const std::string &Message) const {
|
| + if (Verbose) {
|
| + uint64_t Bit = Stream.GetCurrentBitNo();
|
| + *Verbose << "Error: (" << (Bit / CHAR_BIT) << ":"
|
| + << static_cast<unsigned>(Bit % CHAR_BIT)
|
| + << ") " << Message << "\n";
|
| + }
|
| + return Error(E);
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::getAlignmentValue(
|
| + uint64_t Exponent, unsigned &Alignment) {
|
| + if (Exponent > MaxAlignmentExponent + 1) {
|
| + std::string Buffer;
|
| + raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Alignment can't be greater than 2**" << MaxAlignmentExponent
|
| + << ". Found: 2**" << (Exponent - 1);
|
| + return Error(InvalidValue, StrBuf.str());
|
| + }
|
| + Alignment = (1 << static_cast<unsigned>(Exponent)) >> 1;
|
| + return std::error_code();
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::ParseTypeTable() {
|
| + DEBUG(dbgs() << "-> ParseTypeTable\n");
|
| + if (Stream.EnterSubBlock(naclbitc::TYPE_BLOCK_ID_NEW))
|
| + return Error(InvalidRecord, "Malformed block record");
|
| +
|
| + std::error_code result = ParseTypeTableBody();
|
| + if (!result)
|
| + DEBUG(dbgs() << "<- ParseTypeTable\n");
|
| + return result;
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::ParseTypeTableBody() {
|
| + if (!TypeList.empty())
|
| + return Error(InvalidMultipleBlocks, "Multiple TYPE_BLOCKs found!");
|
| +
|
| + SmallVector<uint64_t, 64> Record;
|
| + unsigned NumRecords = 0;
|
| +
|
| + // Read all the records for this type table.
|
| + while (1) {
|
| + NaClBitstreamEntry Entry = Stream.advance(0, nullptr);
|
| +
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::SubBlock:
|
| + return Error(InvalidBlock, "Invalid block found in the types block");
|
| + case NaClBitstreamEntry::Error:
|
| + return Error(MalformedBlock, "Malformed types block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + if (NumRecords != TypeList.size())
|
| + return Error(MalformedBlock,
|
| + "Invalid forward reference in the types block");
|
| + return std::error_code();
|
| + case NaClBitstreamEntry::Record:
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + Record.clear();
|
| + Type *ResultTy = 0;
|
| + unsigned TypeCode = Stream.readRecord(Entry.ID, Record);
|
| + switch (TypeCode) {
|
| + default: {
|
| + std::string Message;
|
| + raw_string_ostream StrM(Message);
|
| + StrM << "Unknown type code in type table: " << TypeCode;
|
| + StrM.flush();
|
| + return Error(InvalidValue, Message);
|
| + }
|
| +
|
| + case naclbitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries]
|
| + // TYPE_CODE_NUMENTRY contains a count of the number of types in the
|
| + // type list. This allows us to reserve space.
|
| + if (Record.size() != 1)
|
| + return Error(InvalidRecord, "Invalid TYPE_CODE_NUMENTRY record");
|
| + TypeList.resize(Record[0]);
|
| + // No type was defined, skip the checks that follow the switch.
|
| + continue;
|
| +
|
| + case naclbitc::TYPE_CODE_VOID: // VOID
|
| + if (Record.size() != 0)
|
| + return Error(InvalidRecord, "Invalid TYPE_CODE_VOID record");
|
| + ResultTy = Type::getVoidTy(Context);
|
| + break;
|
| +
|
| + case naclbitc::TYPE_CODE_FLOAT: // FLOAT
|
| + if (Record.size() != 0)
|
| + return Error(InvalidRecord, "Invalid TYPE_CODE_FLOAT record");
|
| + ResultTy = Type::getFloatTy(Context);
|
| + break;
|
| +
|
| + case naclbitc::TYPE_CODE_DOUBLE: // DOUBLE
|
| + if (Record.size() != 0)
|
| + return Error(InvalidRecord, "Invalid TYPE_CODE_DOUBLE record");
|
| + ResultTy = Type::getDoubleTy(Context);
|
| + break;
|
| +
|
| + case naclbitc::TYPE_CODE_INTEGER: // INTEGER: [width]
|
| + if (Record.size() != 1)
|
| + return Error(InvalidRecord, "Invalid TYPE_CODE_INTEGER record");
|
| + ResultTy = IntegerType::get(Context, Record[0]);
|
| + break;
|
| +
|
| + case naclbitc::TYPE_CODE_FUNCTION: {
|
| + // FUNCTION: [vararg, retty, paramty x N]
|
| + if (Record.size() < 2)
|
| + return Error(InvalidRecord, "Invalid TYPE_CODE_FUNCTION record");
|
| + SmallVector<Type *, 8> ArgTys;
|
| + for (unsigned i = 2, e = Record.size(); i != e; ++i) {
|
| + if (Type *T = getTypeByID(Record[i]))
|
| + ArgTys.push_back(T);
|
| + else
|
| + break;
|
| + }
|
| +
|
| + ResultTy = getTypeByID(Record[1]);
|
| + if (ResultTy == 0 || ArgTys.size() < Record.size() - 2)
|
| + return Error(InvalidType, "invalid type in function type");
|
| +
|
| + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
|
| + break;
|
| + }
|
| + case naclbitc::TYPE_CODE_VECTOR: { // VECTOR: [numelts, eltty]
|
| + if (Record.size() != 2)
|
| + return Error(InvalidRecord, "Invalid VECTOR type record");
|
| + if ((ResultTy = getTypeByID(Record[1])))
|
| + ResultTy = VectorType::get(ResultTy, Record[0]);
|
| + else
|
| + return Error(InvalidType, "invalid type in vector type");
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (NumRecords >= TypeList.size())
|
| + return Error(MalformedBlock, "invalid TYPE table");
|
| + assert(ResultTy && "Didn't read a type?");
|
| + assert(TypeList[NumRecords] == 0 && "Already read type?");
|
| + TypeList[NumRecords++] = ResultTy;
|
| + }
|
| + return std::error_code();
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +// Class to process globals in two passes. In the first pass, build
|
| +// the corresponding global variables with no initializers. In the
|
| +// second pass, add initializers. The purpose of putting off
|
| +// initializers is to make sure that we don't need to generate
|
| +// placeholders for relocation records, and the corresponding cost
|
| +// of duplicating initializers when these placeholders are replaced.
|
| +class ParseGlobalsHandler {
|
| + ParseGlobalsHandler(const ParseGlobalsHandler &H) LLVM_DELETED_FUNCTION;
|
| + void operator=(const ParseGlobalsHandler &H) LLVM_DELETED_FUNCTION;
|
| +
|
| + NaClBitcodeReader &Reader;
|
| + NaClBitcodeReaderValueList &ValueList;
|
| + NaClBitstreamCursor &Stream;
|
| + LLVMContext &Context;
|
| + Module *TheModule;
|
| +
|
| + // Holds read data record.
|
| + SmallVector<uint64_t, 64> Record;
|
| + // True when processing a global variable. Stays true until all records
|
| + // are processed, and the global variable is created.
|
| + bool ProcessingGlobal;
|
| + // The number of initializers needed for the global variable.
|
| + unsigned VarInitializersNeeded ;
|
| + unsigned FirstValueNo;
|
| + // The index of the next global variable.
|
| + unsigned NextValueNo;
|
| + // The number of expected global variable definitions.
|
| + unsigned NumGlobals;
|
| + // The bit to go back to to generate initializers.
|
| + uint64_t StartBit;
|
| +
|
| + void InitPass() {
|
| + Stream.JumpToBit(StartBit);
|
| + ProcessingGlobal = false;
|
| + VarInitializersNeeded = 0;
|
| + NextValueNo = FirstValueNo;
|
| + }
|
| +
|
| +public:
|
| + ParseGlobalsHandler(NaClBitcodeReader &Reader,
|
| + NaClBitcodeReaderValueList &ValueList,
|
| + NaClBitstreamCursor &Stream,
|
| + LLVMContext &Context,
|
| + Module *TheModule)
|
| + : Reader(Reader),
|
| + ValueList(ValueList),
|
| + Stream(Stream),
|
| + Context(Context),
|
| + TheModule(TheModule),
|
| + FirstValueNo(ValueList.size()),
|
| + NumGlobals(0),
|
| + StartBit(Stream.GetCurrentBitNo()) {}
|
| +
|
| + std::error_code GenerateGlobalVarsPass() {
|
| + InitPass();
|
| +
|
| + // The type for the initializer of the global variable.
|
| + SmallVector<Type*, 10> VarType;
|
| + // The alignment value defined for the global variable.
|
| + unsigned VarAlignment = 0;
|
| + // True if the variable is read-only.
|
| + bool VarIsConstant = false;
|
| +
|
| + // Read all records to build global variables without initializers.
|
| + while (1) {
|
| + NaClBitstreamEntry Entry =
|
| + Stream.advance(NaClBitstreamCursor::AF_DontPopBlockAtEnd, nullptr);
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::SubBlock:
|
| + return Reader.Error(NaClBitcodeReader::InvalidBlock,
|
| + "Invalid block in the global vars block");
|
| + case NaClBitstreamEntry::Error:
|
| + return Reader.Error(NaClBitcodeReader::MalformedBlock,
|
| + "Error in the global vars block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + if (ProcessingGlobal || NumGlobals != (NextValueNo - FirstValueNo))
|
| + return Reader.Error(NaClBitcodeReader::MalformedBlock,
|
| + "Error in the global vars block");
|
| + return std::error_code();
|
| + case NaClBitstreamEntry::Record:
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + Record.clear();
|
| + unsigned Bitcode = Stream.readRecord(Entry.ID, Record);
|
| + switch (Bitcode) {
|
| + default:
|
| + return Reader.Error(NaClBitcodeReader::InvalidValue,
|
| + "Unknown global variable entry");
|
| + case naclbitc::GLOBALVAR_VAR:
|
| + // Start the definition of a global variable.
|
| + if (ProcessingGlobal || Record.size() != 2)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_VAR record");
|
| + ProcessingGlobal = true;
|
| + if (std::error_code EC =
|
| + Reader.getAlignmentValue(Record[0], VarAlignment))
|
| + return EC;
|
| + VarIsConstant = Record[1] != 0;
|
| + // Assume (by default) there is a single initializer.
|
| + VarInitializersNeeded = 1;
|
| + break;
|
| + case naclbitc::GLOBALVAR_COMPOUND:
|
| + // Global variable has multiple initializers. Changes the
|
| + // default number of initializers to the given value in
|
| + // Record[0].
|
| + if (!ProcessingGlobal || !VarType.empty() ||
|
| + VarInitializersNeeded != 1 || Record.size() != 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_COMPOUND record");
|
| + VarInitializersNeeded = Record[0];
|
| + break;
|
| + case naclbitc::GLOBALVAR_ZEROFILL: {
|
| + // Define a type that defines a sequence of zero-filled bytes.
|
| + if (!ProcessingGlobal || Record.size() != 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_ZEROFILL record");
|
| + VarType.push_back(ArrayType::get(
|
| + Type::getInt8Ty(Context), Record[0]));
|
| + break;
|
| + }
|
| + case naclbitc::GLOBALVAR_DATA: {
|
| + // Defines a type defined by a sequence of byte values.
|
| + if (!ProcessingGlobal || Record.size() < 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_DATA record");
|
| + VarType.push_back(ArrayType::get(
|
| + Type::getInt8Ty(Context), Record.size()));
|
| + break;
|
| + }
|
| + case naclbitc::GLOBALVAR_RELOC: {
|
| + // Define a relocation initializer type.
|
| + if (!ProcessingGlobal || Record.size() < 1 || Record.size() > 2)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_RELOC record");
|
| + VarType.push_back(IntegerType::get(Context, 32));
|
| + break;
|
| + }
|
| + case naclbitc::GLOBALVAR_COUNT:
|
| + if (Record.size() != 1 || NumGlobals != 0)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Invalid global count record");
|
| + NumGlobals = Record[0];
|
| + break;
|
| + }
|
| +
|
| + // If more initializers needed for global variable, continue processing.
|
| + if (!ProcessingGlobal || VarType.size() < VarInitializersNeeded)
|
| + continue;
|
| +
|
| + Type *Ty = 0;
|
| + switch (VarType.size()) {
|
| + case 0:
|
| + return Reader.Error(
|
| + NaClBitcodeReader::InvalidRecord,
|
| + "No initializer for global variable in global vars block");
|
| + case 1:
|
| + Ty = VarType[0];
|
| + break;
|
| + default:
|
| + Ty = StructType::get(Context, VarType, true);
|
| + break;
|
| + }
|
| + GlobalVariable *GV = new GlobalVariable(
|
| + *TheModule, Ty, VarIsConstant,
|
| + GlobalValue::InternalLinkage, NULL, "");
|
| + GV->setAlignment(VarAlignment);
|
| + ValueList.AssignValue(GV, NextValueNo);
|
| + ++NextValueNo;
|
| + ProcessingGlobal = false;
|
| + VarAlignment = 0;
|
| + VarIsConstant = false;
|
| + VarInitializersNeeded = 0;
|
| + VarType.clear();
|
| + }
|
| + return std::error_code();
|
| + }
|
| +
|
| + std::error_code GenerateGlobalVarInitsPass() {
|
| + InitPass();
|
| + // The initializer for the global variable.
|
| + SmallVector<Constant *, 10> VarInit;
|
| +
|
| + while (1) {
|
| + NaClBitstreamEntry Entry =
|
| + Stream.advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs, nullptr);
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::SubBlock:
|
| + return Reader.Error(NaClBitcodeReader::InvalidBlock,
|
| + "Invalid block in the global vars block");
|
| + case NaClBitstreamEntry::Error:
|
| + return Reader.Error(NaClBitcodeReader::MalformedBlock,
|
| + "Error in the global vars block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + if (ProcessingGlobal || NumGlobals != (NextValueNo - FirstValueNo))
|
| + return Reader.Error(NaClBitcodeReader::MalformedBlock,
|
| + "Error in the global vars block");
|
| + return std::error_code();
|
| + case NaClBitstreamEntry::Record:
|
| + if (Entry.ID == naclbitc::DEFINE_ABBREV) {
|
| + Stream.SkipAbbrevRecord();
|
| + continue;
|
| + }
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + Record.clear();
|
| + unsigned Bitcode = Stream.readRecord(Entry.ID, Record);
|
| + switch (Bitcode) {
|
| + default:
|
| + return Reader.Error(NaClBitcodeReader::InvalidValue,
|
| + "Unknown global variable entry 2");
|
| + case naclbitc::GLOBALVAR_VAR:
|
| + // Start the definition of a global variable.
|
| + ProcessingGlobal = true;
|
| + // Assume (by default) there is a single initializer.
|
| + VarInitializersNeeded = 1;
|
| + break;
|
| + case naclbitc::GLOBALVAR_COMPOUND:
|
| + // Global variable has multiple initializers. Changes the
|
| + // default number of initializers to the given value in
|
| + // Record[0].
|
| + if (!ProcessingGlobal || !VarInit.empty() ||
|
| + VarInitializersNeeded != 1 || Record.size() != 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_COMPOUND record");
|
| + VarInitializersNeeded = Record[0];
|
| + break;
|
| + case naclbitc::GLOBALVAR_ZEROFILL: {
|
| + // Define an initializer that defines a sequence of zero-filled bytes.
|
| + if (!ProcessingGlobal || Record.size() != 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_ZEROFILL record");
|
| + Type *Ty = ArrayType::get(Type::getInt8Ty(Context),
|
| + Record[0]);
|
| + Constant *Zero = ConstantAggregateZero::get(Ty);
|
| + VarInit.push_back(Zero);
|
| + break;
|
| + }
|
| + case naclbitc::GLOBALVAR_DATA: {
|
| + // Defines an initializer defined by a sequence of byte values.
|
| + if (!ProcessingGlobal || Record.size() < 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_DATA record");
|
| + unsigned Size = Record.size();
|
| + uint8_t *Buf = new uint8_t[Size];
|
| + assert(Buf);
|
| + for (unsigned i = 0; i < Size; ++i)
|
| + Buf[i] = Record[i];
|
| + Constant *Init = ConstantDataArray::get(
|
| + Context, ArrayRef<uint8_t>(Buf, Buf + Size));
|
| + VarInit.push_back(Init);
|
| + delete[] Buf;
|
| + break;
|
| + }
|
| + case naclbitc::GLOBALVAR_RELOC: {
|
| + // Define a relocation initializer.
|
| + if (!ProcessingGlobal || Record.size() < 1 || Record.size() > 2)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Bad GLOBALVAR_RELOC record");
|
| + Constant *BaseVal = cast<Constant>(ValueList[Record[0]]);
|
| + Type *IntPtrType = IntegerType::get(Context, 32);
|
| + Constant *Val = ConstantExpr::getPtrToInt(BaseVal, IntPtrType);
|
| + if (Record.size() == 2) {
|
| + uint32_t Addend = Record[1];
|
| + Val = ConstantExpr::getAdd(Val, ConstantInt::get(IntPtrType,
|
| + Addend));
|
| + }
|
| + VarInit.push_back(Val);
|
| + break;
|
| + }
|
| + case naclbitc::GLOBALVAR_COUNT:
|
| + if (Record.size() != 1)
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "Invalid global count record");
|
| + // Note: NumGlobals should have been set in GenerateGlobalVarsPass.
|
| + // Fail if methods are called in wrong order.
|
| + assert(NumGlobals == Record[0]);
|
| + break;
|
| + }
|
| +
|
| + // If more initializers needed for global variable, continue processing.
|
| + if (!ProcessingGlobal || VarInit.size() < VarInitializersNeeded)
|
| + continue;
|
| +
|
| + Constant *Init = 0;
|
| + switch (VarInit.size()) {
|
| + case 0:
|
| + return Reader.Error(NaClBitcodeReader::InvalidRecord,
|
| + "No initializer for global variable in global vars block");
|
| + case 1:
|
| + Init = VarInit[0];
|
| + break;
|
| + default:
|
| + Init = ConstantStruct::getAnon(Context, VarInit, true);
|
| + break;
|
| + }
|
| + cast<GlobalVariable>(ValueList[NextValueNo])->setInitializer(Init);
|
| + ++NextValueNo;
|
| + ProcessingGlobal = false;
|
| + VarInitializersNeeded = 0;
|
| + VarInit.clear();
|
| + }
|
| + return std::error_code();
|
| + }
|
| +};
|
| +
|
| +} // End anonymous namespace.
|
| +
|
| +std::error_code NaClBitcodeReader::ParseGlobalVars() {
|
| + if (Stream.EnterSubBlock(naclbitc::GLOBALVAR_BLOCK_ID))
|
| + return Error(InvalidRecord, "Malformed block record");
|
| +
|
| + ParseGlobalsHandler PassHandler(*this, ValueList, Stream, Context, TheModule);
|
| + if (std::error_code EC = PassHandler.GenerateGlobalVarsPass())
|
| + return EC;
|
| + return PassHandler.GenerateGlobalVarInitsPass();
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::ParseValueSymbolTable() {
|
| + DEBUG(dbgs() << "-> ParseValueSymbolTable\n");
|
| + if (Stream.EnterSubBlock(naclbitc::VALUE_SYMTAB_BLOCK_ID))
|
| + return Error(InvalidRecord, "Malformed block record");
|
| +
|
| + SmallVector<uint64_t, 64> Record;
|
| +
|
| + // Read all the records for this value table.
|
| + SmallString<128> ValueName;
|
| + while (1) {
|
| + NaClBitstreamEntry Entry = Stream.advance(0, nullptr);
|
| +
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::SubBlock:
|
| + return Error(InvalidBlock,
|
| + "Invalid block in the value symbol table block");
|
| + case NaClBitstreamEntry::Error:
|
| + return Error(MalformedBlock, "malformed value symbol table block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + DEBUG(dbgs() << "<- ParseValueSymbolTable\n");
|
| + return std::error_code();
|
| + case NaClBitstreamEntry::Record:
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + Record.clear();
|
| + switch (Stream.readRecord(Entry.ID, Record)) {
|
| + default: // Default behavior: unknown type.
|
| + break;
|
| + case naclbitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N]
|
| + if (ConvertToString(Record, 1, ValueName))
|
| + return Error(InvalidRecord, "Invalid VST_ENTRY record");
|
| + unsigned ValueID = Record[0];
|
| + if (ValueID >= ValueList.size())
|
| + return Error(InvalidValue, "Invalid Value ID in VST_ENTRY record");
|
| + Value *V = ValueList[ValueID];
|
| +
|
| + V->setName(StringRef(ValueName.data(), ValueName.size()));
|
| + ValueName.clear();
|
| + break;
|
| + }
|
| + case naclbitc::VST_CODE_BBENTRY: {
|
| + if (ConvertToString(Record, 1, ValueName))
|
| + return Error(InvalidRecord, "Invalid VST_BBENTRY record");
|
| + BasicBlock *BB = getBasicBlock(Record[0]);
|
| + if (BB == 0)
|
| + return Error(InvalidValue, "Invalid BB ID in VST_BBENTRY record");
|
| +
|
| + BB->setName(StringRef(ValueName.data(), ValueName.size()));
|
| + ValueName.clear();
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::ParseConstants() {
|
| + DEBUG(dbgs() << "-> ParseConstants\n");
|
| + if (Stream.EnterSubBlock(naclbitc::CONSTANTS_BLOCK_ID))
|
| + return Error(InvalidRecord, "Malformed block record");
|
| +
|
| + SmallVector<uint64_t, 64> Record;
|
| +
|
| + // Read all the records for this value table.
|
| + Type *CurTy = Type::getInt32Ty(Context);
|
| + unsigned NextCstNo = ValueList.size();
|
| + while (1) {
|
| + NaClBitstreamEntry Entry = Stream.advance(0, nullptr);
|
| +
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::SubBlock:
|
| + return Error(InvalidBlock, "Invalid block in function constants block");
|
| + case NaClBitstreamEntry::Error:
|
| + return Error(MalformedBlock, "malformed function constants block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + if (NextCstNo != ValueList.size())
|
| + return Error(InvalidConstantReference,
|
| + "Invalid constant reference!");
|
| + DEBUG(dbgs() << "<- ParseConstants\n");
|
| + return std::error_code();
|
| + case NaClBitstreamEntry::Record:
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + Record.clear();
|
| + Value *V = 0;
|
| + unsigned BitCode = Stream.readRecord(Entry.ID, Record);
|
| + switch (BitCode) {
|
| + default: {
|
| + std::string Message;
|
| + raw_string_ostream StrM(Message);
|
| + StrM << "Invalid Constant code: " << BitCode;
|
| + StrM.flush();
|
| + return Error(InvalidValue, Message);
|
| + }
|
| + case naclbitc::CST_CODE_UNDEF: // UNDEF
|
| + V = UndefValue::get(CurTy);
|
| + break;
|
| + case naclbitc::CST_CODE_SETTYPE: // SETTYPE: [typeid]
|
| + if (Record.empty())
|
| + return Error(NaClBitcodeReader::InvalidRecord,
|
| + "Malformed CST_SETTYPE record");
|
| + if (Record[0] >= TypeList.size())
|
| + return Error(NaClBitcodeReader::InvalidType,
|
| + "Invalid Type ID in CST_SETTYPE record");
|
| + CurTy = TypeList[Record[0]];
|
| + continue; // Skip the ValueList manipulation.
|
| + case naclbitc::CST_CODE_INTEGER: // INTEGER: [intval]
|
| + if (!CurTy->isIntegerTy() || Record.empty())
|
| + return Error(InvalidRecord, "Invalid CST_INTEGER record");
|
| + V = ConstantInt::get(CurTy, NaClDecodeSignRotatedValue(Record[0]));
|
| + break;
|
| + case naclbitc::CST_CODE_FLOAT: { // FLOAT: [fpval]
|
| + if (Record.empty())
|
| + return Error(NaClBitcodeReader::InvalidRecord, "Invalid FLOAT record");
|
| + if (CurTy->isFloatTy())
|
| + V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle,
|
| + APInt(32, (uint32_t)Record[0])));
|
| + else if (CurTy->isDoubleTy())
|
| + V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble,
|
| + APInt(64, Record[0])));
|
| + else
|
| + return Error(NaClBitcodeReader::InvalidRecord,
|
| + "Unknown type for FLOAT record");
|
| + break;
|
| + }
|
| + }
|
| +
|
| + ValueList.AssignValue(V, NextCstNo);
|
| + ++NextCstNo;
|
| + }
|
| + return std::error_code();
|
| +}
|
| +
|
| +/// RememberAndSkipFunctionBody - When we see the block for a function body,
|
| +/// remember where it is and then skip it. This lets us lazily deserialize the
|
| +/// functions.
|
| +std::error_code NaClBitcodeReader::RememberAndSkipFunctionBody() {
|
| + DEBUG(dbgs() << "-> RememberAndSkipFunctionBody\n");
|
| + // Get the function we are talking about.
|
| + if (FunctionsWithBodies.empty())
|
| + return Error(InsufficientFunctionProtos,
|
| + "Insufficient function protos");
|
| +
|
| + Function *Fn = FunctionsWithBodies.back();
|
| + FunctionsWithBodies.pop_back();
|
| +
|
| + // Save the current stream state.
|
| + uint64_t CurBit = Stream.GetCurrentBitNo();
|
| + DeferredFunctionInfo[Fn] = CurBit;
|
| +
|
| + // Skip over the function block for now.
|
| + if (Stream.SkipBlock())
|
| + return Error(InvalidSkippedBlock, "Unable to skip function block.");
|
| + DEBUG(dbgs() << "<- RememberAndSkipFunctionBody\n");
|
| + return std::error_code();
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::GlobalCleanup() {
|
| + // 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);
|
| + return std::error_code();
|
| +}
|
| +
|
| +FunctionType *NaClBitcodeReader::AddPointerTypesToIntrinsicType(
|
| + StringRef Name, FunctionType *FTy) {
|
| + FunctionType *IntrinsicTy = AllowedIntrinsics.getIntrinsicType(Name);
|
| + if (IntrinsicTy == 0) return FTy;
|
| +
|
| + Type *IReturnTy = IntrinsicTy->getReturnType();
|
| + Type *FReturnTy = FTy->getReturnType();
|
| +
|
| + if (!PNaClABITypeChecker::IsPointerEquivType(IReturnTy, FReturnTy)) {
|
| + std::string Buffer;
|
| + raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Intrinsic return type mismatch for " << Name << ": "
|
| + << *IReturnTy << " and " << *FReturnTy;
|
| + report_fatal_error(StrBuf.str());
|
| + }
|
| + if (FTy->getNumParams() != IntrinsicTy->getNumParams()) {
|
| + std::string Buffer;
|
| + raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Intrinsic type mistmatch for " << Name << ": "
|
| + << *FTy << " and " << *IntrinsicTy;
|
| + report_fatal_error(StrBuf.str());
|
| + }
|
| + for (unsigned i = 0; i < FTy->getNumParams(); ++i) {
|
| + Type *IargTy = IntrinsicTy->getParamType(i);
|
| + Type *FargTy = FTy->getParamType(i);
|
| + if (!PNaClABITypeChecker::IsPointerEquivType(IargTy, FargTy)) {
|
| + std::string Buffer;
|
| + raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Intrinsic type mismatch for argument " << i << " in "
|
| + << Name << ": " << *IargTy << " and " << *FargTy;
|
| + report_fatal_error(StrBuf.str());
|
| + }
|
| + }
|
| + return IntrinsicTy;
|
| +}
|
| +
|
| +void NaClBitcodeReader::AddPointerTypesToIntrinsicParams() {
|
| + for (unsigned Index = 0, E = ValueList.size(); Index < E; ++Index) {
|
| + if (Function *Func = dyn_cast<Function>(ValueList[Index])) {
|
| + if (Func->isIntrinsic()) {
|
| + FunctionType *FTy = Func->getFunctionType();
|
| + FunctionType *ITy = AddPointerTypesToIntrinsicType(
|
| + Func->getName(), FTy);
|
| + if (ITy == FTy) continue;
|
| + Function *NewIntrinsic = Function::Create(
|
| + ITy, GlobalValue::ExternalLinkage, "", TheModule);
|
| + NewIntrinsic->takeName(Func);
|
| + ValueList.OverwriteValue(NewIntrinsic, Index);
|
| + Func->eraseFromParent();
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::ParseModule(bool Resume) {
|
| + DEBUG(dbgs() << "-> ParseModule\n");
|
| + if (Resume)
|
| + Stream.JumpToBit(NextUnreadBit);
|
| + else if (Stream.EnterSubBlock(naclbitc::MODULE_BLOCK_ID))
|
| + return Error(InvalidRecord, "Malformed block record");
|
| +
|
| + SmallVector<uint64_t, 64> Record;
|
| +
|
| + // Read all the records for this module.
|
| + while (1) {
|
| + NaClBitstreamEntry Entry = Stream.advance(0, nullptr);
|
| +
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::Error:
|
| + return Error(MalformedBlock, "malformed module block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + DEBUG(dbgs() << "<- ParseModule\n");
|
| + if (std::error_code EC = GlobalCleanup())
|
| + return EC;
|
| + if (!Stream.AtEndOfStream())
|
| + return Error(InvalidDataAfterModule, "Invalid data after module");
|
| + return std::error_code();
|
| + case NaClBitstreamEntry::SubBlock:
|
| + switch (Entry.ID) {
|
| + default: {
|
| + std::string Message;
|
| + raw_string_ostream StrM(Message);
|
| + StrM << "Unknown block ID: " << Entry.ID;
|
| + return Error(InvalidRecord, StrM.str());
|
| + }
|
| + case naclbitc::BLOCKINFO_BLOCK_ID:
|
| + if (Stream.ReadBlockInfoBlock(0))
|
| + return Error(MalformedBlock, "Malformed BlockInfoBlock");
|
| + break;
|
| + case naclbitc::TYPE_BLOCK_ID_NEW:
|
| + if (std::error_code EC = ParseTypeTable())
|
| + return EC;
|
| + break;
|
| + case naclbitc::GLOBALVAR_BLOCK_ID:
|
| + if (std::error_code EC = ParseGlobalVars())
|
| + return EC;
|
| + break;
|
| + case naclbitc::VALUE_SYMTAB_BLOCK_ID:
|
| + if (std::error_code EC = ParseValueSymbolTable())
|
| + return EC;
|
| + SeenValueSymbolTable = true;
|
| + // Now that we know the names of the intrinsics, we can add
|
| + // pointer types to the intrinsic declarations' types.
|
| + AddPointerTypesToIntrinsicParams();
|
| + break;
|
| + case naclbitc::FUNCTION_BLOCK_ID:
|
| + // If this is the first function body we've seen, reverse the
|
| + // FunctionsWithBodies list.
|
| + if (!SeenFirstFunctionBody) {
|
| + std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end());
|
| + if (std::error_code EC = GlobalCleanup())
|
| + return EC;
|
| + SeenFirstFunctionBody = true;
|
| + }
|
| +
|
| + if (std::error_code EC = RememberAndSkipFunctionBody())
|
| + return EC;
|
| +
|
| + // 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();
|
| + DEBUG(dbgs() << "<- ParseModule\n");
|
| + return std::error_code();
|
| + }
|
| + break;
|
| + }
|
| + continue;
|
| +
|
| + case NaClBitstreamEntry::Record:
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + unsigned Selector = Stream.readRecord(Entry.ID, Record);
|
| + switch (Selector) {
|
| + default: {
|
| + std::string Message;
|
| + raw_string_ostream StrM(Message);
|
| + StrM << "Invalid MODULE_CODE: " << Selector;
|
| + StrM.flush();
|
| + return Error(InvalidValue, Message);
|
| + }
|
| + case naclbitc::MODULE_CODE_VERSION: { // VERSION: [version#]
|
| + if (Record.size() < 1)
|
| + return Error(InvalidRecord, "Malformed MODULE_CODE_VERSION");
|
| + // Only version #1 is supported for PNaCl. Version #0 is not supported.
|
| + unsigned module_version = Record[0];
|
| + if (module_version != 1)
|
| + return Error(InvalidValue, "Unknown bitstream version!");
|
| + break;
|
| + }
|
| + // FUNCTION: [type, callingconv, isproto, linkage]
|
| + case naclbitc::MODULE_CODE_FUNCTION: {
|
| + if (Record.size() < 4)
|
| + return Error(InvalidRecord, "Invalid MODULE_CODE_FUNCTION record");
|
| + Type *Ty = getTypeByID(Record[0]);
|
| + if (!Ty)
|
| + return Error(InvalidType, "Invalid MODULE_CODE_FUNCTION record");
|
| + FunctionType *FTy = dyn_cast<FunctionType>(Ty);
|
| + if (!FTy)
|
| + return Error(InvalidType,
|
| + "Function not declared with a function type!");
|
| +
|
| + Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage,
|
| + "", TheModule);
|
| +
|
| + CallingConv::ID CallingConv;
|
| + if (!naclbitc::DecodeCallingConv(Record[1], CallingConv))
|
| + return Error(InvalidValue,
|
| + "PNaCl bitcode contains invalid calling conventions.");
|
| + Func->setCallingConv(CallingConv);
|
| + bool isProto = Record[2];
|
| + GlobalValue::LinkageTypes Linkage;
|
| + if (!naclbitc::DecodeLinkage(Record[3], Linkage))
|
| + return Error(InvalidValue, "Unknown linkage type");
|
| + Func->setLinkage(Linkage);
|
| + ValueList.push_back(Func);
|
| +
|
| + // 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) {
|
| + Func->setIsMaterializable(true);
|
| + FunctionsWithBodies.push_back(Func);
|
| + if (LazyStreamer) DeferredFunctionInfo[Func] = 0;
|
| + }
|
| + break;
|
| + }
|
| + }
|
| + Record.clear();
|
| + }
|
| + return std::error_code();
|
| +}
|
| +
|
| +const char *llvm::PNaClDataLayout =
|
| + "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
|
| + "f32:32:32-f64:64:64-p:32:32:32-v128:32:32";
|
| +
|
| +std::error_code NaClBitcodeReader::ParseBitcodeInto(Module *M) {
|
| + TheModule = 0;
|
| +
|
| + // PNaCl does not support different DataLayouts in pexes, so we
|
| + // implicitly set the DataLayout to the following default.
|
| + //
|
| + // This is not usually needed by the backend, but it might be used
|
| + // by IR passes that the PNaCl translator runs. We set this in the
|
| + // reader rather than in pnacl-llc so that 'opt' will also use the
|
| + // correct DataLayout if it is run on a pexe.
|
| + M->setDataLayout(PNaClDataLayout);
|
| +
|
| + if (std::error_code EC = InitStream())
|
| + return EC;
|
| +
|
| + // We expect a number of well-defined blocks, though we don't necessarily
|
| + // need to understand them all.
|
| + while (1) {
|
| + if (Stream.AtEndOfStream())
|
| + return std::error_code();
|
| +
|
| + NaClBitstreamEntry Entry =
|
| + Stream.advance(NaClBitstreamCursor::AF_DontAutoprocessAbbrevs, nullptr);
|
| +
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::Error:
|
| + return Error(MalformedBlock, "malformed module file");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + return std::error_code();
|
| +
|
| + case NaClBitstreamEntry::SubBlock:
|
| + switch (Entry.ID) {
|
| + case naclbitc::MODULE_BLOCK_ID:
|
| + // Reject multiple MODULE_BLOCK's in a single bitstream.
|
| + if (TheModule)
|
| + return Error(InvalidMultipleBlocks,
|
| + "Multiple MODULE_BLOCKs in same stream");
|
| + TheModule = M;
|
| + if (std::error_code EC = ParseModule(false))
|
| + return EC;
|
| + if (LazyStreamer)
|
| + return std::error_code();
|
| + break;
|
| + default:
|
| + return Error(InvalidBlock, "Invalid top-level block found.");
|
| + break;
|
| + }
|
| + continue;
|
| + case NaClBitstreamEntry::Record:
|
| + // There should be no records in the top-level of blocks.
|
| + return Error(InvalidRecord, "Invalid record at top-level");
|
| + }
|
| + }
|
| +}
|
| +
|
| +// Returns true if error occured installing I into BB.
|
| +std::error_code NaClBitcodeReader::InstallInstruction(
|
| + BasicBlock *BB, Instruction *I) {
|
| + // Add instruction to end of current BB. If there is no current BB, reject
|
| + // this file.
|
| + if (BB == 0) {
|
| + delete I;
|
| + return Error(InvalidInstructionWithNoBB,
|
| + "Instruction with no BB, can't install");
|
| + }
|
| + BB->getInstList().push_back(I);
|
| + return std::error_code();
|
| +}
|
| +
|
| +CastInst *
|
| +NaClBitcodeReader::CreateCast(unsigned BBIndex, Instruction::CastOps Op,
|
| + Type *CT, Value *V, bool DeferInsertion) {
|
| + if (BBIndex >= FunctionBBs.size())
|
| + report_fatal_error("CreateCast on unknown basic block");
|
| + BasicBlockInfo &BBInfo = FunctionBBs[BBIndex];
|
| + NaClBitcodeReaderCast ModeledCast(Op, CT, V);
|
| + CastInst *Cast = BBInfo.CastMap[ModeledCast];
|
| + if (Cast == NULL) {
|
| + Cast = CastInst::Create(Op, V, CT);
|
| + BBInfo.CastMap[ModeledCast] = Cast;
|
| + if (DeferInsertion) {
|
| + BBInfo.PhiCasts.push_back(Cast);
|
| + }
|
| + }
|
| + if (!DeferInsertion && Cast->getParent() == 0) {
|
| + InstallInstruction(BBInfo.BB, Cast);
|
| + }
|
| + return Cast;
|
| +}
|
| +
|
| +Value *NaClBitcodeReader::ConvertOpToScalar(Value *Op, unsigned BBIndex,
|
| + bool DeferInsertion) {
|
| + if (Op->getType()->isPointerTy()) {
|
| + return CreateCast(BBIndex, Instruction::PtrToInt, IntPtrType, Op,
|
| + DeferInsertion);
|
| + }
|
| + return Op;
|
| +}
|
| +
|
| +Value *NaClBitcodeReader::ConvertOpToType(Value *Op, Type *T,
|
| + unsigned BBIndex) {
|
| + Type *OpTy = Op->getType();
|
| + if (OpTy == T) return Op;
|
| +
|
| + if (OpTy->isPointerTy()) {
|
| + if (T == IntPtrType) {
|
| + return ConvertOpToScalar(Op, BBIndex);
|
| + } else {
|
| + return CreateCast(BBIndex, Instruction::BitCast, T, Op);
|
| + }
|
| + } else if (OpTy == IntPtrType) {
|
| + return CreateCast(BBIndex, Instruction::IntToPtr, T, Op);
|
| + }
|
| +
|
| + std::string Message;
|
| + raw_string_ostream StrM(Message);
|
| + StrM << "Can't convert " << *Op << " to type " << *T << "\n";
|
| + report_fatal_error(StrM.str());
|
| +}
|
| +
|
| +/// ParseFunctionBody - Lazily parse the specified function body block.
|
| +std::error_code NaClBitcodeReader::ParseFunctionBody(Function *F) {
|
| + DEBUG(dbgs() << "-> ParseFunctionBody\n");
|
| + if (Stream.EnterSubBlock(naclbitc::FUNCTION_BLOCK_ID))
|
| + return Error(InvalidRecord, "Malformed block record");
|
| +
|
| + unsigned ModuleValueListSize = ValueList.size();
|
| +
|
| + // Add all the function arguments to the value table.
|
| + for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I)
|
| + ValueList.push_back(I);
|
| +
|
| + unsigned NextValueNo = ValueList.size();
|
| + BasicBlock *CurBB = 0;
|
| + unsigned CurBBNo = 0;
|
| +
|
| + // Read all the records.
|
| + SmallVector<uint64_t, 64> Record;
|
| + while (1) {
|
| + NaClBitstreamEntry Entry = Stream.advance(0, nullptr);
|
| +
|
| + switch (Entry.Kind) {
|
| + case NaClBitstreamEntry::Error:
|
| + return Error(MalformedBlock, "Bitcode error in function block");
|
| + case NaClBitstreamEntry::EndBlock:
|
| + goto OutOfRecordLoop;
|
| +
|
| + case NaClBitstreamEntry::SubBlock:
|
| + switch (Entry.ID) {
|
| + default:
|
| + return Error(InvalidBlock, "Invalid block in function block");
|
| + break;
|
| + case naclbitc::CONSTANTS_BLOCK_ID:
|
| + if (std::error_code EC = ParseConstants())
|
| + return EC;
|
| + NextValueNo = ValueList.size();
|
| + break;
|
| + case naclbitc::VALUE_SYMTAB_BLOCK_ID:
|
| + if (PNaClAllowLocalSymbolTables) {
|
| + if (std::error_code EC = ParseValueSymbolTable())
|
| + return EC;
|
| + } else {
|
| + return Error(InvalidRecord, "Local value symbol tables not allowed");
|
| + }
|
| + break;
|
| + }
|
| + continue;
|
| +
|
| + case NaClBitstreamEntry::Record:
|
| + // The interesting case.
|
| + break;
|
| + }
|
| +
|
| + // Read a record.
|
| + Record.clear();
|
| + Instruction *I = 0;
|
| + unsigned BitCode = Stream.readRecord(Entry.ID, Record);
|
| + switch (BitCode) {
|
| + default: {// Default behavior: reject
|
| + std::string Message;
|
| + raw_string_ostream StrM(Message);
|
| + StrM << "Unknown instruction record: <" << BitCode;
|
| + for (unsigned I = 0, E = Record.size(); I != E; ++I) {
|
| + StrM << " " << Record[I];
|
| + }
|
| + StrM << ">";
|
| + return Error(InvalidRecord, StrM.str());
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks]
|
| + if (Record.size() != 1 || Record[0] == 0)
|
| + return Error(InvalidRecord, "Invalid DECLAREBLOCKS record");
|
| + // Create all the basic blocks for the function.
|
| + FunctionBBs.resize(Record[0]);
|
| + for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) {
|
| + BasicBlockInfo &BBInfo = FunctionBBs[i];
|
| + BBInfo.BB = BasicBlock::Create(Context, "", F);
|
| + }
|
| + CurBB = FunctionBBs.at(0).BB;
|
| + continue;
|
| +
|
| + case naclbitc::FUNC_CODE_INST_BINOP: {
|
| + // BINOP: [opval, opval, opcode[, flags]]
|
| + // Note: Only old PNaCl bitcode files may contain flags. If
|
| + // they are found, we ignore them.
|
| + unsigned OpNum = 0;
|
| + Value *LHS, *RHS;
|
| + if (popValue(Record, &OpNum, NextValueNo, &LHS) ||
|
| + popValue(Record, &OpNum, NextValueNo, &RHS) ||
|
| + OpNum+1 > Record.size())
|
| + return Error(InvalidRecord, "Invalid BINOP record");
|
| +
|
| + LHS = ConvertOpToScalar(LHS, CurBBNo);
|
| + RHS = ConvertOpToScalar(RHS, CurBBNo);
|
| +
|
| + Instruction::BinaryOps Opc;
|
| + if (!naclbitc::DecodeBinaryOpcode(Record[OpNum++], LHS->getType(), Opc))
|
| + return Error(InvalidValue, "Invalid binary opcode in BINOP record");
|
| + I = BinaryOperator::Create(Opc, LHS, RHS);
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_CAST: { // CAST: [opval, destty, castopc]
|
| + unsigned OpNum = 0;
|
| + Value *Op;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Op) ||
|
| + OpNum+2 != Record.size())
|
| + return Error(InvalidRecord, "Invalid CAST record: bad record size");
|
| +
|
| + Type *ResTy = getTypeByID(Record[OpNum]);
|
| + if (ResTy == 0)
|
| + return Error(InvalidType, "Invalid CAST record: bad type ID");
|
| + Instruction::CastOps Opc;
|
| + if (!naclbitc::DecodeCastOpcode(Record[OpNum+1], Opc)) {
|
| + return Error(InvalidValue, "Invalid CAST record: bad opcode");
|
| + }
|
| +
|
| + // If a ptrtoint cast was elided on the argument of the cast,
|
| + // add it back. Note: The casts allowed here should match the
|
| + // casts in NaClValueEnumerator::ExpectsScalarValue.
|
| + switch (Opc) {
|
| + case Instruction::Trunc:
|
| + case Instruction::ZExt:
|
| + case Instruction::SExt:
|
| + case Instruction::UIToFP:
|
| + case Instruction::SIToFP:
|
| + Op = ConvertOpToScalar(Op, CurBBNo);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + I = CastInst::Create(Opc, Op, ResTy);
|
| + break;
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [opval, opval, pred]
|
| + // new form of select
|
| + // handles select i1 or select [N x i1]
|
| + unsigned OpNum = 0;
|
| + Value *TrueVal, *FalseVal, *Cond;
|
| + if (popValue(Record, &OpNum, NextValueNo, &TrueVal) ||
|
| + popValue(Record, &OpNum, NextValueNo, &FalseVal) ||
|
| + popValue(Record, &OpNum, NextValueNo, &Cond) ||
|
| + OpNum != Record.size())
|
| + return Error(InvalidRecord, "Invalid SELECT record");
|
| +
|
| + TrueVal = ConvertOpToScalar(TrueVal, CurBBNo);
|
| + FalseVal = ConvertOpToScalar(FalseVal, CurBBNo);
|
| +
|
| + // select condition can be either i1 or [N x i1]
|
| + if (VectorType* vector_type =
|
| + dyn_cast<VectorType>(Cond->getType())) {
|
| + // expect <n x i1>
|
| + if (vector_type->getElementType() != Type::getInt1Ty(Context))
|
| + return Error(InvalidTypeForValue,
|
| + "Invalid SELECT vector condition type");
|
| + } else {
|
| + // expect i1
|
| + if (Cond->getType() != Type::getInt1Ty(Context))
|
| + return Error(InvalidTypeForValue, "Invalid SELECT condition type");
|
| + }
|
| +
|
| + I = SelectInst::Create(Cond, TrueVal, FalseVal);
|
| + break;
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opval, opval]
|
| + unsigned OpNum = 0;
|
| + Value *Vec, *Idx;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Vec) ||
|
| + popValue(Record, &OpNum, NextValueNo, &Idx) || OpNum != Record.size())
|
| + return Error(InvalidRecord, "Invalid EXTRACTELEMENT record");
|
| +
|
| + // expect i32
|
| + if (Idx->getType() != Type::getInt32Ty(Context))
|
| + return Error(InvalidTypeForValue, "Invalid EXTRACTELEMENT index type");
|
| +
|
| + I = ExtractElementInst::Create(Vec, Idx);
|
| + break;
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [opval,opval,opval]
|
| + unsigned OpNum = 0;
|
| + Value *Vec, *Elt, *Idx;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Vec) ||
|
| + popValue(Record, &OpNum, NextValueNo, &Elt) ||
|
| + popValue(Record, &OpNum, NextValueNo, &Idx) || OpNum != Record.size())
|
| + return Error(InvalidRecord, "Invalid INSERTELEMENT record");
|
| +
|
| + // expect vector type
|
| + if (!isa<VectorType>(Vec->getType()))
|
| + return Error(InvalidTypeForValue, "Invalid INSERTELEMENT vector type");
|
| + // match vector and element types
|
| + if (cast<VectorType>(Vec->getType())->getElementType() != Elt->getType())
|
| + return Error(InvalidTypeForValue,
|
| + "Mismatched INSERTELEMENT vector and element type");
|
| + // expect i32
|
| + if (Idx->getType() != Type::getInt32Ty(Context))
|
| + return Error(InvalidTypeForValue, "Invalid INSERTELEMENT index type");
|
| +
|
| + I = InsertElementInst::Create(Vec, Elt, Idx);
|
| + break;
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_INST_CMP2: { // CMP2: [opval, opval, pred]
|
| + // FCmp/ICmp returning bool or vector of bool
|
| +
|
| + unsigned OpNum = 0;
|
| + Value *LHS, *RHS;
|
| + if (popValue(Record, &OpNum, NextValueNo, &LHS) ||
|
| + popValue(Record, &OpNum, NextValueNo, &RHS) ||
|
| + OpNum+1 != Record.size())
|
| + return Error(InvalidRecord, "Invalid CMP record");
|
| +
|
| + LHS = ConvertOpToScalar(LHS, CurBBNo);
|
| + RHS = ConvertOpToScalar(RHS, CurBBNo);
|
| +
|
| + CmpInst::Predicate Predicate;
|
| + if (LHS->getType()->isFPOrFPVectorTy()) {
|
| + if (!naclbitc::DecodeFcmpPredicate(Record[OpNum], Predicate))
|
| + return Error(
|
| + InvalidValue,
|
| + "PNaCl bitcode contains invalid floating comparison predicate");
|
| + I = new FCmpInst(Predicate, LHS, RHS);
|
| + } else {
|
| + if (!naclbitc::DecodeIcmpPredicate(Record[OpNum], Predicate))
|
| + return Error(
|
| + InvalidValue,
|
| + "PNaCl bitcode contains invalid integer comparison predicate");
|
| + I = new ICmpInst(Predicate, LHS, RHS);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_INST_RET: // RET: [opval<optional>]
|
| + {
|
| + unsigned Size = Record.size();
|
| + if (Size == 0) {
|
| + I = ReturnInst::Create(Context);
|
| + break;
|
| + }
|
| +
|
| + unsigned OpNum = 0;
|
| + Value *Op = NULL;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Op))
|
| + return Error(InvalidRecord, "Invalid RET record");
|
| + if (OpNum != Record.size())
|
| + return Error(InvalidRecord, "Invalid RET record");
|
| +
|
| + I = ReturnInst::Create(Context, ConvertOpToScalar(Op, CurBBNo));
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#]
|
| + if (Record.size() != 1 && Record.size() != 3)
|
| + return Error(InvalidRecord, "Invalid BR record");
|
| + BasicBlock *TrueDest = getBasicBlock(Record[0]);
|
| + if (TrueDest == 0)
|
| + return Error(InvalidRecord, "Invalid BR record");
|
| +
|
| + if (Record.size() == 1) {
|
| + I = BranchInst::Create(TrueDest);
|
| + }
|
| + else {
|
| + BasicBlock *FalseDest = getBasicBlock(Record[1]);
|
| + Value *Cond = getValue(Record, 2, NextValueNo);
|
| + if (FalseDest == 0 || Cond == 0)
|
| + return Error(InvalidValue, "Invalid BR record");
|
| + I = BranchInst::Create(TrueDest, FalseDest, Cond);
|
| + }
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...]
|
| + if (Record.size() < 4)
|
| + return Error(InvalidRecord, "Invalid SWITCH record");
|
| + Type *OpTy = getTypeByID(Record[0]);
|
| + unsigned ValueBitWidth = cast<IntegerType>(OpTy)->getBitWidth();
|
| + if (ValueBitWidth > 64)
|
| + return Error(InvalidValue,
|
| + "Wide integers are not supported in PNaCl bitcode");
|
| +
|
| + Value *Cond = getValue(Record, 1, NextValueNo);
|
| + BasicBlock *Default = getBasicBlock(Record[2]);
|
| + if (OpTy == 0 || Cond == 0 || Default == 0)
|
| + return Error(InvalidRecord, "Invalid SWITCH record");
|
| +
|
| + Cond = ConvertOpToScalar(Cond, CurBBNo);
|
| + unsigned NumCases = Record[3];
|
| +
|
| + SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases);
|
| +
|
| + unsigned CurIdx = 4;
|
| + for (unsigned i = 0; i != NumCases; ++i) {
|
| + // The PNaCl bitcode format has vestigial support for case
|
| + // ranges, but we no longer support reading them because
|
| + // no-one produced them.
|
| + // See https://code.google.com/p/nativeclient/issues/detail?id=3758
|
| + unsigned NumItems = Record[CurIdx++];
|
| + bool isSingleNumber = Record[CurIdx++];
|
| + if (NumItems != 1 || !isSingleNumber)
|
| + return Error(InvalidRecord,
|
| + "Case ranges are not supported in PNaCl bitcode");
|
| +
|
| + APInt CaseValue(ValueBitWidth,
|
| + NaClDecodeSignRotatedValue(Record[CurIdx++]));
|
| + BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]);
|
| + SI->addCase(ConstantInt::get(Context, CaseValue), DestBB);
|
| + }
|
| + I = SI;
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE
|
| + I = new UnreachableInst(Context);
|
| + break;
|
| + case naclbitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...]
|
| + if (Record.size() < 1 || ((Record.size()-1)&1))
|
| + return Error(InvalidRecord, "Invalid PHI record");
|
| + Type *Ty = getTypeByID(Record[0]);
|
| + if (!Ty) return Error(InvalidType, "Invalid PHI record");
|
| +
|
| + PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2);
|
| +
|
| + for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) {
|
| + Value *V;
|
| + // With relative value IDs, it is possible that operands have
|
| + // negative IDs (for forward references). Use a signed VBR
|
| + // representation to keep the encoding small.
|
| + V = getValueSigned(Record, 1+i, NextValueNo);
|
| + unsigned BBIndex = Record[2+i];
|
| + BasicBlock *BB = getBasicBlock(BBIndex);
|
| + if (!V || !BB)
|
| + return Error(InvalidValue, "Invalid PHI record");
|
| + if (Ty == IntPtrType) {
|
| + // Delay installing scalar casts until all instructions of
|
| + // the function are rendered. This guarantees that we insert
|
| + // the conversion just before the incoming edge (or use an
|
| + // existing conversion if already installed).
|
| + V = ConvertOpToScalar(V, BBIndex, /* DeferInsertion = */ true);
|
| + }
|
| + PN->addIncoming(V, BB);
|
| + }
|
| + I = PN;
|
| + break;
|
| + }
|
| +
|
| + case naclbitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [op, align]
|
| + if (Record.size() != 2)
|
| + return Error(InvalidRecord, "Invalid ALLOCA record");
|
| + Value *Size;
|
| + unsigned OpNum = 0;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Size))
|
| + return Error(InvalidRecord, "Invalid ALLOCA record");
|
| + unsigned Alignment;
|
| + if (std::error_code EC = getAlignmentValue(Record[1], Alignment))
|
| + return EC;
|
| + I = new AllocaInst(Type::getInt8Ty(Context), Size, Alignment);
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_LOAD: {
|
| + // LOAD: [op, align, ty]
|
| + unsigned OpNum = 0;
|
| + Value *Op;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Op) ||
|
| + Record.size() != 3)
|
| + return Error(InvalidRecord, "Invalid LOAD record");
|
| +
|
| + // Add pointer cast to op.
|
| + Type *T = getTypeByID(Record[2]);
|
| + if (T == nullptr)
|
| + return Error(InvalidType, "Invalid type for load instruction");
|
| + Op = ConvertOpToType(Op, T->getPointerTo(), CurBBNo);
|
| + if (Op == nullptr)
|
| + return Error(InvalidTypeForValue, "Can't convert cast to type");
|
| + unsigned Alignment;
|
| + if (std::error_code EC = getAlignmentValue(Record[OpNum], Alignment))
|
| + return EC;
|
| + I = new LoadInst(Op, "", false, Alignment);
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_STORE: {
|
| + // STORE: [ptr, val, align]
|
| + unsigned OpNum = 0;
|
| + Value *Val, *Ptr;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Ptr) ||
|
| + popValue(Record, &OpNum, NextValueNo, &Val) ||
|
| + OpNum+1 != Record.size())
|
| + return Error(InvalidRecord, "Invalid STORE record");
|
| + Val = ConvertOpToScalar(Val, CurBBNo);
|
| + Ptr = ConvertOpToType(Ptr, Val->getType()->getPointerTo(), CurBBNo);
|
| + if (Ptr == nullptr)
|
| + return Error(InvalidTypeForValue, "Can't convert cast to type");
|
| + unsigned Alignment;
|
| + if (std::error_code EC = getAlignmentValue(Record[OpNum], Alignment))
|
| + return EC;
|
| + I = new StoreInst(Val, Ptr, false, Alignment);
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_CALL:
|
| + case naclbitc::FUNC_CODE_INST_CALL_INDIRECT: {
|
| + // CALL: [cc, fnid, arg0, arg1...]
|
| + // CALL_INDIRECT: [cc, fnid, returnty, args...]
|
| + if ((Record.size() < 2) ||
|
| + (BitCode == naclbitc::FUNC_CODE_INST_CALL_INDIRECT &&
|
| + Record.size() < 3))
|
| + return Error(InvalidRecord, "Invalid CALL record");
|
| +
|
| + unsigned CCInfo = Record[0];
|
| +
|
| + unsigned OpNum = 1;
|
| + Value *Callee;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Callee))
|
| + return Error(InvalidRecord, "Invalid CALL record");
|
| +
|
| + // Build function type for call.
|
| + FunctionType *FTy = 0;
|
| + Type *ReturnType = 0;
|
| + if (BitCode == naclbitc::FUNC_CODE_INST_CALL_INDIRECT) {
|
| + // Callee type has been elided, add back in.
|
| + ReturnType = getTypeByID(Record[2]);
|
| + ++OpNum;
|
| + } else {
|
| + // Get type signature from callee.
|
| + if (PointerType *OpTy = dyn_cast<PointerType>(Callee->getType())) {
|
| + FTy = dyn_cast<FunctionType>(OpTy->getElementType());
|
| + }
|
| + if (FTy == 0)
|
| + return Error(InvalidType, "Invalid type for CALL record");
|
| + }
|
| +
|
| + unsigned NumParams = Record.size() - OpNum;
|
| + if (FTy && NumParams != FTy->getNumParams())
|
| + return Error(InvalidRecord, "Invalid CALL record");
|
| +
|
| + // Process call arguments.
|
| + SmallVector<Value*, 6> Args;
|
| + for (unsigned Index = 0; Index < NumParams; ++Index) {
|
| + Value *Arg;
|
| + if (popValue(Record, &OpNum, NextValueNo, &Arg)) {
|
| + std::string Buffer;
|
| + raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Invalid call argument: Index " << Index;
|
| + return Error(InvalidValue, StrBuf.str());
|
| + }
|
| + if (FTy) {
|
| + // Add a cast, to a pointer type if necessary, in case this
|
| + // is an intrinsic call that takes a pointer argument.
|
| + Arg = ConvertOpToType(Arg, FTy->getParamType(Index), CurBBNo);
|
| + } else {
|
| + Arg = ConvertOpToScalar(Arg, CurBBNo);
|
| + }
|
| + if (Arg == nullptr) {
|
| + std::string Buffer;
|
| + raw_string_ostream StrBuf(Buffer);
|
| + StrBuf << "Unable to cast call argument to parameter type: " << Index;
|
| + return Error(InvalidValue, StrBuf.str());
|
| + }
|
| + Args.push_back(Arg);
|
| + }
|
| + if (FTy == nullptr) {
|
| + // Reconstruct the function type and cast the function pointer
|
| + // to it.
|
| + SmallVector<Type*, 6> ArgTypes;
|
| + for (const auto Arg : Args) {
|
| + ArgTypes.push_back(Arg->getType());
|
| + }
|
| + FTy = FunctionType::get(ReturnType, ArgTypes, false);
|
| + Callee = ConvertOpToType(Callee, FTy->getPointerTo(), CurBBNo);
|
| + }
|
| +
|
| + // Construct call.
|
| + I = CallInst::Create(Callee, Args);
|
| + CallingConv::ID CallingConv;
|
| + if (!naclbitc::DecodeCallingConv(CCInfo>>1, CallingConv))
|
| + return Error(InvalidValue,
|
| + "PNaCl bitcode contains invalid calling conventions.");
|
| + cast<CallInst>(I)->setCallingConv(CallingConv);
|
| + cast<CallInst>(I)->setTailCall(CCInfo & 1);
|
| + break;
|
| + }
|
| + case naclbitc::FUNC_CODE_INST_FORWARDTYPEREF:
|
| + // Build corresponding forward reference.
|
| + if (Record.size() != 2 ||
|
| + ValueList.createValueFwdRef(Record[0], getTypeByID(Record[1])))
|
| + return Error(InvalidRecord, "Invalid FORWARDTYPEREF record");
|
| + continue;
|
| + }
|
| +
|
| + if (std::error_code EC = InstallInstruction(CurBB, I))
|
| + return EC;
|
| +
|
| + // If this was a terminator instruction, move to the next block.
|
| + if (isa<TerminatorInst>(I)) {
|
| + ++CurBBNo;
|
| + CurBB = getBasicBlock(CurBBNo);
|
| + }
|
| +
|
| + // Non-void values get registered in the value table for future use.
|
| + if (I && !I->getType()->isVoidTy()) {
|
| + Value *NewVal = I;
|
| + if (NewVal->getType()->isPointerTy() &&
|
| + ValueList.getValueFwdRef(NextValueNo)) {
|
| + // Forward-referenced values cannot have pointer type.
|
| + NewVal = ConvertOpToScalar(NewVal, CurBBNo);
|
| + }
|
| + ValueList.AssignValue(NewVal, NextValueNo++);
|
| + }
|
| + }
|
| +
|
| +OutOfRecordLoop:
|
| +
|
| + // Add PHI conversions to corresponding incoming block, if not
|
| + // already in the block. Also clear all conversions after fixing
|
| + // PHI conversions.
|
| + for (unsigned I = 0, NumBBs = FunctionBBs.size(); I < NumBBs; ++I) {
|
| + BasicBlockInfo &BBInfo = FunctionBBs[I];
|
| + std::vector<CastInst*> &PhiCasts = BBInfo.PhiCasts;
|
| + for (std::vector<CastInst*>::iterator Iter = PhiCasts.begin(),
|
| + IterEnd = PhiCasts.end(); Iter != IterEnd; ++Iter) {
|
| + CastInst *Cast = *Iter;
|
| + if (Cast->getParent() == 0) {
|
| + BasicBlock *BB = BBInfo.BB;
|
| + BB->getInstList().insert(BB->getTerminator(), Cast);
|
| + }
|
| + }
|
| + PhiCasts.clear();
|
| + BBInfo.CastMap.clear();
|
| + }
|
| +
|
| + // Check the function list for unresolved values.
|
| + if (Argument *A = dyn_cast<Argument>(ValueList.back())) {
|
| + if (A->getParent() == 0) {
|
| + // We found at least one unresolved value. Nuke them all to avoid leaks.
|
| + for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){
|
| + if ((A = dyn_cast<Argument>(ValueList[i])) && A->getParent() == 0) {
|
| + A->replaceAllUsesWith(UndefValue::get(A->getType()));
|
| + delete A;
|
| + }
|
| + }
|
| + return Error(InvalidValue, "Never resolved value found in function!");
|
| + }
|
| + }
|
| +
|
| + // Trim the value list down to the size it was before we parsed this function.
|
| + ValueList.shrinkTo(ModuleValueListSize);
|
| + FunctionBBs.clear();
|
| + DEBUG(dbgs() << "-> ParseFunctionBody\n");
|
| + return std::error_code();
|
| +}
|
| +
|
| +/// FindFunctionInStream - Find the function body in the bitcode stream
|
| +std::error_code NaClBitcodeReader::FindFunctionInStream(
|
| + Function *F,
|
| + DenseMap<Function*, uint64_t>::iterator DeferredFunctionInfoIterator) {
|
| + while (DeferredFunctionInfoIterator->second == 0) {
|
| + if (Stream.AtEndOfStream())
|
| + return Error(CouldNotFindFunctionInStream,
|
| + "Could not find Function in stream");
|
| + // ParseModule will parse the next body in the stream and set its
|
| + // position in the DeferredFunctionInfo map.
|
| + if (std::error_code EC = ParseModule(true))
|
| + return EC;
|
| + }
|
| + return std::error_code();
|
| +}
|
| +
|
| +//===----------------------------------------------------------------------===//
|
| +// GVMaterializer implementation
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +void NaClBitcodeReader::releaseBuffer() { Buffer.release(); }
|
| +
|
| +std::error_code NaClBitcodeReader::materialize(GlobalValue *GV) {
|
| + Function *F = dyn_cast<Function>(GV);
|
| + // If it's not a function or is already material, ignore the request.
|
| + if (!F || !F->isMaterializable())
|
| + return std::error_code();
|
| +
|
| + 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 (std::error_code EC = FindFunctionInStream(F, DFII)) {
|
| + return EC;
|
| + }
|
| + }
|
| +
|
| + // Move the bit stream to the saved position of the deferred function body.
|
| + Stream.JumpToBit(DFII->second);
|
| +
|
| + if (std::error_code EC = ParseFunctionBody(F))
|
| + return EC;
|
| + F->setIsMaterializable(false);
|
| +
|
| + // Upgrade any old intrinsic calls in the function.
|
| + for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(),
|
| + E = UpgradedIntrinsics.end(); I != E; ++I) {
|
| + if (I->first != I->second) {
|
| + for (Value::use_iterator UI = I->first->use_begin(),
|
| + UE = I->first->use_end(); UI != UE; ) {
|
| + if (CallInst* CI = dyn_cast<CallInst>(*UI++))
|
| + UpgradeIntrinsicCall(CI, I->second);
|
| + }
|
| + }
|
| + }
|
| +
|
| + return std::error_code();
|
| +}
|
| +
|
| +bool NaClBitcodeReader::isDematerializable(const GlobalValue *GV) const {
|
| + const Function *F = dyn_cast<Function>(GV);
|
| + if (!F || F->isDeclaration())
|
| + return false;
|
| + return DeferredFunctionInfo.count(const_cast<Function*>(F));
|
| +}
|
| +
|
| +void NaClBitcodeReader::Dematerialize(GlobalValue *GV) {
|
| + Function *F = dyn_cast<Function>(GV);
|
| + // If this function isn't dematerializable, this is a noop.
|
| + if (!F || !isDematerializable(F))
|
| + return;
|
| +
|
| + assert(DeferredFunctionInfo.count(F) && "No info to read function later?");
|
| +
|
| + // Just forget the function body, we can remat it later.
|
| + F->dropAllReferences();
|
| + F->setIsMaterializable(true);
|
| +}
|
| +
|
| +
|
| +std::error_code NaClBitcodeReader::MaterializeModule(Module *M) {
|
| + assert(M == TheModule &&
|
| + "Can only Materialize the Module this NaClBitcodeReader is attached to.");
|
| + // Iterate over the module, deserializing any functions that are still on
|
| + // disk.
|
| + for (Module::iterator F = TheModule->begin(), E = TheModule->end();
|
| + F != E; ++F) {
|
| + if (F->isMaterializable()) {
|
| + if (std::error_code EC = materialize(F))
|
| + return EC;
|
| + }
|
| + }
|
| +
|
| + // At this point, if there are any function bodies, the current bit is
|
| + // pointing to the END_BLOCK record after them. Now make sure the rest
|
| + // of the bits in the module have been read.
|
| + if (NextUnreadBit)
|
| + ParseModule(true);
|
| +
|
| + // Upgrade any intrinsic calls that slipped through (should not happen!) and
|
| + // delete the old functions to clean up. We can't do this unless the entire
|
| + // module is materialized because there could always be another function body
|
| + // with calls to the old function.
|
| + for (std::vector<std::pair<Function*, Function*> >::iterator I =
|
| + UpgradedIntrinsics.begin(), E = UpgradedIntrinsics.end(); I != E; ++I) {
|
| + if (I->first != I->second) {
|
| + for (Value::use_iterator UI = I->first->use_begin(),
|
| + UE = I->first->use_end(); UI != UE; ) {
|
| + if (CallInst* CI = dyn_cast<CallInst>(*UI++))
|
| + UpgradeIntrinsicCall(CI, I->second);
|
| + }
|
| + if (!I->first->use_empty())
|
| + I->first->replaceAllUsesWith(I->second);
|
| + I->first->eraseFromParent();
|
| + }
|
| + }
|
| + std::vector<std::pair<Function*, Function*> >().swap(UpgradedIntrinsics);
|
| +
|
| + return std::error_code();
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::InitStream() {
|
| + if (LazyStreamer)
|
| + return InitLazyStream();
|
| + return InitStreamFromBuffer();
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::InitStreamFromBuffer() {
|
| + const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart();
|
| + const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
|
| +
|
| + if (Buffer->getBufferSize() & 3)
|
| + return Error(InvalidBitstream,
|
| + "Bitcode stream should be a multiple of 4 bytes in length");
|
| +
|
| + if (Header.Read(BufPtr, BufEnd))
|
| + return Error(InvalidBitstream, Header.Unsupported());
|
| +
|
| + StreamFile.reset(new NaClBitstreamReader(BufPtr, BufEnd));
|
| + Stream.init(StreamFile.get());
|
| +
|
| + if (AcceptHeader())
|
| + return Error(InvalidBitstream, Header.Unsupported());
|
| + return std::error_code();
|
| +}
|
| +
|
| +std::error_code NaClBitcodeReader::InitLazyStream() {
|
| + if (Header.Read(LazyStreamer))
|
| + return Error(InvalidBitstream, Header.Unsupported());
|
| +
|
| + StreamFile.reset(new NaClBitstreamReader(LazyStreamer,
|
| + Header.getHeaderSize()));
|
| + Stream.init(StreamFile.get());
|
| + if (AcceptHeader())
|
| + return Error(InvalidBitstream, Header.Unsupported());
|
| + return std::error_code();
|
| +}
|
| +
|
| +//===----------------------------------------------------------------------===//
|
| +// External interface
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +/// \brief Get a lazy one-at-time loading module from bitcode.
|
| +///
|
| +/// This isn't always used in a lazy context. In particular, it's also used by
|
| +/// \a NaClParseBitcodeFile(). Compared to the upstream LLVM bitcode reader,
|
| +/// NaCl does not support BlockAddresses, so it does not need to materialize
|
| +/// forward-referenced functions from block address references.
|
| +ErrorOr<Module *> llvm::getNaClLazyBitcodeModule(
|
| + std::unique_ptr<MemoryBuffer> &&Buffer, LLVMContext& Context,
|
| + raw_ostream *Verbose, bool AcceptSupportedOnly) {
|
| + Module *M = new Module(Buffer->getBufferIdentifier(), Context);
|
| + NaClBitcodeReader *R =
|
| + new NaClBitcodeReader(Buffer.get(), Context, Verbose, AcceptSupportedOnly);
|
| + M->setMaterializer(R);
|
| +
|
| + auto cleanupOnError = [&](std::error_code EC) {
|
| + R->releaseBuffer(); // Never take ownership on error.
|
| + delete M; // Also deletes R.
|
| + return EC;
|
| + };
|
| +
|
| + if (std::error_code EC = R->ParseBitcodeInto(M))
|
| + return cleanupOnError(EC);
|
| +
|
| + Buffer.release(); // The BitcodeReader owns it now.
|
| + return M;
|
| +}
|
| +
|
| +
|
| +Module *llvm::getNaClStreamedBitcodeModule(const std::string &name,
|
| + StreamingMemoryObject *Streamer,
|
| + LLVMContext &Context,
|
| + raw_ostream *Verbose,
|
| + std::string *ErrMsg,
|
| + bool AcceptSupportedOnly) {
|
| + Module *M = new Module(name, Context);
|
| + NaClBitcodeReader *R =
|
| + new NaClBitcodeReader(Streamer, Context, Verbose,
|
| + AcceptSupportedOnly);
|
| + M->setMaterializer(R);
|
| + if (std::error_code EC = R->ParseBitcodeInto(M)) {
|
| + if (ErrMsg)
|
| + *ErrMsg = EC.message();
|
| + delete M; // Also deletes R.
|
| + return nullptr;
|
| + }
|
| +
|
| + return M;
|
| +}
|
| +
|
| +ErrorOr<Module *> llvm::NaClParseBitcodeFile(
|
| + MemoryBufferRef Buffer, LLVMContext& Context, raw_ostream *Verbose,
|
| + bool AcceptSupportedOnly){
|
| + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);
|
| + ErrorOr<Module *> ModuleOrErr =
|
| + getNaClLazyBitcodeModule(std::move(Buf), Context, Verbose, AcceptSupportedOnly);
|
| + if (!ModuleOrErr)
|
| + return ModuleOrErr;
|
| + Module *M = ModuleOrErr.get();
|
| + // Read in the entire module, and destroy the NaClBitcodeReader.
|
| + if (std::error_code EC = M->materializeAllPermanently()) {
|
| + delete M;
|
| + return EC;
|
| + }
|
| +
|
| + // TODO: Restore the use-lists to the in-memory state when the bitcode was
|
| + // written. We must defer until the Module has been fully materialized.
|
| +
|
| + return M;
|
| +}
|
|
|