Rename the file name (looks more similar to LLVM).
diff --git a/lib/bcc/CodeEmitter.cpp b/lib/bcc/CodeEmitter.cpp
new file mode 100644
index 0000000..38fc281
--- /dev/null
+++ b/lib/bcc/CodeEmitter.cpp
@@ -0,0 +1,1574 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CodeEmitter.h"
+
+#include "CodeMemoryManager.h"
+#include "EmittedFuncEntry.h"
+#include "Runtime.h"
+
+#include <bcc/bcc.h>
+#include <bcc/bcc_cache.h>
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRelocation.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
+#include "llvm/CodeGen/JITCodeEmitter.h"
+
+#include "llvm/ExecutionEngine/GenericValue.h"
+
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if defined(USE_DISASSEMBLER)
+#include "llvm/Support/MemoryObject.h"
+#endif
+
+#include "llvm/System/Host.h"
+
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Target/TargetJITInfo.h"
+
+#include "llvm/Constant.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Function.h"
+#include "llvm/GlobalAlias.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Instruction.h"
+#include "llvm/Type.h"
+
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <string>
+
+#include <stddef.h>
+
+
+namespace {
+
+#if defined(USE_DISASSEMBLER)
+class BufferMemoryObject : public llvm::MemoryObject {
+private:
+ const uint8_t *mBytes;
+ uint64_t mLength;
+
+public:
+ BufferMemoryObject(const uint8_t *Bytes, uint64_t Length)
+ : mBytes(Bytes), mLength(Length) {
+ }
+
+ virtual uint64_t getBase() const { return 0; }
+ virtual uint64_t getExtent() const { return mLength; }
+
+ virtual int readByte(uint64_t Addr, uint8_t *Byte) const {
+ if (Addr > getExtent())
+ return -1;
+ *Byte = mBytes[Addr];
+ return 0;
+ }
+};
+#endif
+
+}; // namespace anonymous
+
+
+namespace bcc {
+
+// Will take the ownership of @MemMgr
+CodeEmitter::CodeEmitter(CodeMemoryManager *pMemMgr)
+ : mpMemMgr(pMemMgr),
+ mpTarget(NULL),
+ mpTJI(NULL),
+ mpTD(NULL),
+ mpCurEmitFunction(NULL),
+ mpConstantPool(NULL),
+ mpJumpTable(NULL),
+ mpMMI(NULL),
+#if defined(USE_DISASSEMBLER)
+ mpAsmInfo(NULL),
+ mpDisassmbler(NULL),
+ mpIP(NULL),
+#endif
+ mpSymbolLookupFn(NULL),
+ mpSymbolLookupContext(NULL) {
+}
+
+
+CodeEmitter::~CodeEmitter() {
+ delete mpMemMgr;
+#if defined(USE_DISASSEMBLER)
+ delete mpAsmInfo;
+ delete mpDisassmbler;
+ delete mpIP;
+#endif
+}
+
+
+// Once you finish the compilation on a translation unit, you can call this
+// function to recycle the memory (which is used at compilation time and not
+// needed for runtime).
+//
+// NOTE: You should not call this funtion until the code-gen passes for a
+// given module is done. Otherwise, the results is undefined and may
+// cause the system crash!
+void CodeEmitter::releaseUnnecessary() {
+ mMBBLocations.clear();
+ mLabelLocations.clear();
+ mGlobalAddressMap.clear();
+ mFunctionToLazyStubMap.clear();
+ GlobalToIndirectSymMap.clear();
+ ExternalFnToStubMap.clear();
+ PendingFunctions.clear();
+}
+
+
+void CodeEmitter::reset() {
+ releaseUnnecessary();
+
+ mpSymbolLookupFn = NULL;
+ mpSymbolLookupContext = NULL;
+
+ mpTJI = NULL;
+ mpTD = NULL;
+
+ for (EmittedFunctionsMapTy::iterator I = mEmittedFunctions.begin(),
+ E = mEmittedFunctions.end();
+ I != E;
+ I++)
+ if (I->second != NULL)
+ delete I->second;
+ mEmittedFunctions.clear();
+
+ mpMemMgr->reset();
+}
+
+
+void *CodeEmitter::UpdateGlobalMapping(const llvm::GlobalValue *GV, void *Addr) {
+ if (Addr == NULL) {
+ // Removing mapping
+ GlobalAddressMapTy::iterator I = mGlobalAddressMap.find(GV);
+ void *OldVal;
+
+ if (I == mGlobalAddressMap.end()) {
+ OldVal = NULL;
+ } else {
+ OldVal = I->second;
+ mGlobalAddressMap.erase(I);
+ }
+
+ return OldVal;
+ }
+
+ void *&CurVal = mGlobalAddressMap[GV];
+ void *OldVal = CurVal;
+
+ CurVal = Addr;
+
+ return OldVal;
+}
+
+
+unsigned int CodeEmitter::GetConstantPoolSizeInBytes(
+ llvm::MachineConstantPool *MCP) {
+ const std::vector<llvm::MachineConstantPoolEntry> &Constants =
+ MCP->getConstants();
+
+ if (Constants.empty())
+ return 0;
+
+ unsigned int Size = 0;
+ for (int i = 0, e = Constants.size(); i != e; i++) {
+ llvm::MachineConstantPoolEntry CPE = Constants[i];
+ unsigned int AlignMask = CPE.getAlignment() - 1;
+ Size = (Size + AlignMask) & ~AlignMask;
+ const llvm::Type *Ty = CPE.getType();
+ Size += mpTD->getTypeAllocSize(Ty);
+ }
+
+ return Size;
+}
+
+// This function converts a Constant* into a GenericValue. The interesting
+// part is if C is a ConstantExpr.
+void CodeEmitter::GetConstantValue(const llvm::Constant *C,
+ llvm::GenericValue &Result) {
+ if (C->getValueID() == llvm::Value::UndefValueVal)
+ return;
+ else if (C->getValueID() == llvm::Value::ConstantExprVal) {
+ const llvm::ConstantExpr *CE = (llvm::ConstantExpr*) C;
+ const llvm::Constant *Op0 = CE->getOperand(0);
+
+ switch (CE->getOpcode()) {
+ case llvm::Instruction::GetElementPtr: {
+ // Compute the index
+ llvm::SmallVector<llvm::Value*, 8> Indices(CE->op_begin() + 1,
+ CE->op_end());
+ uint64_t Offset = mpTD->getIndexedOffset(Op0->getType(),
+ &Indices[0],
+ Indices.size());
+
+ GetConstantValue(Op0, Result);
+ Result.PointerVal =
+ static_cast<uint8_t*>(Result.PointerVal) + Offset;
+
+ return;
+ }
+ case llvm::Instruction::Trunc: {
+ uint32_t BitWidth =
+ llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
+
+ GetConstantValue(Op0, Result);
+ Result.IntVal = Result.IntVal.trunc(BitWidth);
+
+ return;
+ }
+ case llvm::Instruction::ZExt: {
+ uint32_t BitWidth =
+ llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
+
+ GetConstantValue(Op0, Result);
+ Result.IntVal = Result.IntVal.zext(BitWidth);
+
+ return;
+ }
+ case llvm::Instruction::SExt: {
+ uint32_t BitWidth =
+ llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
+
+ GetConstantValue(Op0, Result);
+ Result.IntVal = Result.IntVal.sext(BitWidth);
+
+ return;
+ }
+ case llvm::Instruction::FPTrunc: {
+ // TODO(all): fixme: long double
+ GetConstantValue(Op0, Result);
+ Result.FloatVal = static_cast<float>(Result.DoubleVal);
+ return;
+ }
+ case llvm::Instruction::FPExt: {
+ // TODO(all): fixme: long double
+ GetConstantValue(Op0, Result);
+ Result.DoubleVal = static_cast<double>(Result.FloatVal);
+ return;
+ }
+ case llvm::Instruction::UIToFP: {
+ GetConstantValue(Op0, Result);
+ if (CE->getType()->isFloatTy())
+ Result.FloatVal =
+ static_cast<float>(Result.IntVal.roundToDouble());
+ else if (CE->getType()->isDoubleTy())
+ Result.DoubleVal = Result.IntVal.roundToDouble();
+ else if (CE->getType()->isX86_FP80Ty()) {
+ const uint64_t zero[] = { 0, 0 };
+ llvm::APFloat apf(llvm::APInt(80, 2, zero));
+ apf.convertFromAPInt(Result.IntVal,
+ false,
+ llvm::APFloat::rmNearestTiesToEven);
+ Result.IntVal = apf.bitcastToAPInt();
+ }
+ return;
+ }
+ case llvm::Instruction::SIToFP: {
+ GetConstantValue(Op0, Result);
+ if (CE->getType()->isFloatTy())
+ Result.FloatVal =
+ static_cast<float>(Result.IntVal.signedRoundToDouble());
+ else if (CE->getType()->isDoubleTy())
+ Result.DoubleVal = Result.IntVal.signedRoundToDouble();
+ else if (CE->getType()->isX86_FP80Ty()) {
+ const uint64_t zero[] = { 0, 0 };
+ llvm::APFloat apf = llvm::APFloat(llvm::APInt(80, 2, zero));
+ apf.convertFromAPInt(Result.IntVal,
+ true,
+ llvm::APFloat::rmNearestTiesToEven);
+ Result.IntVal = apf.bitcastToAPInt();
+ }
+ return;
+ }
+ // double->APInt conversion handles sign
+ case llvm::Instruction::FPToUI:
+ case llvm::Instruction::FPToSI: {
+ uint32_t BitWidth =
+ llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
+
+ GetConstantValue(Op0, Result);
+ if (Op0->getType()->isFloatTy())
+ Result.IntVal =
+ llvm::APIntOps::RoundFloatToAPInt(Result.FloatVal, BitWidth);
+ else if (Op0->getType()->isDoubleTy())
+ Result.IntVal =
+ llvm::APIntOps::RoundDoubleToAPInt(Result.DoubleVal,
+ BitWidth);
+ else if (Op0->getType()->isX86_FP80Ty()) {
+ llvm::APFloat apf = llvm::APFloat(Result.IntVal);
+ uint64_t V;
+ bool Ignored;
+ apf.convertToInteger(&V,
+ BitWidth,
+ CE->getOpcode() == llvm::Instruction::FPToSI,
+ llvm::APFloat::rmTowardZero,
+ &Ignored);
+ Result.IntVal = V; // endian?
+ }
+ return;
+ }
+ case llvm::Instruction::PtrToInt: {
+ uint32_t PtrWidth = mpTD->getPointerSizeInBits();
+
+ GetConstantValue(Op0, Result);
+ Result.IntVal = llvm::APInt(PtrWidth, uintptr_t
+ (Result.PointerVal));
+
+ return;
+ }
+ case llvm::Instruction::IntToPtr: {
+ uint32_t PtrWidth = mpTD->getPointerSizeInBits();
+
+ GetConstantValue(Op0, Result);
+ if (PtrWidth != Result.IntVal.getBitWidth())
+ Result.IntVal = Result.IntVal.zextOrTrunc(PtrWidth);
+ assert(Result.IntVal.getBitWidth() <= 64 && "Bad pointer width");
+
+ Result.PointerVal =
+ llvm::PointerTy(
+ static_cast<uintptr_t>(Result.IntVal.getZExtValue()));
+
+ return;
+ }
+ case llvm::Instruction::BitCast: {
+ GetConstantValue(Op0, Result);
+ const llvm::Type *DestTy = CE->getType();
+
+ switch (Op0->getType()->getTypeID()) {
+ case llvm::Type::IntegerTyID: {
+ assert(DestTy->isFloatingPointTy() && "invalid bitcast");
+ if (DestTy->isFloatTy())
+ Result.FloatVal = Result.IntVal.bitsToFloat();
+ else if (DestTy->isDoubleTy())
+ Result.DoubleVal = Result.IntVal.bitsToDouble();
+ break;
+ }
+ case llvm::Type::FloatTyID: {
+ assert(DestTy->isIntegerTy(32) && "Invalid bitcast");
+ Result.IntVal.floatToBits(Result.FloatVal);
+ break;
+ }
+ case llvm::Type::DoubleTyID: {
+ assert(DestTy->isIntegerTy(64) && "Invalid bitcast");
+ Result.IntVal.doubleToBits(Result.DoubleVal);
+ break;
+ }
+ case llvm::Type::PointerTyID: {
+ assert(DestTy->isPointerTy() && "Invalid bitcast");
+ break; // getConstantValue(Op0) above already converted it
+ }
+ default: {
+ llvm_unreachable("Invalid bitcast operand");
+ }
+ }
+ return;
+ }
+ case llvm::Instruction::Add:
+ case llvm::Instruction::FAdd:
+ case llvm::Instruction::Sub:
+ case llvm::Instruction::FSub:
+ case llvm::Instruction::Mul:
+ case llvm::Instruction::FMul:
+ case llvm::Instruction::UDiv:
+ case llvm::Instruction::SDiv:
+ case llvm::Instruction::URem:
+ case llvm::Instruction::SRem:
+ case llvm::Instruction::And:
+ case llvm::Instruction::Or:
+ case llvm::Instruction::Xor: {
+ llvm::GenericValue LHS, RHS;
+ GetConstantValue(Op0, LHS);
+ GetConstantValue(CE->getOperand(1), RHS);
+
+ switch (Op0->getType()->getTypeID()) {
+ case llvm::Type::IntegerTyID: {
+ switch (CE->getOpcode()) {
+ case llvm::Instruction::Add: {
+ Result.IntVal = LHS.IntVal + RHS.IntVal;
+ break;
+ }
+ case llvm::Instruction::Sub: {
+ Result.IntVal = LHS.IntVal - RHS.IntVal;
+ break;
+ }
+ case llvm::Instruction::Mul: {
+ Result.IntVal = LHS.IntVal * RHS.IntVal;
+ break;
+ }
+ case llvm::Instruction::UDiv: {
+ Result.IntVal = LHS.IntVal.udiv(RHS.IntVal);
+ break;
+ }
+ case llvm::Instruction::SDiv: {
+ Result.IntVal = LHS.IntVal.sdiv(RHS.IntVal);
+ break;
+ }
+ case llvm::Instruction::URem: {
+ Result.IntVal = LHS.IntVal.urem(RHS.IntVal);
+ break;
+ }
+ case llvm::Instruction::SRem: {
+ Result.IntVal = LHS.IntVal.srem(RHS.IntVal);
+ break;
+ }
+ case llvm::Instruction::And: {
+ Result.IntVal = LHS.IntVal & RHS.IntVal;
+ break;
+ }
+ case llvm::Instruction::Or: {
+ Result.IntVal = LHS.IntVal | RHS.IntVal;
+ break;
+ }
+ case llvm::Instruction::Xor: {
+ Result.IntVal = LHS.IntVal ^ RHS.IntVal;
+ break;
+ }
+ default: {
+ llvm_unreachable("Invalid integer opcode");
+ }
+ }
+ break;
+ }
+ case llvm::Type::FloatTyID: {
+ switch (CE->getOpcode()) {
+ case llvm::Instruction::FAdd: {
+ Result.FloatVal = LHS.FloatVal + RHS.FloatVal;
+ break;
+ }
+ case llvm::Instruction::FSub: {
+ Result.FloatVal = LHS.FloatVal - RHS.FloatVal;
+ break;
+ }
+ case llvm::Instruction::FMul: {
+ Result.FloatVal = LHS.FloatVal * RHS.FloatVal;
+ break;
+ }
+ case llvm::Instruction::FDiv: {
+ Result.FloatVal = LHS.FloatVal / RHS.FloatVal;
+ break;
+ }
+ case llvm::Instruction::FRem: {
+ Result.FloatVal = ::fmodf(LHS.FloatVal, RHS.FloatVal);
+ break;
+ }
+ default: {
+ llvm_unreachable("Invalid float opcode");
+ }
+ }
+ break;
+ }
+ case llvm::Type::DoubleTyID: {
+ switch (CE->getOpcode()) {
+ case llvm::Instruction::FAdd: {
+ Result.DoubleVal = LHS.DoubleVal + RHS.DoubleVal;
+ break;
+ }
+ case llvm::Instruction::FSub: {
+ Result.DoubleVal = LHS.DoubleVal - RHS.DoubleVal;
+ break;
+ }
+ case llvm::Instruction::FMul: {
+ Result.DoubleVal = LHS.DoubleVal * RHS.DoubleVal;
+ break;
+ }
+ case llvm::Instruction::FDiv: {
+ Result.DoubleVal = LHS.DoubleVal / RHS.DoubleVal;
+ break;
+ }
+ case llvm::Instruction::FRem: {
+ Result.DoubleVal = ::fmod(LHS.DoubleVal, RHS.DoubleVal);
+ break;
+ }
+ default: {
+ llvm_unreachable("Invalid double opcode");
+ }
+ }
+ break;
+ }
+ case llvm::Type::X86_FP80TyID:
+ case llvm::Type::PPC_FP128TyID:
+ case llvm::Type::FP128TyID: {
+ llvm::APFloat apfLHS = llvm::APFloat(LHS.IntVal);
+ switch (CE->getOpcode()) {
+ case llvm::Instruction::FAdd: {
+ apfLHS.add(llvm::APFloat(RHS.IntVal),
+ llvm::APFloat::rmNearestTiesToEven);
+ break;
+ }
+ case llvm::Instruction::FSub: {
+ apfLHS.subtract(llvm::APFloat(RHS.IntVal),
+ llvm::APFloat::rmNearestTiesToEven);
+ break;
+ }
+ case llvm::Instruction::FMul: {
+ apfLHS.multiply(llvm::APFloat(RHS.IntVal),
+ llvm::APFloat::rmNearestTiesToEven);
+ break;
+ }
+ case llvm::Instruction::FDiv: {
+ apfLHS.divide(llvm::APFloat(RHS.IntVal),
+ llvm::APFloat::rmNearestTiesToEven);
+ break;
+ }
+ case llvm::Instruction::FRem: {
+ apfLHS.mod(llvm::APFloat(RHS.IntVal),
+ llvm::APFloat::rmNearestTiesToEven);
+ break;
+ }
+ default: {
+ llvm_unreachable("Invalid long double opcode");
+ }
+ }
+ Result.IntVal = apfLHS.bitcastToAPInt();
+ break;
+ }
+ default: {
+ llvm_unreachable("Bad add type!");
+ }
+ } // End switch (Op0->getType()->getTypeID())
+ return;
+ }
+ default: {
+ break;
+ }
+ } // End switch (CE->getOpcode())
+
+ std::string msg;
+ llvm::raw_string_ostream Msg(msg);
+ Msg << "ConstantExpr not handled: " << *CE;
+ llvm::report_fatal_error(Msg.str());
+ } // C->getValueID() == llvm::Value::ConstantExprVal
+
+ switch (C->getType()->getTypeID()) {
+ case llvm::Type::FloatTyID: {
+ Result.FloatVal =
+ llvm::cast<llvm::ConstantFP>(C)->getValueAPF().convertToFloat();
+ break;
+ }
+ case llvm::Type::DoubleTyID: {
+ Result.DoubleVal =
+ llvm::cast<llvm::ConstantFP>(C)->getValueAPF().convertToDouble();
+ break;
+ }
+ case llvm::Type::X86_FP80TyID:
+ case llvm::Type::FP128TyID:
+ case llvm::Type::PPC_FP128TyID: {
+ Result.IntVal =
+ llvm::cast<llvm::ConstantFP>(C)->getValueAPF().bitcastToAPInt();
+ break;
+ }
+ case llvm::Type::IntegerTyID: {
+ Result.IntVal =
+ llvm::cast<llvm::ConstantInt>(C)->getValue();
+ break;
+ }
+ case llvm::Type::PointerTyID: {
+ switch (C->getValueID()) {
+ case llvm::Value::ConstantPointerNullVal: {
+ Result.PointerVal = NULL;
+ break;
+ }
+ case llvm::Value::FunctionVal: {
+ const llvm::Function *F = static_cast<const llvm::Function*>(C);
+ Result.PointerVal =
+ GetPointerToFunctionOrStub(const_cast<llvm::Function*>(F));
+ break;
+ }
+ case llvm::Value::GlobalVariableVal: {
+ const llvm::GlobalVariable *GV =
+ static_cast<const llvm::GlobalVariable*>(C);
+ Result.PointerVal =
+ GetOrEmitGlobalVariable(const_cast<llvm::GlobalVariable*>(GV));
+ break;
+ }
+ case llvm::Value::BlockAddressVal: {
+ assert(false && "JIT does not support address-of-label yet!");
+ }
+ default: {
+ llvm_unreachable("Unknown constant pointer type!");
+ }
+ }
+ break;
+ }
+ default: {
+ std::string msg;
+ llvm::raw_string_ostream Msg(msg);
+ Msg << "ERROR: Constant unimplemented for type: " << *C->getType();
+ llvm::report_fatal_error(Msg.str());
+ break;
+ }
+ }
+ return;
+}
+
+
+// Stores the data in @Val of type @Ty at address @Addr.
+void CodeEmitter::StoreValueToMemory(const llvm::GenericValue &Val,
+ void *Addr,
+ const llvm::Type *Ty) {
+ const unsigned int StoreBytes = mpTD->getTypeStoreSize(Ty);
+
+ switch (Ty->getTypeID()) {
+ case llvm::Type::IntegerTyID: {
+ const llvm::APInt &IntVal = Val.IntVal;
+ assert(((IntVal.getBitWidth() + 7) / 8 >= StoreBytes) &&
+ "Integer too small!");
+
+ const uint8_t *Src =
+ reinterpret_cast<const uint8_t*>(IntVal.getRawData());
+
+ if (llvm::sys::isLittleEndianHost()) {
+ // Little-endian host - the source is ordered from LSB to MSB.
+ // Order the destination from LSB to MSB: Do a straight copy.
+ memcpy(Addr, Src, StoreBytes);
+ } else {
+ // Big-endian host - the source is an array of 64 bit words
+ // ordered from LSW to MSW.
+ //
+ // Each word is ordered from MSB to LSB.
+ //
+ // Order the destination from MSB to LSB:
+ // Reverse the word order, but not the bytes in a word.
+ unsigned int i = StoreBytes;
+ while (i > sizeof(uint64_t)) {
+ i -= sizeof(uint64_t);
+ ::memcpy(reinterpret_cast<uint8_t*>(Addr) + i,
+ Src,
+ sizeof(uint64_t));
+ Src += sizeof(uint64_t);
+ }
+ ::memcpy(Addr, Src + sizeof(uint64_t) - i, i);
+ }
+ break;
+ }
+ case llvm::Type::FloatTyID: {
+ *reinterpret_cast<float*>(Addr) = Val.FloatVal;
+ break;
+ }
+ case llvm::Type::DoubleTyID: {
+ *reinterpret_cast<double*>(Addr) = Val.DoubleVal;
+ break;
+ }
+ case llvm::Type::X86_FP80TyID: {
+ memcpy(Addr, Val.IntVal.getRawData(), 10);
+ break;
+ }
+ case llvm::Type::PointerTyID: {
+ // Ensure 64 bit target pointers are fully initialized on 32 bit
+ // hosts.
+ if (StoreBytes != sizeof(llvm::PointerTy))
+ memset(Addr, 0, StoreBytes);
+ *((llvm::PointerTy*) Addr) = Val.PointerVal;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (llvm::sys::isLittleEndianHost() != mpTD->isLittleEndian())
+ std::reverse(reinterpret_cast<uint8_t*>(Addr),
+ reinterpret_cast<uint8_t*>(Addr) + StoreBytes);
+
+ return;
+}
+
+
+// Recursive function to apply a @Constant value into the specified memory
+// location @Addr.
+void CodeEmitter::InitializeConstantToMemory(const llvm::Constant *C, void *Addr) {
+ switch (C->getValueID()) {
+ case llvm::Value::UndefValueVal: {
+ // Nothing to do
+ break;
+ }
+ case llvm::Value::ConstantVectorVal: {
+ // dynamic cast may hurt performance
+ const llvm::ConstantVector *CP = (llvm::ConstantVector*) C;
+
+ unsigned int ElementSize = mpTD->getTypeAllocSize
+ (CP->getType()->getElementType());
+
+ for (int i = 0, e = CP->getNumOperands(); i != e;i++)
+ InitializeConstantToMemory(
+ CP->getOperand(i),
+ reinterpret_cast<uint8_t*>(Addr) + i * ElementSize);
+ break;
+ }
+ case llvm::Value::ConstantAggregateZeroVal: {
+ memset(Addr, 0, (size_t) mpTD->getTypeAllocSize(C->getType()));
+ break;
+ }
+ case llvm::Value::ConstantArrayVal: {
+ const llvm::ConstantArray *CPA = (llvm::ConstantArray*) C;
+ unsigned int ElementSize = mpTD->getTypeAllocSize
+ (CPA->getType()->getElementType());
+
+ for (int i = 0, e = CPA->getNumOperands(); i != e; i++)
+ InitializeConstantToMemory(
+ CPA->getOperand(i),
+ reinterpret_cast<uint8_t*>(Addr) + i * ElementSize);
+ break;
+ }
+ case llvm::Value::ConstantStructVal: {
+ const llvm::ConstantStruct *CPS =
+ static_cast<const llvm::ConstantStruct*>(C);
+ const llvm::StructLayout *SL = mpTD->getStructLayout
+ (llvm::cast<llvm::StructType>(CPS->getType()));
+
+ for (int i = 0, e = CPS->getNumOperands(); i != e; i++)
+ InitializeConstantToMemory(
+ CPS->getOperand(i),
+ reinterpret_cast<uint8_t*>(Addr) + SL->getElementOffset(i));
+ break;
+ }
+ default: {
+ if (C->getType()->isFirstClassType()) {
+ llvm::GenericValue Val;
+ GetConstantValue(C, Val);
+ StoreValueToMemory(Val, Addr, C->getType());
+ } else {
+ llvm_unreachable("Unknown constant type to initialize memory "
+ "with!");
+ }
+ break;
+ }
+ }
+ return;
+}
+
+
+void CodeEmitter::emitConstantPool(llvm::MachineConstantPool *MCP) {
+ if (mpTJI->hasCustomConstantPool())
+ return;
+
+ // Constant pool address resolution is handled by the target itself in ARM
+ // (TargetJITInfo::hasCustomConstantPool() returns true).
+#if !defined(PROVIDE_ARM_CODEGEN)
+ const std::vector<llvm::MachineConstantPoolEntry> &Constants =
+ MCP->getConstants();
+
+ if (Constants.empty())
+ return;
+
+ unsigned Size = GetConstantPoolSizeInBytes(MCP);
+ unsigned Align = MCP->getConstantPoolAlignment();
+
+ mpConstantPoolBase = allocateSpace(Size, Align);
+ mpConstantPool = MCP;
+
+ if (mpConstantPoolBase == NULL)
+ return; // out of memory
+
+ unsigned Offset = 0;
+ for (int i = 0, e = Constants.size(); i != e; i++) {
+ llvm::MachineConstantPoolEntry CPE = Constants[i];
+ unsigned AlignMask = CPE.getAlignment() - 1;
+ Offset = (Offset + AlignMask) & ~AlignMask;
+
+ uintptr_t CAddr = (uintptr_t) mpConstantPoolBase + Offset;
+ mConstPoolAddresses.push_back(CAddr);
+
+ if (CPE.isMachineConstantPoolEntry())
+ llvm::report_fatal_error
+ ("Initialize memory with machine specific constant pool"
+ " entry has not been implemented!");
+
+ InitializeConstantToMemory(CPE.Val.ConstVal, (void*) CAddr);
+
+ const llvm::Type *Ty = CPE.Val.ConstVal->getType();
+ Offset += mpTD->getTypeAllocSize(Ty);
+ }
+#endif
+ return;
+}
+
+
+void CodeEmitter::initJumpTableInfo(llvm::MachineJumpTableInfo *MJTI) {
+ if (mpTJI->hasCustomJumpTables())
+ return;
+
+ const std::vector<llvm::MachineJumpTableEntry> &JT =
+ MJTI->getJumpTables();
+ if (JT.empty())
+ return;
+
+ unsigned NumEntries = 0;
+ for (int i = 0, e = JT.size(); i != e; i++)
+ NumEntries += JT[i].MBBs.size();
+
+ unsigned EntrySize = MJTI->getEntrySize(*mpTD);
+
+ mpJumpTable = MJTI;
+ mpJumpTableBase = allocateSpace(NumEntries * EntrySize,
+ MJTI->getEntryAlignment(*mpTD));
+
+ return;
+}
+
+
+void CodeEmitter::emitJumpTableInfo(llvm::MachineJumpTableInfo *MJTI) {
+ if (mpTJI->hasCustomJumpTables())
+ return;
+
+ const std::vector<llvm::MachineJumpTableEntry> &JT =
+ MJTI->getJumpTables();
+ if (JT.empty() || mpJumpTableBase == 0)
+ return;
+
+ assert(llvm::TargetMachine::getRelocationModel() == llvm::Reloc::Static &&
+ (MJTI->getEntrySize(*mpTD) == sizeof(mpTD /* a pointer type */)) &&
+ "Cross JIT'ing?");
+
+ // For each jump table, map each target in the jump table to the
+ // address of an emitted MachineBasicBlock.
+ intptr_t *SlotPtr = reinterpret_cast<intptr_t*>(mpJumpTableBase);
+ for (int i = 0, ie = JT.size(); i != ie; i++) {
+ const std::vector<llvm::MachineBasicBlock*> &MBBs = JT[i].MBBs;
+ // Store the address of the basic block for this jump table slot in the
+ // memory we allocated for the jump table in 'initJumpTableInfo'
+ for (int j = 0, je = MBBs.size(); j != je; j++)
+ *SlotPtr++ = getMachineBasicBlockAddress(MBBs[j]);
+ }
+}
+
+
+void *CodeEmitter::GetPointerToGlobal(llvm::GlobalValue *V,
+ void *Reference,
+ bool MayNeedFarStub) {
+ switch (V->getValueID()) {
+ case llvm::Value::FunctionVal: {
+ llvm::Function *F = (llvm::Function*) V;
+
+ // If we have code, go ahead and return that.
+ if (void *ResultPtr = GetPointerToGlobalIfAvailable(F))
+ return ResultPtr;
+
+ if (void *FnStub = GetLazyFunctionStubIfAvailable(F))
+ // Return the function stub if it's already created.
+ // We do this first so that:
+ // we're returning the same address for the function as any
+ // previous call.
+ //
+ // TODO(llvm.org): Yes, this is wrong. The lazy stub isn't
+ // guaranteed to be close enough to call.
+ return FnStub;
+
+ // If we know the target can handle arbitrary-distance calls, try to
+ // return a direct pointer.
+ if (!MayNeedFarStub) {
+ //
+ // x86_64 architecture may encounter the bug:
+ // http://llvm.org/bugs/show_bug.cgi?id=5201
+ // which generate instruction "call" instead of "callq".
+ //
+ // And once the real address of stub is greater than 64-bit
+ // long, the replacement will truncate to 32-bit resulting a
+ // serious problem.
+#if !defined(__x86_64__)
+ // If this is an external function pointer, we can force the JIT
+ // to 'compile' it, which really just adds it to the map.
+ if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
+ return GetPointerToFunction(F, /* AbortOnFailure = */false);
+ // Changing to false because wanting to allow later calls to
+ // mpTJI->relocate() without aborting. For caching purpose
+ }
+#endif
+ }
+
+ // Otherwise, we may need a to emit a stub, and, conservatively, we
+ // always do so.
+ return GetLazyFunctionStub(F);
+ break;
+ }
+ case llvm::Value::GlobalVariableVal: {
+ return GetOrEmitGlobalVariable((llvm::GlobalVariable*) V);
+ break;
+ }
+ case llvm::Value::GlobalAliasVal: {
+ llvm::GlobalAlias *GA = (llvm::GlobalAlias*) V;
+ const llvm::GlobalValue *GV = GA->resolveAliasedGlobal(false);
+
+ switch (GV->getValueID()) {
+ case llvm::Value::FunctionVal: {
+ // TODO(all): is there's any possibility that the function is not
+ // code-gen'd?
+ return GetPointerToFunction(
+ static_cast<const llvm::Function*>(GV),
+ /* AbortOnFailure = */false);
+ // Changing to false because wanting to allow later calls to
+ // mpTJI->relocate() without aborting. For caching purpose
+ break;
+ }
+ case llvm::Value::GlobalVariableVal: {
+ if (void *P = mGlobalAddressMap[GV])
+ return P;
+
+ llvm::GlobalVariable *GVar = (llvm::GlobalVariable*) GV;
+ EmitGlobalVariable(GVar);
+
+ return mGlobalAddressMap[GV];
+ break;
+ }
+ case llvm::Value::GlobalAliasVal: {
+ assert(false && "Alias should be resolved ultimately!");
+ }
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ llvm_unreachable("Unknown type of global value!");
+}
+
+
+// If the specified function has been code-gen'd, return a pointer to the
+// function. If not, compile it, or use a stub to implement lazy compilation
+// if available.
+void *CodeEmitter::GetPointerToFunctionOrStub(llvm::Function *F) {
+ // If we have already code generated the function, just return the
+ // address.
+ if (void *Addr = GetPointerToGlobalIfAvailable(F))
+ return Addr;
+
+ // Get a stub if the target supports it.
+ return GetLazyFunctionStub(F);
+}
+
+
+void *CodeEmitter::GetLazyFunctionStub(llvm::Function *F) {
+ // If we already have a lazy stub for this function, recycle it.
+ void *&Stub = mFunctionToLazyStubMap[F];
+ if (Stub)
+ return Stub;
+
+ // In any cases, we should NOT resolve function at runtime (though we are
+ // able to). We resolve this right now.
+ void *Actual = NULL;
+ if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
+ Actual = GetPointerToFunction(F, /* AbortOnFailure = */false);
+ // Changing to false because wanting to allow later calls to
+ // mpTJI->relocate() without aborting. For caching purpose
+ }
+
+ // Codegen a new stub, calling the actual address of the external
+ // function, if it was resolved.
+ llvm::TargetJITInfo::StubLayout SL = mpTJI->getStubLayout();
+ startGVStub(F, SL.Size, SL.Alignment);
+ Stub = mpTJI->emitFunctionStub(F, Actual, *this);
+ finishGVStub();
+
+ // We really want the address of the stub in the GlobalAddressMap for the
+ // JIT, not the address of the external function.
+ UpdateGlobalMapping(F, Stub);
+
+ if (!Actual)
+ PendingFunctions.insert(F);
+ else
+ Disassemble(F->getName(), reinterpret_cast<uint8_t*>(Stub),
+ SL.Size, true);
+
+ return Stub;
+}
+
+
+void *CodeEmitter::GetPointerToFunction(const llvm::Function *F,
+ bool AbortOnFailure) {
+ void *Addr = GetPointerToGlobalIfAvailable(F);
+ if (Addr)
+ return Addr;
+
+ assert((F->isDeclaration() || F->hasAvailableExternallyLinkage()) &&
+ "Internal error: only external defined function routes here!");
+
+ // Handle the failure resolution by ourselves.
+ Addr = GetPointerToNamedSymbol(F->getName().str().c_str(),
+ /* AbortOnFailure = */ false);
+
+ // If we resolved the symbol to a null address (eg. a weak external)
+ // return a null pointer let the application handle it.
+ if (Addr == NULL) {
+ if (AbortOnFailure)
+ llvm::report_fatal_error("Could not resolve external function "
+ "address: " + F->getName());
+ else
+ return NULL;
+ }
+
+ AddGlobalMapping(F, Addr);
+
+ return Addr;
+}
+
+
+void *CodeEmitter::GetPointerToNamedSymbol(const std::string &Name,
+ bool AbortOnFailure) {
+ if (void *Addr = FindRuntimeFunction(Name.c_str()))
+ return Addr;
+
+ if (mpSymbolLookupFn)
+ if (void *Addr = mpSymbolLookupFn(mpSymbolLookupContext, Name.c_str()))
+ return Addr;
+
+ if (AbortOnFailure)
+ llvm::report_fatal_error("Program used external symbol '" + Name +
+ "' which could not be resolved!");
+
+ return NULL;
+}
+
+
+// Return the address of the specified global variable, possibly emitting it
+// to memory if needed. This is used by the Emitter.
+void *CodeEmitter::GetOrEmitGlobalVariable(const llvm::GlobalVariable *GV) {
+ void *Ptr = GetPointerToGlobalIfAvailable(GV);
+ if (Ptr)
+ return Ptr;
+
+ if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) {
+ // If the global is external, just remember the address.
+ Ptr = GetPointerToNamedSymbol(GV->getName().str(), true);
+ AddGlobalMapping(GV, Ptr);
+ } else {
+ // If the global hasn't been emitted to memory yet, allocate space and
+ // emit it into memory.
+ Ptr = GetMemoryForGV(GV);
+ AddGlobalMapping(GV, Ptr);
+ EmitGlobalVariable(GV);
+ }
+
+ return Ptr;
+}
+
+
+// This method abstracts memory allocation of global variable so that the
+// JIT can allocate thread local variables depending on the target.
+void *CodeEmitter::GetMemoryForGV(const llvm::GlobalVariable *GV) {
+ void *Ptr;
+
+ const llvm::Type *GlobalType = GV->getType()->getElementType();
+ size_t S = mpTD->getTypeAllocSize(GlobalType);
+ size_t A = mpTD->getPreferredAlignment(GV);
+
+ if (GV->isThreadLocal()) {
+ // We can support TLS by
+ //
+ // Ptr = TJI.allocateThreadLocalMemory(S);
+ //
+ // But I tend not to.
+ // (should we disable this in the front-end (i.e., slang)?).
+ llvm::report_fatal_error
+ ("Compilation of Thread Local Storage (TLS) is disabled!");
+
+ } else if (mpTJI->allocateSeparateGVMemory()) {
+ if (A <= 8) {
+ Ptr = malloc(S);
+ } else {
+ // Allocate (S + A) bytes of memory, then use an aligned pointer
+ // within that space.
+ Ptr = malloc(S + A);
+ unsigned int MisAligned = ((intptr_t) Ptr & (A - 1));
+ Ptr = reinterpret_cast<uint8_t*>(Ptr) +
+ (MisAligned ? (A - MisAligned) : 0);
+ }
+ } else {
+ Ptr = allocateGlobal(S, A);
+ }
+
+ return Ptr;
+}
+
+
+void CodeEmitter::EmitGlobalVariable(const llvm::GlobalVariable *GV) {
+ void *GA = GetPointerToGlobalIfAvailable(GV);
+
+ if (GV->isThreadLocal())
+ llvm::report_fatal_error
+ ("We don't support Thread Local Storage (TLS)!");
+
+ if (GA == NULL) {
+ // If it's not already specified, allocate memory for the global.
+ GA = GetMemoryForGV(GV);
+ AddGlobalMapping(GV, GA);
+ }
+
+ InitializeConstantToMemory(GV->getInitializer(), GA);
+
+ // You can do some statistics on global variable here.
+ return;
+}
+
+
+void *CodeEmitter::GetPointerToGVIndirectSym(llvm::GlobalValue *V, void *Reference) {
+ // Make sure GV is emitted first, and create a stub containing the fully
+ // resolved address.
+ void *GVAddress = GetPointerToGlobal(V, Reference, false);
+
+ // If we already have a stub for this global variable, recycle it.
+ void *&IndirectSym = GlobalToIndirectSymMap[V];
+ // Otherwise, codegen a new indirect symbol.
+ if (!IndirectSym)
+ IndirectSym = mpTJI->emitGlobalValueIndirectSym(V, GVAddress, *this);
+
+ return IndirectSym;
+}
+
+
+// Return a stub for the function at the specified address.
+void *CodeEmitter::GetExternalFunctionStub(void *FnAddr) {
+ void *&Stub = ExternalFnToStubMap[FnAddr];
+ if (Stub)
+ return Stub;
+
+ llvm::TargetJITInfo::StubLayout SL = mpTJI->getStubLayout();
+ startGVStub(0, SL.Size, SL.Alignment);
+ Stub = mpTJI->emitFunctionStub(0, FnAddr, *this);
+ finishGVStub();
+
+ return Stub;
+}
+
+
+void CodeEmitter::Disassemble(const llvm::StringRef &Name,
+ uint8_t *Start, size_t Length, bool IsStub) {
+
+#if defined(USE_DISASSEMBLER)
+ llvm::raw_ostream *OS;
+
+#if defined(USE_DISASSEMBLER_FILE)
+ std::string ErrorInfo;
+ OS = new llvm::raw_fd_ostream("/data/local/tmp/out.S",
+ ErrorInfo,
+ llvm::raw_fd_ostream::F_Append);
+
+ if (!ErrorInfo.empty()) { // some errors occurred
+ // LOGE("Error in creating disassembly file");
+ delete OS;
+ return;
+ }
+#else
+ OS = &llvm::outs();
+#endif
+
+ *OS << "JIT: Disassembled code: " << Name << ((IsStub) ? " (stub)" : "")
+ << "\n";
+
+ if (mpAsmInfo == NULL)
+ mpAsmInfo = mpTarget->createAsmInfo(Compiler::Triple);
+ if (mpDisassmbler == NULL)
+ mpDisassmbler = mpTarget->createMCDisassembler();
+ if (mpIP == NULL)
+ mpIP = mpTarget->createMCInstPrinter(mpAsmInfo->getAssemblerDialect(),
+ *mpAsmInfo);
+
+ const BufferMemoryObject *BufferMObj = new BufferMemoryObject(Start,
+ Length);
+ uint64_t Size;
+ uint64_t Index;
+
+ for (Index = 0; Index < Length; Index += Size) {
+ llvm::MCInst Inst;
+
+ if (mpDisassmbler->getInstruction(Inst, Size, *BufferMObj, Index,
+ /* REMOVED */ llvm::nulls())) {
+ (*OS).indent(4)
+ .write("0x", 2)
+ .write_hex((uint32_t) Start + Index)
+ .write(':');
+ mpIP->printInst(&Inst, *OS);
+ *OS << "\n";
+ } else {
+ if (Size == 0)
+ Size = 1; // skip illegible bytes
+ }
+ }
+
+ *OS << "\n";
+ delete BufferMObj;
+
+#if defined(USE_DISASSEMBLER_FILE)
+ // If you want the disassemble results write to file, uncomment this.
+ OS->close();
+ delete OS;
+#endif
+
+#endif // defined(USE_DISASSEMBLER)
+}
+
+
+void CodeEmitter::setTargetMachine(llvm::TargetMachine &TM) {
+ // Set Target
+ mpTarget = &TM.getTarget();
+ // Set TargetJITInfo
+ mpTJI = TM.getJITInfo();
+ // set TargetData
+ mpTD = TM.getTargetData();
+
+ assert(!mpTJI->needsGOT() && "We don't support GOT needed target!");
+
+ return;
+}
+
+
+// This callback is invoked when the specified function is about to be code
+// generated. This initializes the BufferBegin/End/Ptr fields.
+void CodeEmitter::startFunction(llvm::MachineFunction &F) {
+ uintptr_t ActualSize = 0;
+
+ mpMemMgr->setMemoryWritable();
+
+ // BufferBegin, BufferEnd and CurBufferPtr are all inherited from class
+ // MachineCodeEmitter, which is the super class of the class
+ // JITCodeEmitter.
+ //
+ // BufferBegin/BufferEnd - Pointers to the start and end of the memory
+ // allocated for this code buffer.
+ //
+ // CurBufferPtr - Pointer to the next byte of memory to fill when emitting
+ // code. This is guranteed to be in the range
+ // [BufferBegin, BufferEnd]. If this pointer is at
+ // BufferEnd, it will never move due to code emission, and
+ // all code emission requests will be ignored (this is the
+ // buffer overflow condition).
+ BufferBegin = CurBufferPtr =
+ mpMemMgr->startFunctionBody(F.getFunction(), ActualSize);
+ BufferEnd = BufferBegin + ActualSize;
+
+ if (mpCurEmitFunction == NULL)
+ mpCurEmitFunction = new EmittedFuncEntry();
+ mpCurEmitFunction->FunctionBody = BufferBegin;
+
+ // Ensure the constant pool/jump table info is at least 4-byte aligned.
+ emitAlignment(16);
+
+ emitConstantPool(F.getConstantPool());
+ if (llvm::MachineJumpTableInfo *MJTI = F.getJumpTableInfo())
+ initJumpTableInfo(MJTI);
+
+ // About to start emitting the machine code for the function.
+ emitAlignment(std::max(F.getFunction()->getAlignment(), 8U));
+
+ UpdateGlobalMapping(F.getFunction(), CurBufferPtr);
+
+ mpCurEmitFunction->Code = CurBufferPtr;
+
+ mMBBLocations.clear();
+}
+
+
+// This callback is invoked when the specified function has finished code
+// generation. If a buffer overflow has occurred, this method returns true
+// (the callee is required to try again).
+bool CodeEmitter::finishFunction(llvm::MachineFunction &F) {
+ if (CurBufferPtr == BufferEnd) {
+ // No enough memory
+ mpMemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
+ return false;
+ }
+
+ if (llvm::MachineJumpTableInfo *MJTI = F.getJumpTableInfo())
+ emitJumpTableInfo(MJTI);
+
+ // FnStart is the start of the text, not the start of the constant pool
+ // and other per-function data.
+ uint8_t *FnStart =
+ reinterpret_cast<uint8_t*>(
+ GetPointerToGlobalIfAvailable(F.getFunction()));
+
+ // FnEnd is the end of the function's machine code.
+ uint8_t *FnEnd = CurBufferPtr;
+
+ if (!mRelocations.empty()) {
+ ptrdiff_t BufferOffset = BufferBegin - mpMemMgr->getCodeMemBase();
+
+ // Resolve the relocations to concrete pointers.
+ for (int i = 0, e = mRelocations.size(); i != e; i++) {
+ llvm::MachineRelocation &MR = mRelocations[i];
+ void *ResultPtr = NULL;
+
+ if (!MR.letTargetResolve()) {
+ if (MR.isExternalSymbol()) {
+ ResultPtr = GetPointerToNamedSymbol(MR.getExternalSymbol(), true);
+
+ if (MR.mayNeedFarStub()) {
+ ResultPtr = GetExternalFunctionStub(ResultPtr);
+ }
+
+ } else if (MR.isGlobalValue()) {
+ ResultPtr = GetPointerToGlobal(MR.getGlobalValue(),
+ BufferBegin
+ + MR.getMachineCodeOffset(),
+ MR.mayNeedFarStub());
+ } else if (MR.isIndirectSymbol()) {
+ ResultPtr =
+ GetPointerToGVIndirectSym(
+ MR.getGlobalValue(),
+ BufferBegin + MR.getMachineCodeOffset());
+ } else if (MR.isBasicBlock()) {
+ ResultPtr =
+ (void*) getMachineBasicBlockAddress(MR.getBasicBlock());
+ } else if (MR.isConstantPoolIndex()) {
+ ResultPtr =
+ (void*) getConstantPoolEntryAddress(MR.getConstantPoolIndex());
+ } else {
+ assert(MR.isJumpTableIndex() && "Unknown type of relocation");
+ ResultPtr =
+ (void*) getJumpTableEntryAddress(MR.getJumpTableIndex());
+ }
+
+ if (!MR.isExternalSymbol() || MR.mayNeedFarStub()) {
+ // TODO(logan): Cache external symbol relocation entry.
+ // Currently, we are not caching them. But since Android
+ // system is using prelink, it is not a problem.
+
+ // Cache the relocation result address
+ mCachingRelocations.push_back(
+ oBCCRelocEntry(MR.getRelocationType(),
+ MR.getMachineCodeOffset() + BufferOffset,
+ ResultPtr));
+ }
+
+ MR.setResultPointer(ResultPtr);
+ }
+ }
+
+ mpTJI->relocate(BufferBegin, &mRelocations[0], mRelocations.size(),
+ mpMemMgr->getGOTBase());
+ }
+
+ mpMemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
+ // CurBufferPtr may have moved beyond FnEnd, due to memory allocation for
+ // global variables that were referenced in the relocations.
+ if (CurBufferPtr == BufferEnd)
+ return false;
+
+ // Now that we've succeeded in emitting the function.
+ mpCurEmitFunction->Size = CurBufferPtr - BufferBegin;
+ BufferBegin = CurBufferPtr = 0;
+
+ if (F.getFunction()->hasName())
+ mEmittedFunctions[F.getFunction()->getNameStr()] = mpCurEmitFunction;
+ mpCurEmitFunction = NULL;
+
+ mRelocations.clear();
+ mConstPoolAddresses.clear();
+
+ if (mpMMI)
+ mpMMI->EndFunction();
+
+ updateFunctionStub(F.getFunction());
+
+ // Mark code region readable and executable if it's not so already.
+ mpMemMgr->setMemoryExecutable();
+
+ Disassemble(F.getFunction()->getName(), FnStart, FnEnd - FnStart, false);
+
+ return false;
+}
+
+
+void CodeEmitter::startGVStub(const llvm::GlobalValue *GV, unsigned StubSize,
+ unsigned Alignment) {
+ mpSavedBufferBegin = BufferBegin;
+ mpSavedBufferEnd = BufferEnd;
+ mpSavedCurBufferPtr = CurBufferPtr;
+
+ BufferBegin = CurBufferPtr = mpMemMgr->allocateStub(GV, StubSize,
+ Alignment);
+ BufferEnd = BufferBegin + StubSize + 1;
+
+ return;
+}
+
+
+void CodeEmitter::startGVStub(void *Buffer, unsigned StubSize) {
+ mpSavedBufferBegin = BufferBegin;
+ mpSavedBufferEnd = BufferEnd;
+ mpSavedCurBufferPtr = CurBufferPtr;
+
+ BufferBegin = CurBufferPtr = reinterpret_cast<uint8_t *>(Buffer);
+ BufferEnd = BufferBegin + StubSize + 1;
+
+ return;
+}
+
+
+void CodeEmitter::finishGVStub() {
+ assert(CurBufferPtr != BufferEnd && "Stub overflowed allocated space.");
+
+ // restore
+ BufferBegin = mpSavedBufferBegin;
+ BufferEnd = mpSavedBufferEnd;
+ CurBufferPtr = mpSavedCurBufferPtr;
+}
+
+
+// Allocates and fills storage for an indirect GlobalValue, and returns the
+// address.
+void *CodeEmitter::allocIndirectGV(const llvm::GlobalValue *GV,
+ const uint8_t *Buffer, size_t Size,
+ unsigned Alignment) {
+ uint8_t *IndGV = mpMemMgr->allocateStub(GV, Size, Alignment);
+ memcpy(IndGV, Buffer, Size);
+ return IndGV;
+}
+
+
+// Allocate memory for a global. Unlike allocateSpace, this method does not
+// allocate memory in the current output buffer, because a global may live
+// longer than the current function.
+void *CodeEmitter::allocateGlobal(uintptr_t Size, unsigned Alignment) {
+ // Delegate this call through the memory manager.
+ return mpMemMgr->allocateGlobal(Size, Alignment);
+}
+
+
+// This should be called by the target when a new basic block is about to be
+// emitted. This way the MCE knows where the start of the block is, and can
+// implement getMachineBasicBlockAddress.
+void CodeEmitter::StartMachineBasicBlock(llvm::MachineBasicBlock *MBB) {
+ if (mMBBLocations.size() <= (unsigned) MBB->getNumber())
+ mMBBLocations.resize((MBB->getNumber() + 1) * 2);
+ mMBBLocations[MBB->getNumber()] = getCurrentPCValue();
+ return;
+}
+
+
+// Return the address of the jump table with index @Index in the function
+// that last called initJumpTableInfo.
+uintptr_t CodeEmitter::getJumpTableEntryAddress(unsigned Index) const {
+ const std::vector<llvm::MachineJumpTableEntry> &JT =
+ mpJumpTable->getJumpTables();
+
+ assert((Index < JT.size()) && "Invalid jump table index!");
+
+ unsigned int Offset = 0;
+ unsigned int EntrySize = mpJumpTable->getEntrySize(*mpTD);
+
+ for (unsigned i = 0; i < Index; i++)
+ Offset += JT[i].MBBs.size();
+ Offset *= EntrySize;
+
+ return (uintptr_t)(reinterpret_cast<uint8_t*>(mpJumpTableBase) + Offset);
+}
+
+
+// Return the address of the specified MachineBasicBlock, only usable after
+// the label for the MBB has been emitted.
+uintptr_t CodeEmitter::getMachineBasicBlockAddress(
+ llvm::MachineBasicBlock *MBB) const {
+ assert(mMBBLocations.size() > (unsigned) MBB->getNumber() &&
+ mMBBLocations[MBB->getNumber()] &&
+ "MBB not emitted!");
+ return mMBBLocations[MBB->getNumber()];
+}
+
+
+void CodeEmitter::updateFunctionStub(const llvm::Function *F) {
+ // Get the empty stub we generated earlier.
+ void *Stub;
+ std::set<const llvm::Function*>::iterator I = PendingFunctions.find(F);
+ if (I != PendingFunctions.end())
+ Stub = mFunctionToLazyStubMap[F];
+ else
+ return;
+
+ void *Addr = GetPointerToGlobalIfAvailable(F);
+
+ assert(Addr != Stub &&
+ "Function must have non-stub address to be updated.");
+
+ // Tell the target jit info to rewrite the stub at the specified address,
+ // rather than creating a new one.
+ llvm::TargetJITInfo::StubLayout SL = mpTJI->getStubLayout();
+ startGVStub(Stub, SL.Size);
+ mpTJI->emitFunctionStub(F, Addr, *this);
+ finishGVStub();
+
+ Disassemble(F->getName(), reinterpret_cast<uint8_t*>(Stub),
+ SL.Size, true);
+
+ PendingFunctions.erase(I);
+}
+
+
+void *CodeEmitter::lookup(const llvm::StringRef &Name) {
+ EmittedFunctionsMapTy::const_iterator
+ I = mEmittedFunctions.find(Name.str());
+
+ return (I == mEmittedFunctions.end()) ? NULL : I->second->Code;
+}
+
+
+void CodeEmitter::getFunctionNames(BCCsizei *actualFunctionCount,
+ BCCsizei maxFunctionCount,
+ BCCchar **functions) {
+ int functionCount = mEmittedFunctions.size();
+
+ if (actualFunctionCount)
+ *actualFunctionCount = functionCount;
+ if (functionCount > maxFunctionCount)
+ functionCount = maxFunctionCount;
+ if (functions)
+ for (EmittedFunctionsMapTy::const_iterator
+ I = mEmittedFunctions.begin(), E = mEmittedFunctions.end();
+ I != E && (functionCount > 0); I++, functionCount--) {
+ *functions++ = const_cast<BCCchar*>(I->first.c_str());
+ }
+}
+
+
+void CodeEmitter::getFunctionBinary(BCCchar *label,
+ BCCvoid **base,
+ BCCsizei *length) {
+ EmittedFunctionsMapTy::const_iterator I = mEmittedFunctions.find(label);
+ if (I == mEmittedFunctions.end()) {
+ *base = NULL;
+ *length = 0;
+ } else {
+ *base = I->second->Code;
+ *length = I->second->Size;
+ }
+}
+
+} // namespace bcc
diff --git a/lib/bcc/CodeEmitter.h b/lib/bcc/CodeEmitter.h
new file mode 100644
index 0000000..90e95ca
--- /dev/null
+++ b/lib/bcc/CodeEmitter.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_CODEEMITTER_H
+#define BCC_CODEEMITTER_H
+
+#include <bcc/bcc.h>
+#include <bcc/bcc_cache.h>
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/MachineRelocation.h"
+#include "llvm/CodeGen/JITCodeEmitter.h"
+#include "llvm/Support/ValueHandle.h"
+
+#include <map>
+#include <vector>
+#include <set>
+
+#include <assert.h>
+#include <stdint.h>
+
+namespace llvm {
+ class Constant;
+ class GenericValue;
+ class GlobalVariable;
+ class GlobalValue;
+ class Function;
+ class MachineBasicBlock;
+ class MachineConstantPool;
+ class MachineFunction;
+ class MachineJumpTableInfo;
+ class MachineModuleInfo;
+#if defined(USE_DISASSEMBLER)
+ class MCAsmInfo;
+ class MCDisassembler;
+ class MCInstPrinter;
+#endif
+ class MCSymbol;
+ class Target;
+ class TargetData;
+ class TargetJITInfo;
+ class TargetMachine;
+ class Type;
+}
+
+namespace bcc {
+ class CodeMemoryManager;
+ class EmittedFuncEntry;
+
+ class CodeEmitter : public llvm::JITCodeEmitter {
+ public:
+ typedef llvm::DenseMap<const llvm::GlobalValue*, void*> GlobalAddressMapTy;
+ typedef GlobalAddressMapTy::const_iterator global_addresses_const_iterator;
+
+ GlobalAddressMapTy mGlobalAddressMap;
+
+ private:
+ CodeMemoryManager *mpMemMgr;
+
+ // The JITInfo for the target we are compiling to
+ const llvm::Target *mpTarget;
+
+ llvm::TargetJITInfo *mpTJI;
+
+ const llvm::TargetData *mpTD;
+
+ EmittedFuncEntry *mpCurEmitFunction;
+
+ typedef std::map<const std::string,
+ EmittedFuncEntry *> EmittedFunctionsMapTy;
+ EmittedFunctionsMapTy mEmittedFunctions;
+
+ // This vector is a mapping from MBB ID's to their address. It is filled in
+ // by the StartMachineBasicBlock callback and queried by the
+ // getMachineBasicBlockAddress callback.
+ std::vector<uintptr_t> mMBBLocations;
+
+ // The constant pool for the current function.
+ llvm::MachineConstantPool *mpConstantPool;
+
+ // A pointer to the first entry in the constant pool.
+ void *mpConstantPoolBase;
+
+ // Addresses of individual constant pool entries.
+ llvm::SmallVector<uintptr_t, 8> mConstPoolAddresses;
+
+ // The jump tables for the current function.
+ llvm::MachineJumpTableInfo *mpJumpTable;
+
+ // A pointer to the first entry in the jump table.
+ void *mpJumpTableBase;
+
+ // When outputting a function stub in the context of some other function, we
+ // save BufferBegin/BufferEnd/CurBufferPtr here.
+ uint8_t *mpSavedBufferBegin, *mpSavedBufferEnd, *mpSavedCurBufferPtr;
+
+ // These are the relocations that the function needs, as emitted.
+ std::vector<llvm::MachineRelocation> mRelocations;
+
+ std::vector<oBCCRelocEntry> mCachingRelocations;
+
+ // This vector is a mapping from Label ID's to their address.
+ llvm::DenseMap<llvm::MCSymbol*, uintptr_t> mLabelLocations;
+
+ // Machine module info for exception informations
+ llvm::MachineModuleInfo *mpMMI;
+
+ // Replace an existing mapping for GV with a new address. This updates both
+ // maps as required. If Addr is null, the entry for the global is removed
+ // from the mappings.
+ void *UpdateGlobalMapping(const llvm::GlobalValue *GV, void *Addr);
+
+ // Tell the execution engine that the specified global is at the specified
+ // location. This is used internally as functions are JIT'd and as global
+ // variables are laid out in memory.
+ void AddGlobalMapping(const llvm::GlobalValue *GV, void *Addr) {
+ void *&CurVal = mGlobalAddressMap[GV];
+ assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
+ CurVal = Addr;
+ }
+
+ // This returns the address of the specified global value if it is has
+ // already been codegen'd, otherwise it returns null.
+ void *GetPointerToGlobalIfAvailable(const llvm::GlobalValue *GV) {
+ GlobalAddressMapTy::iterator I = mGlobalAddressMap.find(GV);
+ return ((I != mGlobalAddressMap.end()) ? I->second : NULL);
+ }
+
+ unsigned int GetConstantPoolSizeInBytes(llvm::MachineConstantPool *MCP);
+
+ // This function converts a Constant* into a GenericValue. The interesting
+ // part is if C is a ConstantExpr.
+ void GetConstantValue(const llvm::Constant *C, llvm::GenericValue &Result);
+
+ // Stores the data in @Val of type @Ty at address @Addr.
+ void StoreValueToMemory(const llvm::GenericValue &Val, void *Addr,
+ const llvm::Type *Ty);
+
+ // Recursive function to apply a @Constant value into the specified memory
+ // location @Addr.
+ void InitializeConstantToMemory(const llvm::Constant *C, void *Addr);
+
+ void emitConstantPool(llvm::MachineConstantPool *MCP);
+
+ void initJumpTableInfo(llvm::MachineJumpTableInfo *MJTI);
+
+ void emitJumpTableInfo(llvm::MachineJumpTableInfo *MJTI);
+
+ void *GetPointerToGlobal(llvm::GlobalValue *V,
+ void *Reference,
+ bool MayNeedFarStub);
+
+ // If the specified function has been code-gen'd, return a pointer to the
+ // function. If not, compile it, or use a stub to implement lazy compilation
+ // if available.
+ void *GetPointerToFunctionOrStub(llvm::Function *F);
+
+ typedef llvm::DenseMap<const llvm::Function*,
+ void*> FunctionToLazyStubMapTy;
+ FunctionToLazyStubMapTy mFunctionToLazyStubMap;
+
+ void *GetLazyFunctionStubIfAvailable(llvm::Function *F) {
+ return mFunctionToLazyStubMap.lookup(F);
+ }
+
+ std::set<const llvm::Function*> PendingFunctions;
+ void *GetLazyFunctionStub(llvm::Function *F);
+
+ void *GetPointerToFunction(const llvm::Function *F, bool AbortOnFailure);
+
+ void *GetPointerToNamedSymbol(const std::string &Name,
+ bool AbortOnFailure);
+
+ // Return the address of the specified global variable, possibly emitting it
+ // to memory if needed. This is used by the Emitter.
+ void *GetOrEmitGlobalVariable(const llvm::GlobalVariable *GV);
+
+ // This method abstracts memory allocation of global variable so that the
+ // JIT can allocate thread local variables depending on the target.
+ void *GetMemoryForGV(const llvm::GlobalVariable *GV);
+
+ void EmitGlobalVariable(const llvm::GlobalVariable *GV);
+
+ typedef std::map<llvm::AssertingVH<llvm::GlobalValue>,
+ void *> GlobalToIndirectSymMapTy;
+
+ GlobalToIndirectSymMapTy GlobalToIndirectSymMap;
+
+ void *GetPointerToGVIndirectSym(llvm::GlobalValue *V, void *Reference);
+
+ // This is the equivalent of FunctionToLazyStubMap for external functions.
+ //
+ // TODO(llvm.org): Of course, external functions don't need a lazy stub.
+ // It's actually here to make it more likely that far calls
+ // succeed, but no single stub can guarantee that. I'll
+ // remove this in a subsequent checkin when I actually fix
+ // far calls.
+ std::map<void*, void*> ExternalFnToStubMap;
+
+ // Return a stub for the function at the specified address.
+ void *GetExternalFunctionStub(void *FnAddr);
+
+#if defined(USE_DISASSEMBLER)
+ const llvm::MCAsmInfo *mpAsmInfo;
+ const llvm::MCDisassembler *mpDisassmbler;
+ llvm::MCInstPrinter *mpIP;
+#endif
+
+ public:
+ void Disassemble(const llvm::StringRef &Name, uint8_t *Start,
+ size_t Length, bool IsStub);
+
+ private:
+ // Resolver to undefined symbol in CodeEmitter
+ BCCSymbolLookupFn mpSymbolLookupFn;
+ void *mpSymbolLookupContext;
+
+ public:
+ // Will take the ownership of @MemMgr
+ explicit CodeEmitter(CodeMemoryManager *pMemMgr);
+
+ virtual ~CodeEmitter();
+
+ global_addresses_const_iterator global_address_begin() const {
+ return mGlobalAddressMap.begin();
+ }
+
+ global_addresses_const_iterator global_address_end() const {
+ return mGlobalAddressMap.end();
+ }
+
+ std::vector<oBCCRelocEntry> const &getCachingRelocations() const {
+ return mCachingRelocations;
+ }
+
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
+ mpSymbolLookupFn = pFn;
+ mpSymbolLookupContext = pContext;
+ }
+
+ void setTargetMachine(llvm::TargetMachine &TM);
+
+ // This callback is invoked when the specified function is about to be code
+ // generated. This initializes the BufferBegin/End/Ptr fields.
+ virtual void startFunction(llvm::MachineFunction &F);
+
+ // This callback is invoked when the specified function has finished code
+ // generation. If a buffer overflow has occurred, this method returns true
+ // (the callee is required to try again).
+ virtual bool finishFunction(llvm::MachineFunction &F);
+
+ void startGVStub(const llvm::GlobalValue *GV, unsigned StubSize,
+ unsigned Alignment);
+
+ void startGVStub(void *Buffer, unsigned StubSize);
+
+ void finishGVStub();
+
+ // Allocates and fills storage for an indirect GlobalValue, and returns the
+ // address.
+ virtual void *allocIndirectGV(const llvm::GlobalValue *GV,
+ const uint8_t *Buffer, size_t Size,
+ unsigned Alignment);
+
+ // Emits a label
+ void emitLabel(llvm::MCSymbol *Label) {
+ mLabelLocations[Label] = getCurrentPCValue();
+ }
+
+ // Allocate memory for a global. Unlike allocateSpace, this method does not
+ // allocate memory in the current output buffer, because a global may live
+ // longer than the current function.
+ virtual void *allocateGlobal(uintptr_t Size, unsigned Alignment);
+
+ // This should be called by the target when a new basic block is about to be
+ // emitted. This way the MCE knows where the start of the block is, and can
+ // implement getMachineBasicBlockAddress.
+ virtual void StartMachineBasicBlock(llvm::MachineBasicBlock *MBB);
+
+ // Whenever a relocatable address is needed, it should be noted with this
+ // interface.
+ virtual void addRelocation(const llvm::MachineRelocation &MR) {
+ mRelocations.push_back(MR);
+ }
+
+ // Return the address of the @Index entry in the constant pool that was
+ // last emitted with the emitConstantPool method.
+ virtual uintptr_t getConstantPoolEntryAddress(unsigned Index) const {
+ assert(Index < mpConstantPool->getConstants().size() &&
+ "Invalid constant pool index!");
+ return mConstPoolAddresses[Index];
+ }
+
+ // Return the address of the jump table with index @Index in the function
+ // that last called initJumpTableInfo.
+ virtual uintptr_t getJumpTableEntryAddress(unsigned Index) const;
+
+ // Return the address of the specified MachineBasicBlock, only usable after
+ // the label for the MBB has been emitted.
+ virtual uintptr_t getMachineBasicBlockAddress(
+ llvm::MachineBasicBlock *MBB) const;
+
+ // Return the address of the specified LabelID, only usable after the
+ // LabelID has been emitted.
+ virtual uintptr_t getLabelAddress(llvm::MCSymbol *Label) const {
+ assert(mLabelLocations.count(Label) && "Label not emitted!");
+ return mLabelLocations.find(Label)->second;
+ }
+
+ // Specifies the MachineModuleInfo object. This is used for exception
+ // handling purposes.
+ virtual void setModuleInfo(llvm::MachineModuleInfo *Info) {
+ mpMMI = Info;
+ }
+
+ void updateFunctionStub(const llvm::Function *F);
+
+ void releaseUnnecessary();
+
+ void reset();
+
+ void *lookup(const char *Name) {
+ return lookup( llvm::StringRef(Name) );
+ }
+
+ void *lookup(const llvm::StringRef &Name);
+
+ void getFunctionNames(BCCsizei *actualFunctionCount,
+ BCCsizei maxFunctionCount,
+ BCCchar **functions);
+
+ void getFunctionBinary(BCCchar *label,
+ BCCvoid **base,
+ BCCsizei *length);
+ };
+
+} // namespace bcc
+
+#endif // BCC_CODEEMITTER_H
diff --git a/lib/bcc/CodeMemoryManager.cpp b/lib/bcc/CodeMemoryManager.cpp
new file mode 100644
index 0000000..62478be
--- /dev/null
+++ b/lib/bcc/CodeMemoryManager.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+
+#include "CodeMemoryManager.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+#include <errno.h>
+#include <sys/mman.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+
+namespace bcc {
+
+
+const unsigned int MaxCodeSize = BCC_MMAP_IMG_CODE_SIZE;
+const unsigned int MaxGOTSize = 1 * 1024;
+const unsigned int MaxGlobalVarSize = BCC_MMAP_IMG_DATA_SIZE;
+
+
+CodeMemoryManager::CodeMemoryManager()
+ : mpCodeMem(NULL), mpGVMem(NULL), mpGOTBase(NULL) {
+
+ reset();
+ std::string ErrMsg;
+
+ // Try to use fixed address
+
+ // Note: If we failed to allocate mpCodeMem at fixed address,
+ // the caching mechanism has to either perform relocation or
+ // give up. If the caching mechanism gives up, then we have to
+ // recompile the bitcode and wasting a lot of time.
+
+ for (size_t i = 0; i < BCC_MMAP_IMG_COUNT; ++i) {
+ if (Compiler::BccMmapImgAddrTaken[i]) {
+ // The address BCC_MMAP_IMG_BEGIN + i * BCC_MMAP_IMG_SIZE has
+ // been taken.
+ continue;
+ }
+
+ // Occupy the mmap image address first (No matter allocation
+ // success or not. Keep occupying if succeed; otherwise,
+ // keep occupying as a mark of failure.)
+ Compiler::BccMmapImgAddrTaken[i] = true;
+
+ void *currMmapImgAddr =
+ reinterpret_cast<void *>(BCC_MMAP_IMG_BEGIN + i * BCC_MMAP_IMG_SIZE);
+
+ mpCodeMem = mmap(currMmapImgAddr, BCC_MMAP_IMG_SIZE,
+ PROT_READ | PROT_EXEC | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+ -1, 0);
+
+ if (mpCodeMem == MAP_FAILED) {
+ LOGE("Mmap mpCodeMem at %p failed with reason: %s. Retrying ..\n",
+ currMmapImgAddr, strerror(errno));
+ } else {
+ // Good, we have got one mmap image address.
+ break;
+ }
+ }
+
+ if (!mpCodeMem || mpCodeMem == MAP_FAILED) {
+ LOGE("Try to allocate mpCodeMem at arbitary address.\n");
+
+ mpCodeMem = mmap(NULL, BCC_MMAP_IMG_SIZE,
+ PROT_READ | PROT_EXEC | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+
+ if (mpCodeMem == MAP_FAILED) {
+ LOGE("Unable to mmap mpCodeMem with reason: %s.\n", strerror(errno));
+ llvm::report_fatal_error("Failed to allocate memory for emitting "
+ "codes\n" + ErrMsg);
+ }
+ }
+
+ LOGE("Mmap mpCodeMem at %p successfully.\n", mpCodeMem);
+
+ // Set global variable pool
+ mpGVMem = (void *) ((char *)mpCodeMem + MaxCodeSize);
+
+ return;
+}
+
+
+CodeMemoryManager::~CodeMemoryManager() {
+ if (mpCodeMem && mpCodeMem != MAP_FAILED) {
+ munmap(mpCodeMem, BCC_MMAP_IMG_SIZE);
+
+ // TODO(logan): Reset Compiler::BccMmapImgAddrTaken[i] to false, so
+ // that the address can be reused.
+ }
+
+ mpCodeMem = 0;
+ mpGVMem = 0;
+}
+
+
+uint8_t *CodeMemoryManager::allocateSGMemory(uintptr_t Size,
+ unsigned Alignment) {
+
+ intptr_t FreeMemSize = getFreeCodeMemSize();
+ if ((FreeMemSize < 0) || (static_cast<uintptr_t>(FreeMemSize) < Size))
+ // The code size excesses our limit
+ return NULL;
+
+ if (Alignment == 0)
+ Alignment = 1;
+
+ uint8_t *result = getCodeMemBase() + mCurSGMemIdx - Size;
+ result = (uint8_t*) (((intptr_t) result) & ~(intptr_t) (Alignment - 1));
+
+ mCurSGMemIdx = result - getCodeMemBase();
+
+ return result;
+}
+
+
+// setMemoryWritable - When code generation is in progress, the code pages
+// may need permissions changed.
+void CodeMemoryManager::setMemoryWritable() {
+ mprotect(mpCodeMem, MaxCodeSize, PROT_READ | PROT_WRITE | PROT_EXEC);
+}
+
+
+// When code generation is done and we're ready to start execution, the
+// code pages may need permissions changed.
+void CodeMemoryManager::setMemoryExecutable() {
+ mprotect(mpCodeMem, MaxCodeSize, PROT_READ | PROT_EXEC);
+}
+
+
+// Setting this flag to true makes the memory manager garbage values over
+// freed memory. This is useful for testing and debugging, and is to be
+// turned on by default in debug mode.
+void CodeMemoryManager::setPoisonMemory(bool poison) {
+ // no effect
+}
+
+
+// Global Offset Table Management
+
+// If the current table requires a Global Offset Table, this method is
+// invoked to allocate it. This method is required to set HasGOT to true.
+void CodeMemoryManager::AllocateGOT() {
+ assert(mpGOTBase != NULL && "Cannot allocate the GOT multiple times");
+ mpGOTBase = allocateSGMemory(MaxGOTSize);
+ HasGOT = true;
+}
+
+
+// Main Allocation Functions
+
+// When we start JITing a function, the JIT calls this method to allocate a
+// block of free RWX memory, which returns a pointer to it. If the JIT wants
+// to request a block of memory of at least a certain size, it passes that
+// value as ActualSize, and this method returns a block with at least that
+// much space. If the JIT doesn't know ahead of time how much space it will
+// need to emit the function, it passes 0 for the ActualSize. In either
+// case, this method is required to pass back the size of the allocated
+// block through ActualSize. The JIT will be careful to not write more than
+// the returned ActualSize bytes of memory.
+uint8_t *CodeMemoryManager::startFunctionBody(const llvm::Function *F,
+ uintptr_t &ActualSize) {
+ intptr_t FreeMemSize = getFreeCodeMemSize();
+ if ((FreeMemSize < 0) ||
+ (static_cast<uintptr_t>(FreeMemSize) < ActualSize))
+ // The code size excesses our limit
+ return NULL;
+
+ ActualSize = getFreeCodeMemSize();
+ return (getCodeMemBase() + mCurFuncMemIdx);
+}
+
+// This method is called when the JIT is done codegen'ing the specified
+// function. At this point we know the size of the JIT compiled function.
+// This passes in FunctionStart (which was returned by the startFunctionBody
+// method) and FunctionEnd which is a pointer to the actual end of the
+// function. This method should mark the space allocated and remember where
+// it is in case the client wants to deallocate it.
+void CodeMemoryManager::endFunctionBody(const llvm::Function *F,
+ uint8_t *FunctionStart,
+ uint8_t *FunctionEnd) {
+ assert(FunctionEnd > FunctionStart);
+ assert(FunctionStart == (getCodeMemBase() + mCurFuncMemIdx) &&
+ "Mismatched function start/end!");
+
+ // Advance the pointer
+ intptr_t FunctionCodeSize = FunctionEnd - FunctionStart;
+ assert(FunctionCodeSize <= getFreeCodeMemSize() &&
+ "Code size excess the limitation!");
+ mCurFuncMemIdx += FunctionCodeSize;
+
+ // Record there's a function in our memory start from @FunctionStart
+ assert(mFunctionMap.find(F) == mFunctionMap.end() &&
+ "Function already emitted!");
+ mFunctionMap.insert(
+ std::make_pair<const llvm::Function*, std::pair<void*, void*> >(
+ F, std::make_pair(FunctionStart, FunctionEnd)));
+
+ return;
+}
+
+// Allocate a (function code) memory block of the given size. This method
+// cannot be called between calls to startFunctionBody and endFunctionBody.
+uint8_t *CodeMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {
+ if (getFreeCodeMemSize() < Size) {
+ // The code size excesses our limit
+ return NULL;
+ }
+
+ if (Alignment == 0)
+ Alignment = 1;
+
+ uint8_t *result = getCodeMemBase() + mCurFuncMemIdx;
+ result = (uint8_t*) (((intptr_t) result + Alignment - 1) &
+ ~(intptr_t) (Alignment - 1));
+
+ mCurFuncMemIdx = (result + Size) - getCodeMemBase();
+
+ return result;
+}
+
+// Allocate memory for a global variable.
+uint8_t *CodeMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
+ if (getFreeGVMemSize() < Size) {
+ // The code size excesses our limit
+ LOGE("No Global Memory");
+ return NULL;
+ }
+
+ if (Alignment == 0)
+ Alignment = 1;
+
+ uint8_t *result = getGVMemBase() + mCurGVMemIdx;
+ result = (uint8_t*) (((intptr_t) result + Alignment - 1) &
+ ~(intptr_t) (Alignment - 1));
+
+ mCurGVMemIdx = (result + Size) - getGVMemBase();
+
+ return result;
+}
+
+// Free the specified function body. The argument must be the return value
+// from a call to startFunctionBody() that hasn't been deallocated yet. This
+// is never called when the JIT is currently emitting a function.
+void CodeMemoryManager::deallocateFunctionBody(void *Body) {
+ // linear search
+ uint8_t *FunctionStart = NULL, *FunctionEnd = NULL;
+ for (FunctionMapTy::iterator I = mFunctionMap.begin(),
+ E = mFunctionMap.end(); I != E; I++) {
+ if (I->second.first == Body) {
+ FunctionStart = reinterpret_cast<uint8_t*>(I->second.first);
+ FunctionEnd = reinterpret_cast<uint8_t*>(I->second.second);
+ break;
+ }
+ }
+
+ assert((FunctionStart == NULL) && "Memory is never allocated!");
+
+ // free the memory
+ intptr_t SizeNeedMove = (getCodeMemBase() + mCurFuncMemIdx) - FunctionEnd;
+
+ assert(SizeNeedMove >= 0 &&
+ "Internal error: CodeMemoryManager::mCurFuncMemIdx may not"
+ " be correctly calculated!");
+
+ if (SizeNeedMove > 0) {
+ // there's data behind deallocating function
+ memmove(FunctionStart, FunctionEnd, SizeNeedMove);
+ }
+
+ mCurFuncMemIdx -= (FunctionEnd - FunctionStart);
+}
+
+// Below are the methods we create
+void CodeMemoryManager::reset() {
+ mpGOTBase = NULL;
+ HasGOT = false;
+
+ mCurFuncMemIdx = 0;
+ mCurSGMemIdx = MaxCodeSize - 1;
+ mCurGVMemIdx = 0;
+
+ mFunctionMap.clear();
+}
+
+} // namespace bcc
diff --git a/lib/bcc/CodeMemoryManager.h b/lib/bcc/CodeMemoryManager.h
new file mode 100644
index 0000000..4a25ee6
--- /dev/null
+++ b/lib/bcc/CodeMemoryManager.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_CODEMEMORYMANAGER_H
+#define BCC_CODEMEMORYMANAGER_H
+
+#include "Compiler.h"
+
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+
+#include <map>
+#include <utility>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+
+namespace llvm {
+ // Forward Declaration
+ class Function;
+ class GlobalValue;
+};
+
+
+namespace bcc {
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Memory manager for the code reside in memory
+ //
+ // The memory for our code emitter is very simple and is conforming to the
+ // design decisions of Android RenderScript's Exection Environment:
+ // The code, data, and symbol sizes are limited (currently 100KB.)
+ //
+ // It's very different from typical compiler, which has no limitation
+ // on the code size. How does code emitter know the size of the code
+ // it is about to emit? It does not know beforehand. We want to solve
+ // this without complicating the code emitter too much.
+ //
+ // We solve this by pre-allocating a certain amount of memory,
+ // and then start the code emission. Once the buffer overflows, the emitter
+ // simply discards all the subsequent emission but still has a counter
+ // on how many bytes have been emitted.
+ //
+ // So once the whole emission is done, if there's a buffer overflow,
+ // it re-allocates the buffer with enough size (based on the
+ // counter from previous emission) and re-emit again.
+
+ extern const unsigned int MaxCodeSize;
+ extern const unsigned int MaxGOTSize;
+ extern const unsigned int MaxGlobalVarSize;
+
+
+ class CodeMemoryManager : public llvm::JITMemoryManager {
+ private:
+ //
+ // Our memory layout is as follows:
+ //
+ // The direction of arrows (-> and <-) shows memory's growth direction
+ // when more space is needed.
+ //
+ // @mpCodeMem:
+ // +--------------------------------------------------------------+
+ // | Function Memory ... -> <- ... Stub/GOT |
+ // +--------------------------------------------------------------+
+ // |<------------------ Total: @MaxCodeSize KiB ----------------->|
+ //
+ // Where size of GOT is @MaxGOTSize KiB.
+ //
+ // @mpGVMem:
+ // +--------------------------------------------------------------+
+ // | Global variable ... -> |
+ // +--------------------------------------------------------------+
+ // |<--------------- Total: @MaxGlobalVarSize KiB --------------->|
+ //
+ //
+ // @mCurFuncMemIdx: The current index (starting from 0) of the last byte
+ // of function code's memory usage
+ // @mCurSGMemIdx: The current index (starting from tail) of the last byte
+ // of stub/GOT's memory usage
+ // @mCurGVMemIdx: The current index (starting from tail) of the last byte
+ // of global variable's memory usage
+ //
+ uintptr_t mCurFuncMemIdx;
+ uintptr_t mCurSGMemIdx;
+ uintptr_t mCurGVMemIdx;
+ void *mpCodeMem;
+ void *mpGVMem;
+
+ // GOT Base
+ uint8_t *mpGOTBase;
+
+ typedef std::map<const llvm::Function*,
+ std::pair<void * /* start address */,
+ void * /* end address */> > FunctionMapTy;
+
+ FunctionMapTy mFunctionMap;
+
+ intptr_t getFreeCodeMemSize() const {
+ return mCurSGMemIdx - mCurFuncMemIdx;
+ }
+
+ uint8_t *allocateSGMemory(uintptr_t Size,
+ unsigned Alignment = 1 /* no alignment */);
+
+ uintptr_t getFreeGVMemSize() const {
+ return MaxGlobalVarSize - mCurGVMemIdx;
+ }
+
+ uint8_t *getGVMemBase() const {
+ return reinterpret_cast<uint8_t*>(mpGVMem);
+ }
+
+ public:
+
+ CodeMemoryManager();
+ virtual ~CodeMemoryManager();
+
+ uint8_t *getCodeMemBase() const {
+ return reinterpret_cast<uint8_t*>(mpCodeMem);
+ }
+
+ // setMemoryWritable - When code generation is in progress, the code pages
+ // may need permissions changed.
+ virtual void setMemoryWritable();
+
+ // When code generation is done and we're ready to start execution, the
+ // code pages may need permissions changed.
+ virtual void setMemoryExecutable();
+
+ // Setting this flag to true makes the memory manager garbage values over
+ // freed memory. This is useful for testing and debugging, and is to be
+ // turned on by default in debug mode.
+ virtual void setPoisonMemory(bool poison);
+
+
+ // Global Offset Table Management
+
+ // If the current table requires a Global Offset Table, this method is
+ // invoked to allocate it. This method is required to set HasGOT to true.
+ virtual void AllocateGOT();
+
+ // If this is managing a Global Offset Table, this method should return a
+ // pointer to its base.
+ virtual uint8_t *getGOTBase() const {
+ return mpGOTBase;
+ }
+
+ // Main Allocation Functions
+
+ // When we start JITing a function, the JIT calls this method to allocate a
+ // block of free RWX memory, which returns a pointer to it. If the JIT wants
+ // to request a block of memory of at least a certain size, it passes that
+ // value as ActualSize, and this method returns a block with at least that
+ // much space. If the JIT doesn't know ahead of time how much space it will
+ // need to emit the function, it passes 0 for the ActualSize. In either
+ // case, this method is required to pass back the size of the allocated
+ // block through ActualSize. The JIT will be careful to not write more than
+ // the returned ActualSize bytes of memory.
+ virtual uint8_t *startFunctionBody(const llvm::Function *F,
+ uintptr_t &ActualSize);
+
+ // This method is called by the JIT to allocate space for a function stub
+ // (used to handle limited branch displacements) while it is JIT compiling a
+ // function. For example, if foo calls bar, and if bar either needs to be
+ // lazily compiled or is a native function that exists too far away from the
+ // call site to work, this method will be used to make a thunk for it. The
+ // stub should be "close" to the current function body, but should not be
+ // included in the 'actualsize' returned by startFunctionBody.
+ virtual uint8_t *allocateStub(const llvm::GlobalValue *F,
+ unsigned StubSize,
+ unsigned Alignment) {
+ return allocateSGMemory(StubSize, Alignment);
+ }
+
+ // This method is called when the JIT is done codegen'ing the specified
+ // function. At this point we know the size of the JIT compiled function.
+ // This passes in FunctionStart (which was returned by the startFunctionBody
+ // method) and FunctionEnd which is a pointer to the actual end of the
+ // function. This method should mark the space allocated and remember where
+ // it is in case the client wants to deallocate it.
+ virtual void endFunctionBody(const llvm::Function *F,
+ uint8_t *FunctionStart,
+ uint8_t *FunctionEnd);
+
+ // Allocate a (function code) memory block of the given size. This method
+ // cannot be called between calls to startFunctionBody and endFunctionBody.
+ virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
+
+ // Allocate memory for a global variable.
+ virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);
+
+ // Free the specified function body. The argument must be the return value
+ // from a call to startFunctionBody() that hasn't been deallocated yet. This
+ // is never called when the JIT is currently emitting a function.
+ virtual void deallocateFunctionBody(void *Body);
+
+ // When we finished JITing the function, if exception handling is set, we
+ // emit the exception table.
+ virtual uint8_t *startExceptionTable(const llvm::Function *F,
+ uintptr_t &ActualSize) {
+ assert(false && "Exception is not allowed in our language specification");
+ return NULL;
+ }
+
+ // This method is called when the JIT is done emitting the exception table.
+ virtual void endExceptionTable(const llvm::Function *F, uint8_t *TableStart,
+ uint8_t *TableEnd, uint8_t *FrameRegister) {
+ assert(false && "Exception is not allowed in our language specification");
+ }
+
+ // Free the specified exception table's memory. The argument must be the
+ // return value from a call to startExceptionTable() that hasn't been
+ // deallocated yet. This is never called when the JIT is currently emitting
+ // an exception table.
+ virtual void deallocateExceptionTable(void *ET) {
+ assert(false && "Exception is not allowed in our language specification");
+ }
+
+ // Below are the methods we create
+ void reset();
+
+ };
+
+} // namespace bcc
+
+#endif // BCC_CODEMEMORYMANAGER_H
diff --git a/lib/bcc/Compiler.cpp b/lib/bcc/Compiler.cpp
new file mode 100644
index 0000000..50aeaa2
--- /dev/null
+++ b/lib/bcc/Compiler.cpp
@@ -0,0 +1,1776 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+
+#if defined(__arm__)
+# define DEFAULT_ARM_CODEGEN
+# define PROVIDE_ARM_CODEGEN
+#elif defined(__i386__)
+# define DEFAULT_X86_CODEGEN
+# define PROVIDE_X86_CODEGEN
+#elif defined(__x86_64__)
+# define DEFAULT_X64_CODEGEN
+# define PROVIDE_X64_CODEGEN
+#endif
+
+#if defined(FORCE_ARM_CODEGEN)
+# define DEFAULT_ARM_CODEGEN
+# undef DEFAULT_X86_CODEGEN
+# undef DEFAULT_X64_CODEGEN
+# define PROVIDE_ARM_CODEGEN
+# undef PROVIDE_X86_CODEGEN
+# undef PROVIDE_X64_CODEGEN
+#elif defined(FORCE_X86_CODEGEN)
+# undef DEFAULT_ARM_CODEGEN
+# define DEFAULT_X86_CODEGEN
+# undef DEFAULT_X64_CODEGEN
+# undef PROVIDE_ARM_CODEGEN
+# define PROVIDE_X86_CODEGEN
+# undef PROVIDE_X64_CODEGEN
+#elif defined(FORCE_X64_CODEGEN)
+# undef DEFAULT_ARM_CODEGEN
+# undef DEFAULT_X86_CODEGEN
+# define DEFAULT_X64_CODEGEN
+# undef PROVIDE_ARM_CODEGEN
+# undef PROVIDE_X86_CODEGEN
+# define PROVIDE_X64_CODEGEN
+#endif
+
+#if defined(DEFAULT_ARM_CODEGEN)
+# define TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
+#elif defined(DEFAULT_X86_CODEGEN)
+# define TARGET_TRIPLE_STRING "i686-unknown-linux"
+#elif defined(DEFAULT_X64_CODEGEN)
+# define TARGET_TRIPLE_STRING "x86_64-unknown-linux"
+#endif
+
+#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
+# define ARM_USE_VFP
+#endif
+
+#include "Compiler.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/Analysis/Passes.h"
+
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/RegAllocRegistry.h"
+#include "llvm/CodeGen/SchedulerRegistry.h"
+
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Scalar.h"
+
+#include "llvm/Target/SubtargetFeature.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Target/TargetSelect.h"
+
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "llvm/GlobalValue.h"
+#include "llvm/Linker.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Metadata.h"
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Value.h"
+
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+
+namespace {
+
+#define TEMP_FAILURE_RETRY1(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+
+
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg) {
+ while (count != 0) {
+ ssize_t actual = TEMP_FAILURE_RETRY1(write(fd, buf, count));
+ if (actual < 0) {
+ int err = errno;
+ LOGE("%s: write failed: %s\n", logMsg, strerror(err));
+ return err;
+ } else if (actual != (ssize_t) count) {
+ LOGD("%s: partial write (will retry): (%d of %zd)\n",
+ logMsg, (int) actual, count);
+ buf = (const void*) (((const uint8_t*) buf) + actual);
+ }
+ count -= actual;
+ }
+
+ return 0;
+}
+
+} // namespace anonymous
+
+
+namespace bcc {
+
+//////////////////////////////////////////////////////////////////////////////
+// BCC Compiler Static Variables
+//////////////////////////////////////////////////////////////////////////////
+
+bool Compiler::GlobalInitialized = false;
+
+bool Compiler::BccMmapImgAddrTaken[BCC_MMAP_IMG_COUNT];
+
+// Code generation optimization level for the compiler
+llvm::CodeGenOpt::Level Compiler::CodeGenOptLevel;
+
+std::string Compiler::Triple;
+
+std::string Compiler::CPU;
+
+std::vector<std::string> Compiler::Features;
+
+// The named of metadata node that pragma resides (should be synced with
+// slang.cpp)
+const llvm::StringRef Compiler::PragmaMetadataName = "#pragma";
+
+// The named of metadata node that export variable name resides (should be
+// synced with slang_rs_metadata.h)
+const llvm::StringRef Compiler::ExportVarMetadataName = "#rs_export_var";
+
+// The named of metadata node that export function name resides (should be
+// synced with slang_rs_metadata.h)
+const llvm::StringRef Compiler::ExportFuncMetadataName = "#rs_export_func";
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Compiler
+//////////////////////////////////////////////////////////////////////////////
+
+void Compiler::GlobalInitialization() {
+ if (GlobalInitialized)
+ return;
+
+ // if (!llvm::llvm_is_multithreaded())
+ // llvm::llvm_start_multithreaded();
+
+ // Set Triple, CPU and Features here
+ Triple = TARGET_TRIPLE_STRING;
+
+ // TODO(sliao): NEON for JIT
+ // Features.push_back("+neon");
+ // Features.push_back("+vmlx");
+ // Features.push_back("+neonfp");
+ Features.push_back("+vfp3");
+ Features.push_back("+d16");
+
+#if defined(DEFAULT_ARM_CODEGEN) || defined(PROVIDE_ARM_CODEGEN)
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+#if defined(USE_DISASSEMBLER)
+ LLVMInitializeARMDisassembler();
+ LLVMInitializeARMAsmPrinter();
+#endif
+#endif
+
+#if defined(DEFAULT_X86_CODEGEN) || defined(PROVIDE_X86_CODEGEN)
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeX86Target();
+#if defined(USE_DISASSEMBLER)
+ LLVMInitializeX86Disassembler();
+ LLVMInitializeX86AsmPrinter();
+#endif
+#endif
+
+#if defined(DEFAULT_X64_CODEGEN) || defined(PROVIDE_X64_CODEGEN)
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeX86Target();
+#if defined(USE_DISASSEMBLER)
+ LLVMInitializeX86Disassembler();
+ LLVMInitializeX86AsmPrinter();
+#endif
+#endif
+
+ // -O0: llvm::CodeGenOpt::None
+ // -O1: llvm::CodeGenOpt::Less
+ // -O2: llvm::CodeGenOpt::Default
+ // -O3: llvm::CodeGenOpt::Aggressive
+ CodeGenOptLevel = llvm::CodeGenOpt::None;
+
+ // Below are the global settings to LLVM
+
+ // Disable frame pointer elimination optimization
+ llvm::NoFramePointerElim = false;
+
+ // Use hardfloat ABI
+ //
+ // TODO(all): Need to detect the CPU capability and decide whether to use
+ // softfp. To use softfp, change following 2 lines to
+ //
+ // llvm::FloatABIType = llvm::FloatABI::Soft;
+ // llvm::UseSoftFloat = true;
+ //
+ llvm::FloatABIType = llvm::FloatABI::Soft;
+ llvm::UseSoftFloat = false;
+
+ // BCC needs all unknown symbols resolved at JIT/compilation time.
+ // So we don't need any dynamic relocation model.
+ llvm::TargetMachine::setRelocationModel(llvm::Reloc::Static);
+
+#if defined(DEFAULT_X64_CODEGEN)
+ // Data address in X86_64 architecture may reside in a far-away place
+ llvm::TargetMachine::setCodeModel(llvm::CodeModel::Medium);
+#else
+ // This is set for the linker (specify how large of the virtual addresses
+ // we can access for all unknown symbols.)
+ llvm::TargetMachine::setCodeModel(llvm::CodeModel::Small);
+#endif
+
+ // Register the scheduler
+ llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
+
+ // Register allocation policy:
+ // createFastRegisterAllocator: fast but bad quality
+ // createLinearScanRegisterAllocator: not so fast but good quality
+ llvm::RegisterRegAlloc::setDefault
+ ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
+ llvm::createFastRegisterAllocator :
+ llvm::createLinearScanRegisterAllocator);
+
+ GlobalInitialized = true;
+}
+
+
+void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) {
+ std::string *Error = static_cast<std::string*>(UserData);
+ Error->assign(Message);
+ LOGE("%s", Message.c_str());
+ exit(1);
+}
+
+
+CodeMemoryManager *Compiler::createCodeMemoryManager() {
+ mCodeMemMgr.reset(new CodeMemoryManager());
+ return mCodeMemMgr.get();
+}
+
+
+CodeEmitter *Compiler::createCodeEmitter() {
+ mCodeEmitter.reset(new CodeEmitter(mCodeMemMgr.take()));
+ return mCodeEmitter.get();
+}
+
+
+Compiler::Compiler()
+ : mUseCache(false),
+ mCacheNew(false),
+ mCacheFd(-1),
+ mCacheMapAddr(NULL),
+ mCacheHdr(NULL),
+ mCacheSize(0),
+ mCacheDiff(0),
+ mCodeDataAddr(NULL),
+ mpSymbolLookupFn(NULL),
+ mpSymbolLookupContext(NULL),
+ mContext(NULL),
+ mModule(NULL),
+ mHasLinked(false) /* Turn off linker */ {
+ llvm::remove_fatal_error_handler();
+ llvm::install_fatal_error_handler(LLVMErrorHandler, &mError);
+ mContext = new llvm::LLVMContext();
+ return;
+}
+
+
+int Compiler::readBC(const char *bitcode,
+ size_t bitcodeSize,
+ const BCCchar *resName) {
+ GlobalInitialization();
+
+ if (resName) {
+ // Turn on mUseCache mode iff
+ // 1. Has resName
+ // and, assuming USE_RELOCATE is false:
+ // 2. Later running code doesn't violate the following condition:
+ // mCodeDataAddr (set in loadCacheFile()) ==
+ // mCacheHdr->cachedCodeDataAddr
+ //
+ // BTW, this condition is achievable only when in the earlier
+ // cache-generating run,
+ // mpCodeMem == BccCodeAddr - MaxCodeSize - MaxGlobalVarSize,
+ // which means the mmap'ed is in the reserved area,
+ //
+ // Note: Upon violation, mUseCache will be set back to false.
+ mUseCache = true;
+
+ mCacheFd = openCacheFile(resName, true /* createIfMissing */);
+ if (mCacheFd >= 0 && !mCacheNew) { // Just use cache file
+ return -mCacheFd;
+ }
+ }
+
+ llvm::OwningPtr<llvm::MemoryBuffer> MEM;
+
+ if (bitcode == NULL || bitcodeSize <= 0)
+ return 0;
+
+ // Package input to object MemoryBuffer
+ MEM.reset(llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(bitcode, bitcodeSize)));
+
+ if (MEM.get() == NULL) {
+ setError("Error reading input program bitcode into memory");
+ return hasError();
+ }
+
+ // Read the input Bitcode as a Module
+ mModule = llvm::ParseBitcodeFile(MEM.get(), *mContext, &mError);
+ MEM.reset();
+ return hasError();
+}
+
+
+int Compiler::linkBC(const char *bitcode, size_t bitcodeSize) {
+ llvm::OwningPtr<llvm::MemoryBuffer> MEM;
+
+ if (bitcode == NULL || bitcodeSize <= 0)
+ return 0;
+
+ if (mModule == NULL) {
+ setError("No module presents for linking");
+ return hasError();
+ }
+
+ MEM.reset(llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(bitcode, bitcodeSize)));
+
+ if (MEM.get() == NULL) {
+ setError("Error reading input library bitcode into memory");
+ return hasError();
+ }
+
+ llvm::OwningPtr<llvm::Module> Lib(llvm::ParseBitcodeFile(MEM.get(),
+ *mContext,
+ &mError));
+ if (Lib.get() == NULL)
+ return hasError();
+
+ if (llvm::Linker::LinkModules(mModule, Lib.take(), &mError))
+ return hasError();
+
+ // Everything for linking should be settled down here with no error occurs
+ mHasLinked = true;
+ return hasError();
+}
+
+
+// interface for bccLoadBinary()
+int Compiler::loadCacheFile() {
+ // Check File Descriptor
+ if (mCacheFd < 0) {
+ LOGE("loading cache from invalid mCacheFd = %d\n", (int)mCacheFd);
+ goto giveup;
+ }
+
+ // Check File Size
+ struct stat statCacheFd;
+ if (fstat(mCacheFd, &statCacheFd) < 0) {
+ LOGE("unable to stat mCacheFd = %d\n", (int)mCacheFd);
+ goto giveup;
+ }
+
+ mCacheSize = statCacheFd.st_size;
+
+ if (mCacheSize < sizeof(oBCCHeader) ||
+ mCacheSize <= MaxCodeSize + MaxGlobalVarSize) {
+ LOGE("mCacheFd %d is too small to be correct\n", (int)mCacheFd);
+ goto giveup;
+ }
+
+ if (lseek(mCacheFd, 0, SEEK_SET) != 0) {
+ LOGE("Unable to seek to 0: %s\n", strerror(errno));
+ goto giveup;
+ }
+
+ // Part 1. Deal with the non-codedata section first
+ {
+ // Read cached file and perform quick integrity check
+
+ off_t heuristicCodeOffset = mCacheSize - MaxCodeSize - MaxGlobalVarSize;
+ LOGW("TODO(sliao)@loadCacheFile: mCacheSize=%x, heuristicCodeOffset=%llx",
+ (unsigned int)mCacheSize,
+ (unsigned long long int)heuristicCodeOffset);
+
+ mCacheMapAddr = (char *)malloc(heuristicCodeOffset);
+ if (!mCacheMapAddr) {
+ flock(mCacheFd, LOCK_UN);
+ LOGE("allocation failed.\n");
+ goto bail;
+ }
+
+ size_t nread = TEMP_FAILURE_RETRY1(read(mCacheFd, mCacheMapAddr,
+ heuristicCodeOffset));
+ if (nread != (size_t)heuristicCodeOffset) {
+ LOGE("read(mCacheFd) failed\n");
+ goto bail;
+ }
+
+ mCacheHdr = reinterpret_cast<oBCCHeader *>(mCacheMapAddr);
+ // Sanity check
+ if (mCacheHdr->codeOffset != (uint32_t)heuristicCodeOffset) {
+ LOGE("assertion failed: heuristic code offset is not correct.\n");
+ goto bail;
+ }
+ LOGW("TODO(sliao): mCacheHdr->cachedCodeDataAddr=%x", mCacheHdr->cachedCodeDataAddr);
+ LOGW("mCacheHdr->rootAddr=%x", mCacheHdr->rootAddr);
+ LOGW("mCacheHdr->initAddr=%x", mCacheHdr->initAddr);
+ LOGW("mCacheHdr->codeOffset=%x", mCacheHdr->codeOffset);
+ LOGW("mCacheHdr->codeSize=%x", mCacheHdr->codeSize);
+
+ // Verify the Cache File
+ if (memcmp(mCacheHdr->magic, OBCC_MAGIC, 4) != 0) {
+ LOGE("bad magic word\n");
+ goto bail;
+ }
+
+ if (memcmp(mCacheHdr->magicVersion, OBCC_MAGIC_VERS, 4) != 0) {
+ LOGE("bad oBCC version 0x%08x\n",
+ *reinterpret_cast<uint32_t *>(mCacheHdr->magicVersion));
+ goto bail;
+ }
+
+ if (mCacheSize < mCacheHdr->relocOffset +
+ mCacheHdr->relocCount * sizeof(oBCCRelocEntry)) {
+ LOGE("relocate table overflow\n");
+ goto bail;
+ }
+
+ if (mCacheSize < mCacheHdr->exportVarsOffset +
+ mCacheHdr->exportVarsCount * sizeof(uint32_t)) {
+ LOGE("export variables table overflow\n");
+ goto bail;
+ }
+
+ if (mCacheSize < mCacheHdr->exportFuncsOffset +
+ mCacheHdr->exportFuncsCount * sizeof(uint32_t)) {
+ LOGE("export functions table overflow\n");
+ goto bail;
+ }
+
+ if (mCacheSize < mCacheHdr->exportPragmasOffset +
+ mCacheHdr->exportPragmasCount * sizeof(uint32_t)) {
+ LOGE("export pragmas table overflow\n");
+ goto bail;
+ }
+
+ if (mCacheSize < mCacheHdr->codeOffset + mCacheHdr->codeSize) {
+ LOGE("code cache overflow\n");
+ goto bail;
+ }
+
+ if (mCacheSize < mCacheHdr->dataOffset + mCacheHdr->dataSize) {
+ LOGE("data (global variable) cache overflow\n");
+ goto bail;
+ }
+
+ long pagesize = sysconf(_SC_PAGESIZE);
+ if (mCacheHdr->codeOffset % pagesize != 0) {
+ LOGE("code offset must aligned to pagesize\n");
+ goto bail;
+ }
+ }
+
+ // Part 2. Deal with the codedata section
+ {
+ long pagesize = sysconf(_SC_PAGESIZE);
+
+ if (mCacheHdr->cachedCodeDataAddr % pagesize == 0) {
+ void *addr = reinterpret_cast<char *>(mCacheHdr->cachedCodeDataAddr);
+
+ // Try to mmap at cached address directly.
+ mCodeDataAddr = (char *) mmap(addr,
+ BCC_MMAP_IMG_SIZE,
+ PROT_READ | PROT_EXEC | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED,
+ mCacheFd,
+ mCacheHdr->codeOffset);
+
+ if (mCodeDataAddr && mCodeDataAddr != MAP_FAILED) {
+ // Cheers! Mapped at the cached address successfully.
+
+ // Update the BccMmapImgAddrTaken table (if required)
+ if (mCacheHdr->cachedCodeDataAddr >= BCC_MMAP_IMG_BEGIN) {
+ size_t offset = mCacheHdr->cachedCodeDataAddr - BCC_MMAP_IMG_BEGIN;
+
+ if ((offset % BCC_MMAP_IMG_SIZE) == 0 &&
+ (offset / BCC_MMAP_IMG_SIZE) < BCC_MMAP_IMG_COUNT) {
+ Compiler::BccMmapImgAddrTaken[offset / BCC_MMAP_IMG_SIZE] = true;
+ }
+ }
+
+#if 1
+ // Check the checksum of code and data
+ {
+ uint32_t sum = mCacheHdr->checksum;
+ uint32_t *ptr = (uint32_t *)mCodeDataAddr;
+
+ for (size_t i = 0; i < BCC_MMAP_IMG_SIZE / sizeof(uint32_t); ++i) {
+ sum ^= *ptr++;
+ }
+
+ if (sum != 0) {
+ LOGE("Checksum check failed\n");
+ goto bail;
+ }
+
+ LOGE("Passed checksum even parity verification.\n");
+ }
+#endif
+
+ flock(mCacheFd, LOCK_UN);
+ return 0; // loadCacheFile succeed!
+ }
+ }
+ }
+
+#if !USE_RELOCATE
+ // Note: Since this build does not support relocation, we have no
+ // choose but give up to load the cached file, and recompile the
+ // code.
+
+ flock(mCacheFd, LOCK_UN);
+ goto bail;
+#else
+
+ // Note: Currently, relocation code is not working. Give up now.
+ flock(mCacheFd, LOCK_UN);
+ goto bail;
+
+ // TODO(logan): Following code is not working. Don't use them.
+ // And rewrite them asap.
+#if 0
+ {
+ // Try to allocate at arbitary address. And perform relocation.
+ mCacheMapAddr = (char *) mmap(0,
+ mCacheSize,
+ PROT_READ | PROT_EXEC | PROT_WRITE,
+ MAP_PRIVATE,
+ mCacheFd,
+ 0);
+
+ if (mCacheMapAddr == MAP_FAILED) {
+ LOGE("unable to mmap .oBBC cache: %s\n", strerror(errno));
+ flock(mCacheFd, LOCK_UN);
+ goto giveup;
+ }
+
+ flock(mCacheFd, LOCK_UN);
+ mCodeDataAddr = mCacheMapAddr + mCacheHdr->codeOffset;
+
+ // Relocate
+ mCacheDiff = mCodeDataAddr -
+ reinterpret_cast<char *>(mCacheHdr->cachedCodeDataAddr);
+
+ if (mCacheDiff) { // To relocate
+ if (mCacheHdr->rootAddr) {
+ mCacheHdr->rootAddr += mCacheDiff;
+ }
+
+ if (mCacheHdr->initAddr) {
+ mCacheHdr->initAddr += mCacheDiff;
+ }
+
+ oBCCRelocEntry *cachedRelocTable =
+ reinterpret_cast<oBCCRelocEntry *>(mCacheMapAddr +
+ mCacheHdr->relocOffset);
+
+ std::vector<llvm::MachineRelocation> relocations;
+
+ // Read in the relocs
+ for (size_t i = 0; i < mCacheHdr->relocCount; i++) {
+ oBCCRelocEntry *entry = &cachedRelocTable[i];
+
+ llvm::MachineRelocation reloc =
+ llvm::MachineRelocation::getGV((uintptr_t)entry->relocOffset,
+ (unsigned)entry->relocType, 0, 0);
+
+ reloc.setResultPointer(
+ reinterpret_cast<char *>(entry->cachedResultAddr) + mCacheDiff);
+
+ relocations.push_back(reloc);
+ }
+
+ // Rewrite machine code using llvm::TargetJITInfo relocate
+ {
+ llvm::TargetMachine *TM = NULL;
+ const llvm::Target *Target;
+ std::string FeaturesStr;
+
+ // Create TargetMachine
+ Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
+ if (hasError())
+ goto bail;
+
+ if (!CPU.empty() || !Features.empty()) {
+ llvm::SubtargetFeatures F;
+ F.setCPU(CPU);
+ for (std::vector<std::string>::const_iterator I = Features.begin(),
+ E = Features.end(); I != E; I++)
+ F.AddFeature(*I);
+ FeaturesStr = F.getString();
+ }
+
+ TM = Target->createTargetMachine(Triple, FeaturesStr);
+ if (TM == NULL) {
+ setError("Failed to create target machine implementation for the"
+ " specified triple '" + Triple + "'");
+ goto bail;
+ }
+
+ TM->getJITInfo()->relocate(mCodeDataAddr,
+ &relocations[0], relocations.size(),
+ (unsigned char *)mCodeDataAddr+MaxCodeSize);
+
+ if (mCodeEmitter.get()) {
+ mCodeEmitter->Disassemble(llvm::StringRef("cache"),
+ reinterpret_cast<uint8_t*>(mCodeDataAddr),
+ 2 * 1024 /*MaxCodeSize*/,
+ false);
+ }
+
+ delete TM;
+ }
+ } // End of if (mCacheDiff)
+
+ return 0; // Success!
+ }
+#endif
+#endif
+
+bail:
+ if (mCacheMapAddr) {
+ free(mCacheMapAddr);
+ }
+
+ if (mCodeDataAddr && mCodeDataAddr != MAP_FAILED) {
+ if (munmap(mCodeDataAddr, BCC_MMAP_IMG_SIZE) != 0) {
+ LOGE("munmap failed: %s\n", strerror(errno));
+ }
+ }
+
+ mCacheMapAddr = NULL;
+ mCacheHdr = NULL;
+ mCodeDataAddr = NULL;
+
+giveup:
+ return 1;
+}
+
+// interace for bccCompileBC()
+int Compiler::compile() {
+ llvm::TargetData *TD = NULL;
+
+ llvm::TargetMachine *TM = NULL;
+ const llvm::Target *Target;
+ std::string FeaturesStr;
+
+ llvm::FunctionPassManager *CodeGenPasses = NULL;
+
+ const llvm::NamedMDNode *PragmaMetadata;
+ const llvm::NamedMDNode *ExportVarMetadata;
+ const llvm::NamedMDNode *ExportFuncMetadata;
+
+ if (mModule == NULL) // No module was loaded
+ return 0;
+
+ // Create TargetMachine
+ Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
+ if (hasError())
+ goto on_bcc_compile_error;
+
+ if (!CPU.empty() || !Features.empty()) {
+ llvm::SubtargetFeatures F;
+ F.setCPU(CPU);
+
+ for (std::vector<std::string>::const_iterator
+ I = Features.begin(), E = Features.end(); I != E; I++) {
+ F.AddFeature(*I);
+ }
+
+ FeaturesStr = F.getString();
+ }
+
+ TM = Target->createTargetMachine(Triple, FeaturesStr);
+ if (TM == NULL) {
+ setError("Failed to create target machine implementation for the"
+ " specified triple '" + Triple + "'");
+ goto on_bcc_compile_error;
+ }
+
+ // Create memory manager for creation of code emitter later.
+ if (!mCodeMemMgr.get() && !createCodeMemoryManager()) {
+ setError("Failed to startup memory management for further compilation");
+ goto on_bcc_compile_error;
+ }
+ mCodeDataAddr = (char *) (mCodeMemMgr.get()->getCodeMemBase());
+
+ // Create code emitter
+ if (!mCodeEmitter.get()) {
+ if (!createCodeEmitter()) {
+ setError("Failed to create machine code emitter to complete"
+ " the compilation");
+ goto on_bcc_compile_error;
+ }
+ } else {
+ // Reuse the code emitter
+ mCodeEmitter->reset();
+ }
+
+ mCodeEmitter->setTargetMachine(*TM);
+ mCodeEmitter->registerSymbolCallback(mpSymbolLookupFn,
+ mpSymbolLookupContext);
+
+ // Get target data from Module
+ TD = new llvm::TargetData(mModule);
+
+ // Load named metadata
+ ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName);
+ ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName);
+ PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName);
+
+ // Create LTO passes and run them on the mModule
+ if (mHasLinked) {
+ llvm::TimePassesIsEnabled = true; // TODO(all)
+ llvm::PassManager LTOPasses;
+ LTOPasses.add(new llvm::TargetData(*TD));
+
+ std::vector<const char*> ExportSymbols;
+
+ // A workaround for getting export variable and function name. Will refine
+ // it soon.
+ if (ExportVarMetadata) {
+ for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
+ llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
+ if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
+ llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
+ if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef ExportVarName =
+ static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
+ ExportSymbols.push_back(ExportVarName.data());
+ }
+ }
+ }
+ }
+
+ if (ExportFuncMetadata) {
+ for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
+ llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
+ if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
+ llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
+ if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef ExportFuncName =
+ static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
+ ExportSymbols.push_back(ExportFuncName.data());
+ }
+ }
+ }
+ }
+ // root() and init() are born to be exported
+ ExportSymbols.push_back("root");
+ ExportSymbols.push_back("init");
+
+ // We now create passes list performing LTO. These are copied from
+ // (including comments) llvm::createStandardLTOPasses().
+
+ // Internalize all other symbols not listed in ExportSymbols
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+
+ // Propagate constants at call sites into the functions they call. This
+ // opens opportunities for globalopt (and inlining) by substituting
+ // function pointers passed as arguments to direct uses of functions.
+ LTOPasses.add(llvm::createIPSCCPPass());
+
+ // Now that we internalized some globals, see if we can hack on them!
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
+
+ // Linking modules together can lead to duplicated global constants, only
+ // keep one copy of each constant...
+ LTOPasses.add(llvm::createConstantMergePass());
+
+ // Remove unused arguments from functions...
+ LTOPasses.add(llvm::createDeadArgEliminationPass());
+
+ // Reduce the code after globalopt and ipsccp. Both can open up
+ // significant simplification opportunities, and both can propagate
+ // functions through function pointers. When this happens, we often have
+ // to resolve varargs calls, etc, so let instcombine do this.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
+
+ // Inline small functions
+ LTOPasses.add(llvm::createFunctionInliningPass());
+
+ // Remove dead EH info.
+ LTOPasses.add(llvm::createPruneEHPass());
+
+ // Internalize the globals again after inlining
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
+
+ // Remove dead functions.
+ LTOPasses.add(llvm::createGlobalDCEPass());
+
+ // If we didn't decide to inline a function, check to see if we can
+ // transform it to pass arguments by value instead of by reference.
+ LTOPasses.add(llvm::createArgumentPromotionPass());
+
+ // The IPO passes may leave cruft around. Clean up after them.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
+
+ // Break up allocas
+ LTOPasses.add(llvm::createScalarReplAggregatesPass());
+
+ // Run a few AA driven optimizations here and now, to cleanup the code.
+ LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
+ LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
+
+ // Hoist loop invariants.
+ LTOPasses.add(llvm::createLICMPass());
+
+ // Remove redundancies.
+ LTOPasses.add(llvm::createGVNPass());
+
+ // Remove dead memcpys.
+ LTOPasses.add(llvm::createMemCpyOptPass());
+
+ // Nuke dead stores.
+ LTOPasses.add(llvm::createDeadStoreEliminationPass());
+
+ // Cleanup and simplify the code after the scalar optimizations.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
+
+ LTOPasses.add(llvm::createJumpThreadingPass());
+
+ // Delete basic blocks, which optimization passes may have killed.
+ LTOPasses.add(llvm::createCFGSimplificationPass());
+
+ // Now that we have optimized the program, discard unreachable functions.
+ LTOPasses.add(llvm::createGlobalDCEPass());
+
+ LTOPasses.run(*mModule);
+ }
+
+ // Create code-gen pass to run the code emitter
+ CodeGenPasses = new llvm::FunctionPassManager(mModule);
+ CodeGenPasses->add(TD); // Will take the ownership of TD
+
+ if (TM->addPassesToEmitMachineCode(*CodeGenPasses,
+ *mCodeEmitter,
+ CodeGenOptLevel)) {
+ setError("The machine code emission is not supported by BCC on target '"
+ + Triple + "'");
+ goto on_bcc_compile_error;
+ }
+
+ // Run the pass (the code emitter) on every non-declaration function in the
+ // module
+ CodeGenPasses->doInitialization();
+ for (llvm::Module::iterator I = mModule->begin(), E = mModule->end();
+ I != E; I++) {
+ if (!I->isDeclaration()) {
+ CodeGenPasses->run(*I);
+ }
+ }
+
+ CodeGenPasses->doFinalization();
+
+ // Copy the global address mapping from code emitter and remapping
+ if (ExportVarMetadata) {
+ for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
+ llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
+ if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
+ llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
+ if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef ExportVarName =
+ static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
+
+ CodeEmitter::global_addresses_const_iterator I, E;
+ for (I = mCodeEmitter->global_address_begin(),
+ E = mCodeEmitter->global_address_end();
+ I != E; I++) {
+ if (I->first->getValueID() != llvm::Value::GlobalVariableVal)
+ continue;
+ if (ExportVarName == I->first->getName()) {
+ mExportVars.push_back(I->second);
+ break;
+ }
+ }
+ if (I != mCodeEmitter->global_address_end())
+ continue; // found
+ }
+ }
+ // if reaching here, we know the global variable record in metadata is
+ // not found. So we make an empty slot
+ mExportVars.push_back(NULL);
+ }
+ assert((mExportVars.size() == ExportVarMetadata->getNumOperands()) &&
+ "Number of slots doesn't match the number of export variables!");
+ }
+
+ if (ExportFuncMetadata) {
+ for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
+ llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
+ if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
+ llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
+ if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef ExportFuncName =
+ static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
+ mExportFuncs.push_back(mCodeEmitter->lookup(ExportFuncName));
+ }
+ }
+ }
+ }
+
+ // Tell code emitter now can release the memory using during the JIT since
+ // we have done the code emission
+ mCodeEmitter->releaseUnnecessary();
+
+ // Finally, read pragma information from the metadata node of the @Module if
+ // any.
+ if (PragmaMetadata)
+ for (int i = 0, e = PragmaMetadata->getNumOperands(); i != e; i++) {
+ llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
+ if (Pragma != NULL &&
+ Pragma->getNumOperands() == 2 /* should have exactly 2 operands */) {
+ llvm::Value *PragmaNameMDS = Pragma->getOperand(0);
+ llvm::Value *PragmaValueMDS = Pragma->getOperand(1);
+
+ if ((PragmaNameMDS->getValueID() == llvm::Value::MDStringVal) &&
+ (PragmaValueMDS->getValueID() == llvm::Value::MDStringVal)) {
+ llvm::StringRef PragmaName =
+ static_cast<llvm::MDString*>(PragmaNameMDS)->getString();
+ llvm::StringRef PragmaValue =
+ static_cast<llvm::MDString*>(PragmaValueMDS)->getString();
+
+ mPragmas.push_back(
+ std::make_pair(std::string(PragmaName.data(),
+ PragmaName.size()),
+ std::string(PragmaValue.data(),
+ PragmaValue.size())));
+ }
+ }
+ }
+
+on_bcc_compile_error:
+ // LOGE("on_bcc_compiler_error");
+ if (CodeGenPasses) {
+ delete CodeGenPasses;
+ } else if (TD) {
+ delete TD;
+ }
+ if (TM)
+ delete TM;
+
+ if (mError.empty()) {
+ if (mUseCache && mCacheFd >= 0 && mCacheNew) {
+ genCacheFile();
+ flock(mCacheFd, LOCK_UN);
+ }
+
+ return false;
+ }
+
+ // LOGE(getErrorMessage());
+ return true;
+}
+
+
+// interface for bccGetScriptLabel()
+void *Compiler::lookup(const char *name) {
+ void *addr = NULL;
+ if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
+ if (!strcmp(name, "root")) {
+ addr = reinterpret_cast<void *>(mCacheHdr->rootAddr);
+ } else if (!strcmp(name, "init")) {
+ addr = reinterpret_cast<void *>(mCacheHdr->initAddr);
+ }
+ return addr;
+ }
+
+ if (mCodeEmitter.get())
+ // Find function pointer
+ addr = mCodeEmitter->lookup(name);
+ return addr;
+}
+
+
+// Interface for bccGetExportVars()
+void Compiler::getExportVars(BCCsizei *actualVarCount,
+ BCCsizei maxVarCount,
+ BCCvoid **vars) {
+ int varCount;
+
+ if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
+ varCount = static_cast<int>(mCacheHdr->exportVarsCount);
+ if (actualVarCount)
+ *actualVarCount = varCount;
+ if (varCount > maxVarCount)
+ varCount = maxVarCount;
+ if (vars) {
+ uint32_t *cachedVars = (uint32_t *)(mCacheMapAddr +
+ mCacheHdr->exportVarsOffset);
+
+ for (int i = 0; i < varCount; i++) {
+ *vars++ = (BCCvoid *)(reinterpret_cast<char *>(*cachedVars) +
+ mCacheDiff);
+ cachedVars++;
+ }
+ }
+ return;
+ }
+
+ varCount = mExportVars.size();
+ if (actualVarCount)
+ *actualVarCount = varCount;
+ if (varCount > maxVarCount)
+ varCount = maxVarCount;
+ if (vars) {
+ for (ExportVarList::const_iterator
+ I = mExportVars.begin(), E = mExportVars.end(); I != E; I++) {
+ *vars++ = *I;
+ }
+ }
+
+ return;
+}
+
+
+// Interface for bccGetExportFuncs()
+void Compiler::getExportFuncs(BCCsizei *actualFuncCount,
+ BCCsizei maxFuncCount,
+ BCCvoid **funcs) {
+ int funcCount;
+
+ if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
+ funcCount = static_cast<int>(mCacheHdr->exportFuncsCount);
+ if (actualFuncCount)
+ *actualFuncCount = funcCount;
+ if (funcCount > maxFuncCount)
+ funcCount = maxFuncCount;
+ if (funcs) {
+ uint32_t *cachedFuncs = (uint32_t *)(mCacheMapAddr +
+ mCacheHdr->exportFuncsOffset);
+
+ for (int i = 0; i < funcCount; i++) {
+ *funcs++ = (BCCvoid *)(reinterpret_cast<char *>(*cachedFuncs) +
+ mCacheDiff);
+ cachedFuncs++;
+ }
+ }
+ return;
+ }
+
+ funcCount = mExportFuncs.size();
+ if (actualFuncCount)
+ *actualFuncCount = funcCount;
+ if (funcCount > maxFuncCount)
+ funcCount = maxFuncCount;
+ if (funcs) {
+ for (ExportFuncList::const_iterator I = mExportFuncs.begin(),
+ E = mExportFuncs.end();
+ I != E;
+ I++) {
+ *funcs++ = *I;
+ }
+ }
+
+ return;
+}
+
+
+// Interface for bccGetPragmas()
+void Compiler::getPragmas(BCCsizei *actualStringCount,
+ BCCsizei maxStringCount,
+ BCCchar **strings) {
+ int stringCount;
+ if (mUseCache && mCacheFd >= 0 && !mCacheNew) {
+ if (actualStringCount)
+ *actualStringCount = 0; // XXX
+ return;
+ }
+
+ stringCount = mPragmas.size() * 2;
+
+ if (actualStringCount)
+ *actualStringCount = stringCount;
+ if (stringCount > maxStringCount)
+ stringCount = maxStringCount;
+ if (strings) {
+ for (PragmaList::const_iterator it = mPragmas.begin();
+ stringCount > 0;
+ stringCount -= 2, it++) {
+ *strings++ = const_cast<BCCchar*>(it->first.c_str());
+ *strings++ = const_cast<BCCchar*>(it->second.c_str());
+ }
+ }
+
+ return;
+}
+
+
+// Interface for bccGetFunctions()
+void Compiler::getFunctions(BCCsizei *actualFunctionCount,
+ BCCsizei maxFunctionCount,
+ BCCchar **functions) {
+ if (mCodeEmitter.get())
+ mCodeEmitter->getFunctionNames(actualFunctionCount,
+ maxFunctionCount,
+ functions);
+ else
+ *actualFunctionCount = 0;
+
+ return;
+}
+
+
+// Interface for bccGetFunctionBinary()
+void Compiler::getFunctionBinary(BCCchar *function,
+ BCCvoid **base,
+ BCCsizei *length) {
+ if (mCodeEmitter.get()) {
+ mCodeEmitter->getFunctionBinary(function, base, length);
+ } else {
+ *base = NULL;
+ *length = 0;
+ }
+ return;
+}
+
+
+Compiler::~Compiler() {
+ if (!mCodeMemMgr.get()) {
+ // mCodeDataAddr and mCacheMapAddr are from loadCacheFile and not
+ // managed by CodeMemoryManager.
+
+ if (mCodeDataAddr != 0 && mCodeDataAddr != MAP_FAILED) {
+ if (munmap(mCodeDataAddr, BCC_MMAP_IMG_SIZE) < 0) {
+ LOGE("munmap failed while releasing mCodeDataAddr\n");
+ }
+ }
+
+ if (mCacheMapAddr) {
+ free(mCacheMapAddr);
+ }
+
+ mCodeDataAddr = 0;
+ mCacheMapAddr = 0;
+ }
+
+ delete mModule;
+ delete mContext;
+
+ // llvm::llvm_shutdown();
+}
+
+
+// Design of caching EXE:
+// ======================
+// 1. Each process will have virtual address available starting at 0x7e00000.
+// E.g., Books and Youtube all have its own 0x7e00000. Next, we should
+// minimize the chance of needing to do relocation INSIDE an app too.
+//
+// 2. Each process will have ONE class static variable called BccCodeAddr.
+// I.e., even though the Compiler class will have multiple Compiler objects,
+// e.g, one object for carousel.rs and the other for pageturn.rs,
+// both Compiler objects will share 1 static variable called BccCodeAddr.
+//
+// Key observation: Every app (process) initiates, say 3, scripts (which
+// correspond to 3 Compiler objects) in the same order, usually.
+//
+// So, we should mmap to, e.g., 0x7e00000, 0x7e40000, 0x7e80000 for the 3
+// scripts, respectively. Each time, BccCodeAddr should be updated after
+// JITTing a script. BTW, in ~Compiler(), BccCodeAddr should NOT be
+// decremented back by CodeDataSize. I.e., for 3 scripts: A, B, C,
+// even if it's A -> B -> ~B -> C -> ~C -> B -> C ... no relocation will
+// ever be needed.)
+//
+// If we are lucky, then we don't need relocation ever, since next time the
+// application gets run, the 3 scripts are likely created in the SAME order.
+//
+//
+// End-to-end algorithm on when to caching and when to JIT:
+// ========================================================
+// Prologue:
+// ---------
+// Assertion: bccReadBC() is always called and is before bccCompileBC(),
+// bccLoadBinary(), ...
+//
+// Key variable definitions: Normally,
+// Compiler::BccCodeAddr: non-zero if (USE_CACHE)
+// | (Stricter, because currently relocation doesn't work. So mUseCache only
+// | when BccCodeAddr is nonzero.)
+// V
+// mUseCache: In addition to (USE_CACHE), resName is non-zero
+// Note: mUseCache will be set to false later on whenever we find that caching
+// won't work. E.g., when mCodeDataAddr != mCacheHdr->cachedCodeDataAddr.
+// This is because currently relocation doesn't work.
+// | (Stricter, initially)
+// V
+// mCacheFd: In addition, >= 0 if openCacheFile() returns >= 0
+// | (Stricter)
+// V
+// mCacheNew: In addition, mCacheFd's size is 0, so need to call genCacheFile()
+// at the end of compile()
+//
+//
+// Main algorithm:
+// ---------------
+// #if !USE_RELOCATE
+// Case 1. ReadBC() doesn't detect a cache file:
+// compile(), which calls genCacheFile() at the end.
+// Note: mCacheNew will guard the invocation of genCacheFile()
+// Case 2. ReadBC() find a cache file
+// loadCacheFile(). But if loadCacheFile() failed, should go to Case 1.
+// #endif
+
+// Note: loadCacheFile() and genCacheFile() go hand in hand
+void Compiler::genCacheFile() {
+ if (lseek(mCacheFd, 0, SEEK_SET) != 0) {
+ LOGE("Unable to seek to 0: %s\n", strerror(errno));
+ return;
+ }
+
+ bool codeOffsetNeedPadding = false;
+
+ uint32_t offset = sizeof(oBCCHeader);
+
+ // BCC Cache File Header
+ oBCCHeader *hdr = (oBCCHeader *)malloc(sizeof(oBCCHeader));
+
+ if (!hdr) {
+ LOGE("Unable to allocate oBCCHeader.\n");
+ return;
+ }
+
+ // Magic Words
+ memcpy(hdr->magic, OBCC_MAGIC, 4);
+ memcpy(hdr->magicVersion, OBCC_MAGIC_VERS, 4);
+
+ // Timestamp
+ hdr->sourceWhen = 0; // TODO(all)
+ hdr->rslibWhen = 0; // TODO(all)
+ hdr->libRSWhen = 0; // TODO(all)
+ hdr->libbccWhen = 0; // TODO(all)
+
+ // Current Memory Address (Saved for Recalculation)
+ hdr->cachedCodeDataAddr = reinterpret_cast<uint32_t>(mCodeDataAddr);
+ hdr->rootAddr = reinterpret_cast<uint32_t>(lookup("root"));
+ hdr->initAddr = reinterpret_cast<uint32_t>(lookup("init"));
+
+ // Relocation Table Offset and Entry Count
+ hdr->relocOffset = sizeof(oBCCHeader);
+ hdr->relocCount = mCodeEmitter->getCachingRelocations().size();
+
+ offset += hdr->relocCount * (sizeof(oBCCRelocEntry));
+
+ // Export Variable Table Offset and Entry Count
+ hdr->exportVarsOffset = offset;
+ hdr->exportVarsCount = mExportVars.size();
+
+ offset += hdr->exportVarsCount * sizeof(uint32_t);
+
+ // Export Function Table Offset and Entry Count
+ hdr->exportFuncsOffset = offset;
+ hdr->exportFuncsCount = mExportFuncs.size();
+
+ offset += hdr->exportFuncsCount * sizeof(uint32_t);
+
+ // Export Pragmas Table Offset and Entry Count
+ hdr->exportPragmasOffset = offset;
+ hdr->exportPragmasCount = 0; // TODO(all): mPragmas.size();
+
+ offset += hdr->exportPragmasCount * sizeof(uint32_t);
+
+ // Code Offset and Size
+
+ { // Always pad to the page boundary for now
+ long pagesize = sysconf(_SC_PAGESIZE);
+
+ if (offset % pagesize > 0) {
+ codeOffsetNeedPadding = true;
+ offset += pagesize - (offset % pagesize);
+ }
+ }
+
+ hdr->codeOffset = offset;
+ hdr->codeSize = MaxCodeSize;
+
+ offset += hdr->codeSize;
+
+ // Data (Global Variable) Offset and Size
+ hdr->dataOffset = offset;
+ hdr->dataSize = MaxGlobalVarSize;
+
+ offset += hdr->dataSize;
+
+ // Checksum
+#if 1
+ {
+ // Note: This is an simple checksum implementation that are using xor
+ // to calculate even parity (for code and data only).
+
+ uint32_t sum = 0;
+ uint32_t *ptr = (uint32_t *)mCodeDataAddr;
+
+ for (size_t i = 0; i < BCC_MMAP_IMG_SIZE / sizeof(uint32_t); ++i) {
+ sum ^= *ptr++;
+ }
+
+ hdr->checksum = sum;
+ }
+#else
+ hdr->checksum = 0; // Set Field checksum. TODO(all)
+#endif
+
+ // Write Header
+ sysWriteFully(mCacheFd, reinterpret_cast<char const *>(hdr),
+ sizeof(oBCCHeader), "Write oBCC header");
+
+ // Write Relocation Entry Table
+ {
+ size_t allocSize = hdr->relocCount * sizeof(oBCCRelocEntry);
+
+ oBCCRelocEntry const*records = &mCodeEmitter->getCachingRelocations()[0];
+
+ sysWriteFully(mCacheFd, reinterpret_cast<char const *>(records),
+ allocSize, "Write Relocation Entries");
+ }
+
+ // Write Export Variables Table
+ {
+ uint32_t *record, *ptr;
+
+ record = (uint32_t *)calloc(hdr->exportVarsCount, sizeof(uint32_t));
+ ptr = record;
+
+ if (!record) {
+ goto bail;
+ }
+
+ for (ExportVarList::const_iterator I = mExportVars.begin(),
+ E = mExportVars.end(); I != E; I++) {
+ *ptr++ = reinterpret_cast<uint32_t>(*I);
+ }
+
+ sysWriteFully(mCacheFd, reinterpret_cast<char const *>(record),
+ hdr->exportVarsCount * sizeof(uint32_t),
+ "Write ExportVars");
+
+ free(record);
+ }
+
+ // Write Export Functions Table
+ {
+ uint32_t *record, *ptr;
+
+ record = (uint32_t *)calloc(hdr->exportFuncsCount, sizeof(uint32_t));
+ ptr = record;
+
+ if (!record) {
+ goto bail;
+ }
+
+ for (ExportFuncList::const_iterator I = mExportFuncs.begin(),
+ E = mExportFuncs.end(); I != E; I++) {
+ *ptr++ = reinterpret_cast<uint32_t>(*I);
+ }
+
+ sysWriteFully(mCacheFd, reinterpret_cast<char const *>(record),
+ hdr->exportFuncsCount * sizeof(uint32_t),
+ "Write ExportFuncs");
+
+ free(record);
+ }
+
+
+ // TODO(all): Write Export Pragmas Table
+#if 0
+#else
+ // Note: As long as we have comment out export pragmas table code,
+ // we have to seek the position to correct offset.
+
+ lseek(mCacheFd, hdr->codeOffset, SEEK_SET);
+#endif
+
+ if (codeOffsetNeedPadding) {
+ // requires additional padding
+ lseek(mCacheFd, hdr->codeOffset, SEEK_SET);
+ }
+
+ // Write Generated Code and Global Variable
+ sysWriteFully(mCacheFd, mCodeDataAddr, MaxCodeSize + MaxGlobalVarSize,
+ "Write code and global variable");
+
+ goto close_return;
+
+bail:
+ if (ftruncate(mCacheFd, 0) != 0) {
+ LOGW("Warning: unable to truncate cache file: %s\n", strerror(errno));
+ }
+
+close_return:
+ free(hdr);
+ close(mCacheFd);
+ mCacheFd = -1;
+}
+
+
+// OpenCacheFile() returns fd of the cache file.
+// Input:
+// BCCchar *resName: Used to genCacheFileName()
+// bool createIfMissing: If false, turn off caching
+// Output:
+// returns fd: If -1: Failed
+// mCacheNew: If true, the returned fd is new. Otherwise, the fd is the
+// cache file's file descriptor
+// Note: openCacheFile() will check the cache file's validity,
+// such as Magic number, sourceWhen... dependencies.
+int Compiler::openCacheFile(const BCCchar *resName, bool createIfMissing) {
+ int fd, cc;
+ struct stat fdStat, fileStat;
+ bool readOnly = false;
+
+ char *cacheFileName = genCacheFileName(resName, ".oBCC");
+
+ mCacheNew = false;
+
+retry:
+ /*
+ * Try to open the cache file. If we've been asked to,
+ * create it if it doesn't exist.
+ */
+ fd = createIfMissing ? open(cacheFileName, O_CREAT|O_RDWR, 0644) : -1;
+ if (fd < 0) {
+ fd = open(cacheFileName, O_RDONLY, 0);
+ if (fd < 0) {
+ if (createIfMissing) {
+ LOGW("Can't open bcc-cache '%s': %s\n",
+ cacheFileName, strerror(errno));
+ mUseCache = false;
+ }
+ return fd;
+ }
+ readOnly = true;
+ }
+
+ /*
+ * Grab an exclusive lock on the cache file. If somebody else is
+ * working on it, we'll block here until they complete.
+ */
+ LOGV("bcc: locking cache file %s (fd=%d, boot=%d)\n",
+ cacheFileName, fd);
+
+ cc = flock(fd, LOCK_EX | LOCK_NB);
+ if (cc != 0) {
+ LOGD("bcc: sleeping on flock(%s)\n", cacheFileName);
+ cc = flock(fd, LOCK_EX);
+ }
+
+ if (cc != 0) {
+ LOGE("Can't lock bcc cache '%s': %d\n", cacheFileName, cc);
+ close(fd);
+ return -1;
+ }
+ LOGV("bcc: locked cache file\n");
+
+ /*
+ * Check to see if the fd we opened and locked matches the file in
+ * the filesystem. If they don't, then somebody else unlinked ours
+ * and created a new file, and we need to use that one instead. (If
+ * we caught them between the unlink and the create, we'll get an
+ * ENOENT from the file stat.)
+ */
+ cc = fstat(fd, &fdStat);
+ if (cc != 0) {
+ LOGE("Can't stat open file '%s'\n", cacheFileName);
+ LOGV("bcc: unlocking cache file %s\n", cacheFileName);
+ goto close_fail;
+ }
+ cc = stat(cacheFileName, &fileStat);
+ if (cc != 0 ||
+ fdStat.st_dev != fileStat.st_dev || fdStat.st_ino != fileStat.st_ino) {
+ LOGD("bcc: our open cache file is stale; sleeping and retrying\n");
+ LOGV("bcc: unlocking cache file %s\n", cacheFileName);
+ flock(fd, LOCK_UN);
+ close(fd);
+ usleep(250 * 1000); // if something is hosed, don't peg machine
+ goto retry;
+ }
+
+ /*
+ * We have the correct file open and locked. If the file size is zero,
+ * then it was just created by us, and we want to fill in some fields
+ * in the "bcc" header and set "mCacheNew". Otherwise, we want to
+ * verify that the fields in the header match our expectations, and
+ * reset the file if they don't.
+ */
+ if (fdStat.st_size == 0) {
+ if (readOnly) { // The device is readOnly --> close_fail
+ LOGW("bcc: file has zero length and isn't writable\n");
+ goto close_fail;
+ }
+ /*cc = createEmptyHeader(fd);
+ if (cc != 0)
+ goto close_fail;
+ */
+ mCacheNew = true;
+ LOGV("bcc: successfully initialized new cache file\n");
+ } else {
+ // Calculate sourceWhen
+ // XXX
+ uint32_t sourceWhen = 0;
+ uint32_t rslibWhen = 0;
+ uint32_t libRSWhen = 0;
+ uint32_t libbccWhen = 0;
+ if (!checkHeaderAndDependencies(fd,
+ sourceWhen,
+ rslibWhen,
+ libRSWhen,
+ libbccWhen)) {
+ // If checkHeaderAndDependencies returns 0: FAILED
+ // Will truncate the file and retry to createIfMissing the file
+
+ if (readOnly) { // Shouldn't be readonly.
+ /*
+ * We could unlink and rewrite the file if we own it or
+ * the "sticky" bit isn't set on the directory. However,
+ * we're not able to truncate it, which spoils things. So,
+ * give up now.
+ */
+ if (createIfMissing) {
+ LOGW("Cached file %s is stale and not writable\n",
+ cacheFileName);
+ }
+ goto close_fail;
+ }
+
+ /*
+ * If we truncate the existing file before unlinking it, any
+ * process that has it mapped will fail when it tries to touch
+ * the pages? Probably OK because we use MAP_PRIVATE.
+ */
+ LOGD("oBCC file is stale or bad; removing and retrying (%s)\n",
+ cacheFileName);
+ if (ftruncate(fd, 0) != 0) {
+ LOGW("Warning: unable to truncate cache file '%s': %s\n",
+ cacheFileName, strerror(errno));
+ /* keep going */
+ }
+ if (unlink(cacheFileName) != 0) {
+ LOGW("Warning: unable to remove cache file '%s': %d %s\n",
+ cacheFileName, errno, strerror(errno));
+ /* keep going; permission failure should probably be fatal */
+ }
+ LOGV("bcc: unlocking cache file %s\n", cacheFileName);
+ flock(fd, LOCK_UN);
+ close(fd);
+ goto retry;
+ } else {
+ // Got cacheFile! Good to go.
+ LOGV("Good cache file\n");
+ }
+ }
+
+ assert(fd >= 0);
+ return fd;
+
+close_fail:
+ flock(fd, LOCK_UN);
+ close(fd);
+ return -1;
+} // End of openCacheFile()
+
+char *Compiler::genCacheFileName(const char *fileName,
+ const char *subFileName) {
+ char nameBuf[512];
+ static const char kCachePath[] = "bcc-cache";
+ char absoluteFile[sizeof(nameBuf)];
+ const size_t kBufLen = sizeof(nameBuf) - 1;
+ const char *dataRoot;
+ char *cp;
+
+ // Get the absolute path of the raw/***.bc file.
+ absoluteFile[0] = '\0';
+ if (fileName[0] != '/') {
+ /*
+ * Generate the absolute path. This doesn't do everything it
+ * should, e.g. if filename is "./out/whatever" it doesn't crunch
+ * the leading "./" out, but it'll do.
+ */
+ if (getcwd(absoluteFile, kBufLen) == NULL) {
+ LOGE("Can't get CWD while opening raw/***.bc file\n");
+ return NULL;
+ }
+ // TODO(srhines): strncat() is a bit dangerous
+ strncat(absoluteFile, "/", kBufLen);
+ }
+ strncat(absoluteFile, fileName, kBufLen);
+
+ if (subFileName != NULL) {
+ strncat(absoluteFile, "/", kBufLen);
+ strncat(absoluteFile, subFileName, kBufLen);
+ }
+
+ /* Turn the path into a flat filename by replacing
+ * any slashes after the first one with '@' characters.
+ */
+ cp = absoluteFile + 1;
+ while (*cp != '\0') {
+ if (*cp == '/') {
+ *cp = '@';
+ }
+ cp++;
+ }
+
+ /* Build the name of the cache directory.
+ */
+ dataRoot = getenv("ANDROID_DATA");
+ if (dataRoot == NULL)
+ dataRoot = "/data";
+ snprintf(nameBuf, kBufLen, "%s/%s", dataRoot, kCachePath);
+
+ /* Tack on the file name for the actual cache file path.
+ */
+ strncat(nameBuf, absoluteFile, kBufLen);
+
+ LOGV("Cache file for '%s' '%s' is '%s'\n", fileName, subFileName, nameBuf);
+ return strdup(nameBuf);
+}
+
+/*
+ * Read the oBCC header, verify it, then read the dependent section
+ * and verify that data as well.
+ *
+ * On successful return, the file will be seeked immediately past the
+ * oBCC header.
+ */
+bool Compiler::checkHeaderAndDependencies(int fd,
+ uint32_t sourceWhen,
+ uint32_t rslibWhen,
+ uint32_t libRSWhen,
+ uint32_t libbccWhen) {
+ ssize_t actual;
+ oBCCHeader optHdr;
+ uint32_t val;
+ uint8_t const *magic, *magicVer;
+
+ /*
+ * Start at the start. The "bcc" header, when present, will always be
+ * the first thing in the file.
+ */
+ if (lseek(fd, 0, SEEK_SET) != 0) {
+ LOGE("bcc: failed to seek to start of file: %s\n", strerror(errno));
+ goto bail;
+ }
+
+ /*
+ * Read and do trivial verification on the bcc header. The header is
+ * always in host byte order.
+ */
+ actual = read(fd, &optHdr, sizeof(optHdr));
+ if (actual < 0) {
+ LOGE("bcc: failed reading bcc header: %s\n", strerror(errno));
+ goto bail;
+ } else if (actual != sizeof(optHdr)) {
+ LOGE("bcc: failed reading bcc header (got %d of %zd)\n",
+ (int) actual, sizeof(optHdr));
+ goto bail;
+ }
+
+ magic = optHdr.magic;
+ if (memcmp(magic, OBCC_MAGIC, 4) != 0) {
+ /* not an oBCC file, or previous attempt was interrupted */
+ LOGD("bcc: incorrect opt magic number (0x%02x %02x %02x %02x)\n",
+ magic[0], magic[1], magic[2], magic[3]);
+ goto bail;
+ }
+
+ magicVer = optHdr.magicVersion;
+ if (memcmp(magic+4, OBCC_MAGIC_VERS, 4) != 0) {
+ LOGW("bcc: stale oBCC version (0x%02x %02x %02x %02x)\n",
+ magicVer[0], magicVer[1], magicVer[2], magicVer[3]);
+ goto bail;
+ }
+
+ /*
+ * Do the header flags match up with what we want?
+ *
+ * This is useful because it allows us to automatically regenerate
+ * a file when settings change (e.g. verification is now mandatory),
+ * but can cause difficulties if the thing we depend upon
+ * were handled differently than the current options specify.
+ *
+ * So, for now, we essentially ignore "expectVerify" and "expectOpt"
+ * by limiting the match mask.
+ *
+ * The only thing we really can't handle is incorrect byte-ordering.
+ */
+
+ val = optHdr.sourceWhen;
+ if (val && (val != sourceWhen)) {
+ LOGI("bcc: source file mod time mismatch (%08x vs %08x)\n",
+ val, sourceWhen);
+ goto bail;
+ }
+ val = optHdr.rslibWhen;
+ if (val && (val != rslibWhen)) {
+ LOGI("bcc: rslib file mod time mismatch (%08x vs %08x)\n",
+ val, rslibWhen);
+ goto bail;
+ }
+ val = optHdr.libRSWhen;
+ if (val && (val != libRSWhen)) {
+ LOGI("bcc: libRS file mod time mismatch (%08x vs %08x)\n",
+ val, libRSWhen);
+ goto bail;
+ }
+ val = optHdr.libbccWhen;
+ if (val && (val != libbccWhen)) {
+ LOGI("bcc: libbcc file mod time mismatch (%08x vs %08x)\n",
+ val, libbccWhen);
+ goto bail;
+ }
+
+ return true;
+
+bail:
+ return false;
+}
+
+} // namespace bcc
diff --git a/lib/bcc/Compiler.h b/lib/bcc/Compiler.h
new file mode 100644
index 0000000..08c92c5
--- /dev/null
+++ b/lib/bcc/Compiler.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_COMPILER_H
+#define BCC_COMPILER_H
+
+#include <bcc/bcc.h>
+
+#include "CodeEmitter.h"
+#include "CodeMemoryManager.h"
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Target/TargetMachine.h"
+
+#include <stddef.h>
+
+#include <list>
+#include <string>
+#include <vector>
+#include <utility>
+
+
+#define BCC_MMAP_IMG_BEGIN 0x7e000000
+#define BCC_MMAP_IMG_COUNT 5
+
+#define BCC_MMAP_IMG_CODE_SIZE (128 * 1024)
+#define BCC_MMAP_IMG_DATA_SIZE (128 * 1024)
+#define BCC_MMAP_IMG_SIZE (BCC_MMAP_IMG_CODE_SIZE + BCC_MMAP_IMG_DATA_SIZE)
+
+
+namespace llvm {
+ class LLVMContext;
+ class Module;
+}
+
+
+namespace bcc {
+
+ class Compiler {
+ // This part is designed to be orthogonal to those exported bcc*() functions
+ // implementation and internal struct BCCscript.
+
+ //////////////////////////////////////////////////////////////////////////
+ // The variable section below (e.g., Triple, CodeGenOptLevel)
+ // is initialized in GlobalInitialization()
+ //
+ static bool GlobalInitialized;
+
+ static bool BccMmapImgAddrTaken[BCC_MMAP_IMG_COUNT];
+
+ // If given, this will be the name of the target triple to compile for.
+ // If not given, the initial values defined in this file will be used.
+ static std::string Triple;
+
+ static llvm::CodeGenOpt::Level CodeGenOptLevel;
+
+ // End of section of GlobalInitializing variables
+ /////////////////////////////////////////////////////////////////////////
+ // If given, the name of the target CPU to generate code for.
+ static std::string CPU;
+
+ // The list of target specific features to enable or disable -- this should
+ // be a list of strings starting with '+' (enable) or '-' (disable).
+ static std::vector<std::string> Features;
+
+ static void GlobalInitialization();
+
+ static void LLVMErrorHandler(void *UserData, const std::string &Message);
+
+ static const llvm::StringRef PragmaMetadataName;
+ static const llvm::StringRef ExportVarMetadataName;
+ static const llvm::StringRef ExportFuncMetadataName;
+
+ friend class CodeEmitter;
+ friend class CodeMemoryManager;
+
+ private:
+ std::string mError;
+
+ bool hasError() const {
+ return !mError.empty();
+ }
+
+ void setError(const char *Error) {
+ mError.assign(Error); // Copying
+ }
+
+ void setError(const std::string &Error) {
+ mError = Error;
+ }
+
+ private:
+ bool mUseCache; // Set by readBC()
+ bool mCacheNew; // Set by readBC()
+ int mCacheFd; // Set by readBC()
+ char *mCacheMapAddr; // Set by loadCacheFile() if mCacheNew is false
+ oBCCHeader *mCacheHdr; // Set by loadCacheFile()
+ size_t mCacheSize; // Set by loadCacheFile()
+ ptrdiff_t mCacheDiff; // Set by loadCacheFile()
+ char *mCodeDataAddr; // Set by CodeMemoryManager if mCacheNew is true.
+ // Used by genCacheFile() for dumping
+
+ typedef std::list< std::pair<std::string, std::string> > PragmaList;
+ PragmaList mPragmas;
+
+ typedef std::list<void*> ExportVarList;
+ ExportVarList mExportVars;
+
+ typedef std::list<void*> ExportFuncList;
+ ExportFuncList mExportFuncs;
+
+ // The memory manager for code emitter
+ llvm::OwningPtr<CodeMemoryManager> mCodeMemMgr;
+ CodeMemoryManager *createCodeMemoryManager();
+
+ // The CodeEmitter
+ llvm::OwningPtr<CodeEmitter> mCodeEmitter;
+ CodeEmitter *createCodeEmitter();
+
+ BCCSymbolLookupFn mpSymbolLookupFn;
+ void *mpSymbolLookupContext;
+
+ llvm::LLVMContext *mContext;
+ llvm::Module *mModule;
+
+ bool mHasLinked;
+
+ public:
+ Compiler();
+
+ // interface for BCCscript::registerSymbolCallback()
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
+ mpSymbolLookupFn = pFn;
+ mpSymbolLookupContext = pContext;
+ }
+
+ int readModule(llvm::Module *module) {
+ GlobalInitialization();
+ mModule = module;
+ return hasError();
+ }
+
+ int readBC(const char *bitcode, size_t bitcodeSize,const BCCchar *resName);
+
+ int linkBC(const char *bitcode, size_t bitcodeSize);
+
+ // interface for bccLoadBinary()
+ int loadCacheFile();
+
+ // interace for bccCompileBC()
+ int compile();
+
+ // interface for bccGetScriptInfoLog()
+ char *getErrorMessage() {
+ return const_cast<char*>(mError.c_str());
+ }
+
+ // interface for bccGetScriptLabel()
+ void *lookup(const char *name);
+
+ // Interface for bccGetExportVars()
+ void getExportVars(BCCsizei *actualVarCount,
+ BCCsizei maxVarCount,
+ BCCvoid **vars);
+
+ // Interface for bccGetExportFuncs()
+ void getExportFuncs(BCCsizei *actualFuncCount,
+ BCCsizei maxFuncCount,
+ BCCvoid **funcs);
+
+ // Interface for bccGetPragmas()
+ void getPragmas(BCCsizei *actualStringCount,
+ BCCsizei maxStringCount,
+ BCCchar **strings);
+
+ // Interface for bccGetFunctions()
+ void getFunctions(BCCsizei *actualFunctionCount,
+ BCCsizei maxFunctionCount,
+ BCCchar **functions);
+
+ // Interface for bccGetFunctionBinary()
+ void getFunctionBinary(BCCchar *function,
+ BCCvoid **base,
+ BCCsizei *length);
+
+ const llvm::Module *getModule() const {
+ return mModule;
+ }
+
+ ~Compiler();
+
+ private:
+ // Note: loadCacheFile() and genCacheFile() go hand in hand
+ void genCacheFile();
+
+ // OpenCacheFile() returns fd of the cache file.
+ // Input:
+ // BCCchar *resName: Used to genCacheFileName()
+ // bool createIfMissing: If false, turn off caching
+ // Output:
+ // returns fd: If -1: Failed
+ // mCacheNew: If true, the returned fd is new. Otherwise, the fd is the
+ // cache file's file descriptor
+ // Note: openCacheFile() will check the cache file's validity,
+ // such as Magic number, sourceWhen... dependencies.
+ int openCacheFile(const BCCchar *resName, bool createIfMissing);
+
+ char *genCacheFileName(const char *fileName, const char *subFileName);
+
+ /*
+ * Read the oBCC header, verify it, then read the dependent section
+ * and verify that data as well.
+ *
+ * On successful return, the file will be seeked immediately past the
+ * oBCC header.
+ */
+ bool checkHeaderAndDependencies(int fd,
+ uint32_t sourceWhen,
+ uint32_t rslibWhen,
+ uint32_t libRSWhen,
+ uint32_t libbccWhen);
+
+ };
+
+
+
+} // namespace bcc
+
+#endif // BCC_COMPILER_H
diff --git a/lib/bcc/EmittedFuncEntry.h b/lib/bcc/EmittedFuncEntry.h
new file mode 100644
index 0000000..798c354
--- /dev/null
+++ b/lib/bcc/EmittedFuncEntry.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_EMITTEDFUNCENTRY_H
+#define BCC_EMITTEDFUNCENTRY_H
+
+#include <stddef.h>
+
+namespace bcc {
+
+ class EmittedFuncEntry {
+ public:
+ // Beginning of the function's allocation.
+ void *FunctionBody;
+
+ // The address the function's code actually starts at.
+ void *Code;
+
+ // The size of the function code
+ int Size;
+
+ EmittedFuncEntry() : FunctionBody(NULL), Code(NULL) {
+ }
+
+ };
+
+} // namespace bcc
+
+#endif // BCC_EMITTEDFUNCENTRY_H
diff --git a/lib/bcc/Runtime.c b/lib/bcc/Runtime.c
new file mode 100644
index 0000000..3f690aa
--- /dev/null
+++ b/lib/bcc/Runtime.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "runtime/lib/absvdi2.c"
+#include "runtime/lib/absvsi2.c"
+#include "runtime/lib/addvdi3.c"
+#include "runtime/lib/addvsi3.c"
+#include "runtime/lib/ashldi3.c"
+#ifndef ANDROID
+# include "runtime/lib/ashrdi3.c"
+#endif
+#include "runtime/lib/clzdi2.c"
+#include "runtime/lib/clzsi2.c"
+#include "runtime/lib/cmpdi2.c"
+#include "runtime/lib/ctzdi2.c"
+#include "runtime/lib/ctzsi2.c"
+#ifndef ANDROID // no complex.h
+# include "runtime/lib/divdc3.c"
+#endif
+#include "runtime/lib/divdi3.c"
+#ifndef ANDROID // no complex.h
+# include "runtime/lib/divsc3.c"
+#endif
+#include "runtime/lib/ffsdi2.c"
+#include "runtime/lib/fixdfdi.c"
+#include "runtime/lib/fixsfdi.c"
+#include "runtime/lib/fixunsdfdi.c"
+#include "runtime/lib/fixunsdfsi.c"
+#include "runtime/lib/fixunssfdi.c"
+#include "runtime/lib/fixunssfsi.c"
+#include "runtime/lib/floatdidf.c"
+#include "runtime/lib/floatdisf.c"
+#include "runtime/lib/floatundidf.c"
+#include "runtime/lib/floatundisf.c"
+#include "runtime/lib/lshrdi3.c"
+#include "runtime/lib/moddi3.c"
+#ifndef ANDROID // no complex.h
+# include "runtime/lib/muldc3.c"
+#endif
+#include "runtime/lib/muldi3.c"
+#ifndef ANDROID // no complex.h
+# include "runtime/lib/mulsc3.c"
+#endif
+#include "runtime/lib/mulvdi3.c"
+#include "runtime/lib/mulvsi3.c"
+#include "runtime/lib/negdi2.c"
+#include "runtime/lib/negvdi2.c"
+#include "runtime/lib/negvsi2.c"
+#include "runtime/lib/paritydi2.c"
+#include "runtime/lib/paritysi2.c"
+#include "runtime/lib/popcountdi2.c"
+#include "runtime/lib/popcountsi2.c"
+#include "runtime/lib/powidf2.c"
+#include "runtime/lib/powisf2.c"
+#include "runtime/lib/subvdi3.c"
+#include "runtime/lib/subvsi3.c"
+#include "runtime/lib/ucmpdi2.c"
+#include "runtime/lib/udivdi3.c"
+#include "runtime/lib/udivsi3.c"
+#include "runtime/lib/udivmoddi4.c"
+#include "runtime/lib/umoddi3.c"
+#include "runtime/lib/eprintf.c"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+typedef struct {
+ const char *mName;
+ void *mPtr;
+} RuntimeFunction;
+
+#define USE_VFP_RUNTIME 1
+
+#if defined(__arm__)
+ #define DEF_GENERIC_RUNTIME(func) \
+ extern void *func;
+ #define DEF_VFP_RUNTIME(func) \
+ extern void *func ## vfp;
+ #define DEF_LLVM_RUNTIME(func)
+ #define DEF_BCC_RUNTIME(func)
+#include "Runtime.def"
+#endif
+
+static const RuntimeFunction gRuntimes[] = {
+#if defined(__arm__)
+ #define DEF_GENERIC_RUNTIME(func) \
+ { #func, (void*) &func },
+ // TODO: enable only when target support VFP
+ #define DEF_VFP_RUNTIME(func) \
+ { #func, (void*) &func ## vfp },
+#else
+ // host compiler library must contain generic runtime
+ #define DEF_GENERIC_RUNTIME(func)
+ #define DEF_VFP_RUNTIME(func)
+#endif
+#define DEF_LLVM_RUNTIME(func) \
+ { #func, (void*) &func },
+#define DEF_BCC_RUNTIME(func) \
+ { #func, &func ## _bcc },
+#include "Runtime.def"
+};
+
+static int CompareRuntimeFunction(const void *a, const void *b) {
+ return strcmp(((const RuntimeFunction*) a)->mName,
+ ((const RuntimeFunction*) b)->mName);
+}
+
+void *FindRuntimeFunction(const char *Name) {
+ // binary search
+ const RuntimeFunction Key = { Name, NULL };
+ const RuntimeFunction *R =
+ bsearch(&Key,
+ gRuntimes,
+ sizeof(gRuntimes) / sizeof(RuntimeFunction),
+ sizeof(RuntimeFunction),
+ CompareRuntimeFunction);
+
+ return ((R) ? R->mPtr : NULL);
+}
+
+void VerifyRuntimesTable() {
+ unsigned N = sizeof(gRuntimes) / sizeof(RuntimeFunction), i;
+ for(i = 0; i < N; i++) {
+ const char *Name = gRuntimes[i].mName;
+ int *Ptr = FindRuntimeFunction(Name);
+
+ if (Ptr != (int*) gRuntimes[i].mPtr)
+ assert(false && "Table is corrupted (runtime name should be sorted in "
+ "Runtime.def).");
+ }
+}
diff --git a/lib/bcc/Runtime.def b/lib/bcc/Runtime.def
new file mode 100644
index 0000000..484915f
--- /dev/null
+++ b/lib/bcc/Runtime.def
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef USE_VFP_RUNTIME
+# define DEF_GENERIC_OR_VFP_RUNTIME(func) DEF_VFP_RUNTIME(func)
+# define DEF_LLVM_OR_VFP_RUNTIME(func) DEF_VFP_RUNTIME(func)
+#else
+# undef DEF_VFP_RUNTIME
+# define DEF_VFP_RUNTIME(func)
+# define DEF_GENERIC_OR_VFP_RUNTIME(func) DEF_GENERIC_RUNTIME(func)
+# define DEF_LLVM_OR_VFP_RUNTIME(func) DEF_LLVM_RUNTIME(func)
+#endif
+
+// Sorted
+DEF_LLVM_RUNTIME(__absvdi2)
+DEF_LLVM_RUNTIME(__absvsi2)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__adddf3)
+DEF_GENERIC_OR_VFP_RUNTIME(__addsf3)
+
+DEF_LLVM_RUNTIME(__addvdi3)
+DEF_LLVM_RUNTIME(__addvsi3)
+DEF_LLVM_RUNTIME(__ashldi3)
+#ifndef ANDROID // has one in bionic
+ DEF_LLVM_RUNTIME(__ashrdi3)
+#endif
+
+#ifdef USE_VFP_RUNTIME
+// DEF_GENERIC_RUNTIME(__bswapdi2)
+// DEF_GENERIC_RUNTIME(__bswapsi2)
+#endif
+
+DEF_LLVM_RUNTIME(__clzdi2)
+DEF_LLVM_RUNTIME(__clzsi2)
+DEF_LLVM_RUNTIME(__cmpdi2)
+DEF_LLVM_RUNTIME(__ctzdi2)
+DEF_LLVM_RUNTIME(__ctzsi2)
+
+#ifndef ANDROID // no complex extension
+ DEF_LLVM_RUNTIME(__divdc3)
+#endif
+
+DEF_GENERIC_OR_VFP_RUNTIME(__divdf3)
+
+DEF_LLVM_RUNTIME(__divdi3)
+
+#ifndef ANDROID // no complex extension
+ DEF_LLVM_RUNTIME(__divsc3)
+#endif
+
+DEF_GENERIC_OR_VFP_RUNTIME(__divsf3)
+
+DEF_LLVM_RUNTIME(__eprintf)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__eqdf2)
+DEF_GENERIC_OR_VFP_RUNTIME(__eqsf2)
+DEF_GENERIC_OR_VFP_RUNTIME(__extendsfdf2)
+
+DEF_LLVM_RUNTIME(__ffsdi2)
+DEF_LLVM_RUNTIME(__fixdfdi)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__fixdfsi)
+
+DEF_LLVM_RUNTIME(__fixsfdi)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__fixsfsi)
+
+DEF_LLVM_RUNTIME(__fixunsdfdi)
+DEF_LLVM_OR_VFP_RUNTIME(__fixunsdfsi)
+DEF_LLVM_RUNTIME(__fixunssfdi)
+
+DEF_LLVM_OR_VFP_RUNTIME(__fixunssfsi)
+
+DEF_LLVM_RUNTIME(__floatdidf)
+DEF_LLVM_RUNTIME(__floatdisf)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__floatsidf)
+DEF_GENERIC_OR_VFP_RUNTIME(__floatsisf)
+
+DEF_LLVM_RUNTIME(__floatundidf)
+DEF_LLVM_RUNTIME(__floatundisf)
+
+DEF_GENERIC_RUNTIME(__floatunsidf)
+DEF_GENERIC_RUNTIME(__floatunsisf)
+
+DEF_VFP_RUNTIME(__floatunssidf)
+DEF_VFP_RUNTIME(__floatunssisf)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__gedf2)
+DEF_GENERIC_OR_VFP_RUNTIME(__gesf2)
+DEF_VFP_RUNTIME(__gtdf2)
+DEF_VFP_RUNTIME(__gtsf2)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__ledf2)
+DEF_GENERIC_OR_VFP_RUNTIME(__lesf2)
+
+DEF_LLVM_RUNTIME(__lshrdi3)
+
+DEF_VFP_RUNTIME(__ltdf2)
+DEF_VFP_RUNTIME(__ltsf2)
+
+DEF_LLVM_RUNTIME(__moddi3)
+
+#ifndef ANDROID // no complex extension
+ DEF_LLVM_RUNTIME(__muldc3)
+#endif
+
+DEF_GENERIC_OR_VFP_RUNTIME(__muldf3)
+DEF_LLVM_RUNTIME(__muldi3)
+DEF_LLVM_RUNTIME(__muldsi3)
+
+#ifndef ANDROID // no complex extension
+ DEF_LLVM_RUNTIME(__mulsc3)
+#endif
+
+DEF_GENERIC_OR_VFP_RUNTIME(__mulsf3)
+
+DEF_LLVM_RUNTIME(__mulvdi3)
+DEF_LLVM_RUNTIME(__mulvsi3)
+
+DEF_VFP_RUNTIME(__nedf2)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__negdf2)
+
+DEF_LLVM_RUNTIME(__negdi2)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__negsf2)
+
+DEF_LLVM_RUNTIME(__negvdi2)
+DEF_LLVM_RUNTIME(__negvsi2)
+
+DEF_VFP_RUNTIME(__nesf2)
+
+DEF_LLVM_RUNTIME(__paritydi2)
+DEF_LLVM_RUNTIME(__paritysi2)
+DEF_LLVM_RUNTIME(__popcountdi2)
+DEF_LLVM_RUNTIME(__popcountsi2)
+DEF_LLVM_RUNTIME(__powidf2)
+DEF_LLVM_RUNTIME(__powisf2)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__subdf3)
+DEF_GENERIC_OR_VFP_RUNTIME(__subsf3)
+
+DEF_LLVM_RUNTIME(__subvdi3)
+DEF_LLVM_RUNTIME(__subvsi3)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__truncdfsf2)
+
+DEF_LLVM_RUNTIME(__ucmpdi2)
+DEF_LLVM_RUNTIME(__udivdi3)
+DEF_LLVM_RUNTIME(__udivmoddi4)
+DEF_LLVM_RUNTIME(__udivsi3)
+DEF_LLVM_RUNTIME(__umoddi3)
+
+DEF_GENERIC_OR_VFP_RUNTIME(__unorddf2)
+DEF_GENERIC_OR_VFP_RUNTIME(__unordsf2)
+
+#undef DEF_GENERIC_RUNTIME
+#undef DEF_LLVM_RUNTIME
+#undef DEF_VFP_RUNTIME
+#undef DEF_BCC_RUNTIME
diff --git a/lib/bcc/Runtime.h b/lib/bcc/Runtime.h
new file mode 100644
index 0000000..c0b7ad8
--- /dev/null
+++ b/lib/bcc/Runtime.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RUNTIME_H
+#define BCC_RUNTIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *FindRuntimeFunction(const char *Name);
+void VerifyRuntimesTable();
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* BCC_RUNTIME_H */
diff --git a/lib/bcc/Script.h b/lib/bcc/Script.h
new file mode 100644
index 0000000..5307f07
--- /dev/null
+++ b/lib/bcc/Script.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SCRIPT_H
+#define BCC_SCRIPT_H
+
+#include "Compiler.h"
+
+#include <bcc/bcc.h>
+
+namespace bcc {
+
+ class BCCscript {
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ // Part I. Compiler
+ //////////////////////////////////////////////////////////////////////////
+ Compiler compiler;
+
+ void registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
+ compiler.registerSymbolCallback(pFn, pContext);
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Part II. Logistics & Error handling
+ //////////////////////////////////////////////////////////////////////////
+ BCCscript() {
+ bccError = BCC_NO_ERROR;
+ }
+
+ ~BCCscript() {
+ }
+
+ void setError(BCCenum error) {
+ if (bccError == BCC_NO_ERROR && error != BCC_NO_ERROR) {
+ bccError = error;
+ }
+ }
+
+ BCCenum getError() {
+ BCCenum result = bccError;
+ bccError = BCC_NO_ERROR;
+ return result;
+ }
+
+ BCCenum bccError;
+ };
+
+} // namespace bcc
+
+#endif // BCC_SCRIPT_H
diff --git a/lib/bcc/bcc.cpp b/lib/bcc/bcc.cpp
new file mode 100644
index 0000000..6b64d36
--- /dev/null
+++ b/lib/bcc/bcc.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Bitcode compiler (bcc) for Android:
+// This is an eager-compilation JIT running on Android.
+
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+
+#include "Compiler.h"
+#include "Script.h"
+
+#include <bcc/bcc.h>
+
+#include <utils/StopWatch.h>
+
+
+namespace llvm {
+ class Module;
+}
+
+
+extern "C" BCCscript *bccCreateScript() {
+ return new BCCscript();
+}
+
+extern "C" BCCenum bccGetError(BCCscript *script) {
+ return script->getError();
+}
+
+extern "C" void bccDeleteScript(BCCscript *script) {
+ delete script;
+}
+
+extern "C" void bccRegisterSymbolCallback(BCCscript *script,
+ BCCSymbolLookupFn pFn,
+ BCCvoid *pContext) {
+ script->registerSymbolCallback(pFn, pContext);
+}
+
+extern "C" int bccReadModule(BCCscript *script, BCCvoid *module) {
+ return script->compiler.readModule(reinterpret_cast<llvm::Module*>(module));
+}
+
+extern "C" int bccReadBC(BCCscript *script,
+ const BCCchar *bitcode,
+ BCCint size,
+ const BCCchar *resName) {
+ return script->compiler.readBC(bitcode, size, resName);
+}
+
+extern "C" void bccLinkBC(BCCscript *script,
+ const BCCchar *bitcode,
+ BCCint size) {
+ script->compiler.linkBC(bitcode, size);
+}
+
+extern "C" int bccLoadBinary(BCCscript *script) {
+ int result = script->compiler.loadCacheFile();
+ if (result)
+ script->setError(BCC_INVALID_OPERATION);
+ return result;
+}
+
+extern "C" void bccCompileBC(BCCscript *script) {
+ {
+#if defined(__arm__)
+ android::StopWatch compileTimer("RenderScript compile time");
+#endif
+ int result = script->compiler.compile();
+ if (result)
+ script->setError(BCC_INVALID_OPERATION);
+ }
+}
+
+extern "C" void bccGetScriptInfoLog(BCCscript *script,
+ BCCsizei maxLength,
+ BCCsizei *length,
+ BCCchar *infoLog) {
+ char *message = script->compiler.getErrorMessage();
+ int messageLength = strlen(message) + 1;
+ if (length)
+ *length = messageLength;
+
+ if (infoLog && maxLength > 0) {
+ int trimmedLength = maxLength < messageLength ? maxLength : messageLength;
+ memcpy(infoLog, message, trimmedLength);
+ infoLog[trimmedLength] = 0;
+ }
+}
+
+extern "C" void bccGetScriptLabel(BCCscript *script,
+ const BCCchar *name,
+ BCCvoid **address) {
+ void *value = script->compiler.lookup(name);
+ if (value)
+ *address = value;
+ else
+ script->setError(BCC_INVALID_VALUE);
+}
+
+extern "C" void bccGetExportVars(BCCscript *script,
+ BCCsizei *actualVarCount,
+ BCCsizei maxVarCount,
+ BCCvoid **vars) {
+ script->compiler.getExportVars(actualVarCount, maxVarCount, vars);
+}
+
+extern "C" void bccGetExportFuncs(BCCscript *script,
+ BCCsizei *actualFuncCount,
+ BCCsizei maxFuncCount,
+ BCCvoid **funcs) {
+ script->compiler.getExportFuncs(actualFuncCount, maxFuncCount, funcs);
+}
+
+extern "C" void bccGetPragmas(BCCscript *script,
+ BCCsizei *actualStringCount,
+ BCCsizei maxStringCount,
+ BCCchar **strings) {
+ script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
+}
+
+extern "C" void bccGetFunctions(BCCscript *script,
+ BCCsizei *actualFunctionCount,
+ BCCsizei maxFunctionCount,
+ BCCchar **functions) {
+ script->compiler.getFunctions(actualFunctionCount,
+ maxFunctionCount,
+ functions);
+}
+
+extern "C" void bccGetFunctionBinary(BCCscript *script,
+ BCCchar *function,
+ BCCvoid **base,
+ BCCsizei *length) {
+ script->compiler.getFunctionBinary(function, base, length);
+}