[LLVMdev] Proper way to handle JIT codegen exceptions?
Török Edwin
edwintorok at gmail.com
Fri Oct 28 00:31:44 PDT 2011
On 10/28/2011 09:00 AM, Gregory Junker wrote:
> I am looking through the source and Support/ErrorHandling.cpp/.h says, in so
> many words, "don't throw exceptions from inside an installed fatal error
> handling routine".
>
> So how are people handling errors during JIT? For command-line compilers,
> calling exit() or abort() isn't as big a deal -- the compiler is probably
> going to exit anyway. But say, for instance, the host application is Firefox
> -- my guess is that just letting exit() handle the situation isn't the
> solution.
>
> So what is the "proper" way to handle exceptional LLVM conditions ("cannot
> select", for instance)? Yes, I know this is something that needs to be
> brought to the programmer's attention, but having the user's application
> crash out on them isn't the way I expect most actual LLVM-JIT-based
> applications are handling these things...
I use setjmp/longjmp in ClamAV. Would be better if instead of throwing a fatal error
the code generators would simply return an error code, but that would be too much work.
Although this might leak memory in the case of a fatal error, it is better than crashing (for example
in ClamAV we simply turn off the JIT and fallback to our own interpreter).
I wrap all my toplevel functions that call into LLVM with (there are only 3):
HANDLER_TRY(handler) {
...
return 0;
} HANDLER_END(handler);
return ...some_errorcode...
class ScopedExceptionHandler {
public:
jmp_buf &getEnv() { return env;}
void Set() {
/* set the exception handler's return location to here for the
* current thread */
ExceptionReturn.set((const jmp_buf*)&env);
}
~ScopedExceptionHandler() {
/* leaving scope, remove exception handler for current thread */
ExceptionReturn.erase();
}
private:
jmp_buf env;
};
static sys::ThreadLocal<const jmp_buf> ExceptionReturn;
static void NORETURN jit_exception_handler(void)
{
jmp_buf* buf = const_cast<jmp_buf*>(ExceptionReturn.get());
if (buf) {
// For errors raised during bytecode generation and execution.
longjmp(*buf, 1);
} else {
// Oops, got no error recovery pointer set up,
// this is probably an error raised during shutdown.
cli_errmsg("[Bytecode JIT]: exception handler called, but no recovery point set up");
// should never happen, we remove the error handler when we don't use
// LLVM anymore, and when we use it, we do set an error recovery point.
llvm_unreachable("Bytecode JIT]: no exception handler recovery installed, but exception hit!");
}
}
void llvm_error_handler(void *user_data, const std::string &reason)
{
// Output it to stderr, it might exceed the 1k/4k limit of cli_errmsg
cli_errmsg("[Bytecode JIT]: [LLVM error] %s\n", reason.c_str());
jit_exception_handler();
}
};
#define HANDLER_TRY(handler) \
if (setjmp(handler.getEnv()) == 0) {\
handler.Set();
#define HANDLER_END(handler) \
} else cli_warnmsg("[Bytecode JIT]: recovered from error\n");
More information about the llvm-dev
mailing list