// Call handlers: flexible map of call targets to arbitrary handling code
//
// Each handler needs DEF_CALL_HANDLER and SETUP_CALL_HANDLER
//
typedef std::string (JSWriter::*CallHandler)(const Instruction*, std::string Name, int NumArgs);
typedef std::map<std::string, CallHandler> CallHandlerMap;
CallHandlerMap *CallHandlers;
// Definitions
unsigned getNumArgOperands(const Instruction *I) {
return ImmutableCallSite(I).arg_size();
}
const Value *getActuallyCalledValue(const Instruction *I) {
const Value *CV = ImmutableCallSite(I).getCalledValue();
// if the called value is a bitcast of a function, then we just call it directly, properly
// for example, extern void x() in C will turn into void x(...) in LLVM IR, then the IR bitcasts
// it to the proper form right before the call. this both causes an unnecessary indirect
// call, and it is done with the wrong type. TODO: don't even put it into the function table
if (const Function *F = dyn_cast<const Function>(CV->stripPointerCasts())) {
CV = F;
}
return CV;
}
#define DEF_CALL_HANDLER(Ident, Code) \
std::string CH_##Ident(const Instruction *CI, std::string Name, int NumArgs=-1) { Code }
DEF_CALL_HANDLER(__default__, {
if (!CI) return ""; // we are just called from a handler that was called from getFunctionIndex, only to ensure the handler was run at least once
const Value *CV = getActuallyCalledValue(CI);
bool NeedCasts;
FunctionType *FT;
bool Invoke = false;
if (InvokeState == 1) {
InvokeState = 2;
Invoke = true;
}
std::string Sig;
const Function *F = dyn_cast<const Function>(CV);
if (F) {
NeedCasts = F->isDeclaration(); // if ffi call, need casts
FT = F->getFunctionType();
if (EmscriptenAssertions) {
unsigned TypeNumArgs = FT->getNumParams();
unsigned ActualNumArgs = getNumArgOperands(CI);
if (TypeNumArgs != ActualNumArgs) {
errs().changeColor(raw_ostream::YELLOW);
errs() << "warning:";
errs().resetColor();
errs() << " unexpected number of arguments " << utostr(ActualNumArgs) << " in call to '" << F->getName() << "', should be " << utostr(TypeNumArgs) << "\n";
}
for (unsigned i = 0; i < std::min(TypeNumArgs, ActualNumArgs); i++) {
Type *TypeType = FT->getParamType(i);
Type *ActualType = CI->getOperand(i)->getType();
if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(ActualType)) {
errs().changeColor(raw_ostream::YELLOW);
errs() << "warning:";
errs().resetColor();
errs() << " unexpected argument type " << *ActualType << " at index " << utostr(i) << " in call to '" << F->getName() << "', should be " << *TypeType << "\n";
}
}
Type *TypeType = FT->getReturnType();
Type *ActualType = CI->getType();
if (getFunctionSignatureLetter(TypeType) != getFunctionSignatureLetter(ActualType)) {
errs().changeColor(raw_ostream::YELLOW);
errs() << "warning:";
errs().resetColor();
errs() << " unexpected return type " << *ActualType << " in call to '" << F->getName() << "', should be " << *TypeType << "\n";
}
}
} else {
if (isAbsolute(CV)) return "abort(); /* segfault, call an absolute addr */";
// function pointer call
FT = dyn_cast<FunctionType>(dyn_cast<PointerType>(CV->getType())->getElementType());
ensureFunctionTable(FT);
if (!Invoke) {
Sig =