// FIXME: This might have been relevant for the old JIT but the MCJIT // has a completly different implementation so this comment below is // likely irrelevant and misleading. // // For performance purposes we construct the stub in such a way that the // arguments pointer is passed through the static global variable gTheArgsP in // this file. This is done so that the stub function prototype trivially matches // the special cases that the JIT knows how to directly call. If this is not // done, then the jit will end up generating a nullary stub just to call our // stub, for every single function call. Function *ExternalDispatcherImpl::createDispatcher(Function *target, Instruction *inst, Module *module) { if (!resolveSymbol(target->getName())) return 0; CallSite cs; if (inst->getOpcode() == Instruction::Call) { cs = CallSite(cast<CallInst>(inst)); } else { cs = CallSite(cast<InvokeInst>(inst)); } Value **args = new Value *[cs.arg_size()]; std::vector<Type *> nullary; // MCJIT functions need unique names, or wrong function can be called. // The module identifier is included because for the MCJIT we need // unique function names across all `llvm::Modules`s. std::string fnName = "dispatcher_" + target->getName().str() + module->getModuleIdentifier(); Function *dispatcher = Function::Create(FunctionType::get(Type::getVoidTy(ctx), nullary, false), GlobalVariable::ExternalLinkage, fnName, module); BasicBlock *dBB = BasicBlock::Create(ctx, "entry", dispatcher); // Get a Value* for &gTheArgsP, as an i64**. Instruction *argI64sp = new IntToPtrInst( ConstantInt::get(Type::getInt64Ty(ctx), (uintptr_t)(void *)&gTheArgsP), PointerType::getUnqual(PointerType::getUnqual(Type::getInt64Ty(ctx))), "argsp", dBB); Instruction *argI64s = new LoadInst(argI64sp, "args", dBB); // Get the target function type. FunctionType *FTy = cast<FunctionType>( cast<PointerType>(target->getType())->getElementType()); // Each argument will be passed by writing it into gTheArgsP[i]. unsigned i = 0, idx = 2; for (CallSite::arg_iterator ai = cs.arg_begin(), ae = cs.arg_end(); ai != ae; ++ai, ++i) { // Determine the type the argument will be passed as. This accomodates for // the corresponding code in Executor.cpp for handling calls to bitcasted // functions. Type *argTy = (i < FTy->getNumParams() ? FTy->getParamType(i) : (*ai)->getType()); Instruction *argI64p = GetElementPtrInst::Create( KLEE_LLVM_GEP_TYPE(nullptr) argI64s, ConstantInt::get(Type::getInt32Ty(ctx), idx), "", dBB); Instruction *argp = new BitCastInst(argI64p, PointerType::getUnqual(argTy), "", dBB); args[i] = new LoadInst(argp, "", dBB); unsigned argSize = argTy->getPrimitiveSizeInBits(); idx += ((!!argSize ? argSize : 64) + 63) / 64; } Constant *dispatchTarget = module->getOrInsertFunction( target->getName(), FTy, target->getAttributes()); Instruction *result = CallInst::Create( dispatchTarget, llvm::ArrayRef<Value *>(args, args + i), "", dBB); if (result->getType() != Type::getVoidTy(ctx)) { Instruction *resp = new BitCastInst( argI64s, PointerType::getUnqual(result->getType()), "", dBB); new StoreInst(result, resp, dBB); } ReturnInst::Create(ctx, dBB); delete[] args; return dispatcher; }
inline String parseExpression(QStringRef const &expression) const { // Presently the expression consists of a single symbol. return resolveSymbol(expression); }