Commit 2d7d24ca authored by Kevin Modzelewski's avatar Kevin Modzelewski

Use profiling to know when to throw CAPI exceptions

Also, allow reraising using CAPI exceptions.
parent 3307cddc
......@@ -202,6 +202,8 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
exception_style = CAPI;
if (name == "next")
exception_style = CAPI;
if (f->propagated_cxx_exceptions >= 100)
exception_style = CAPI;
if (VERBOSITY("irgen") >= 1) {
std::string s;
......
......@@ -2296,17 +2296,26 @@ private:
// It looks like ommitting the second and third arguments are equivalent to passing None,
// but ommitting the first argument is *not* the same as passing None.
ExceptionStyle target_exception_style = CXX;
if (unw_info.preferredExceptionStyle() == CAPI && (node->arg0 && !node->arg2))
ExceptionStyle target_exception_style;
if (unw_info.hasHandler())
target_exception_style = CAPI;
else
target_exception_style = irstate->getExceptionStyle();
if (node->arg0 == NULL) {
assert(!node->arg1);
assert(!node->arg2);
assert(target_exception_style == CXX);
emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>());
emitter.getBuilder()->CreateUnreachable();
if (target_exception_style == CAPI) {
emitter.createCall(unw_info, g.funcs.raise0_capi, std::vector<llvm::Value*>(), CAPI);
emitter.checkAndPropagateCapiException(unw_info, getNullPtr(g.llvm_value_type_ptr),
getNullPtr(g.llvm_value_type_ptr));
emitter.getBuilder()->CreateUnreachable();
} else {
emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>());
emitter.getBuilder()->CreateUnreachable();
}
endBlock(DEAD);
return;
......
......@@ -307,6 +307,7 @@ void initGlobalFuncs(GlobalState& g) {
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
GET(raise0);
GET(raise0_capi);
GET(raise3);
GET(raise3_capi);
GET(PyErr_Fetch);
......
......@@ -50,7 +50,7 @@ struct GlobalFuncs {
llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel;
llvm::Value* __cxa_end_catch;
llvm::Value* raise0, *raise3, *raise3_capi;
llvm::Value* raise0, *raise0_capi, *raise3, *raise3_capi;
llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *caughtCapiException, *reraiseCapiExcAsCxx;
llvm::Value* deopt;
......
......@@ -556,6 +556,8 @@ public:
PythonFrameIteratorImpl frame_iter;
bool found_frame = pystack_extractor.handleCFrame(cursor, &frame_iter);
if (found_frame) {
frame_iter.getCL()->propagated_cxx_exceptions++;
if (exceptionAtLineCheck()) {
// TODO: shouldn't fetch this multiple times?
frame_iter.getCurrentStatement()->cxx_exception_count++;
......
......@@ -376,6 +376,8 @@ public:
// Please use codeForFunction() to access this:
BoxedCode* code_obj;
int propagated_cxx_exceptions = 0;
// For use by the interpreter/baseline jit:
int times_interpreted;
std::vector<std::unique_ptr<JitCodeBlock>> code_blocks;
......
......@@ -68,19 +68,6 @@ void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* nod
raiseSyntaxError(buf, node_at->lineno, node_at->col_offset, file, "");
}
extern "C" void raise0() {
ExcInfo* exc_info = getFrameExcInfo();
assert(exc_info->type);
// TODO need to clean up when we call normalize, do_raise, etc
if (exc_info->type == None)
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not NoneType");
startReraise();
assert(!PyErr_Occurred());
throw * exc_info;
}
void ExcInfo::printExcAndTraceback() const {
PyErr_Display(type, value, traceback);
}
......@@ -148,6 +135,35 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) {
return ExcInfo(type, value, tb);
}
extern "C" void raise0() {
ExcInfo* exc_info = getFrameExcInfo();
assert(exc_info->type);
// TODO need to clean up when we call normalize, do_raise, etc
if (exc_info->type == None)
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not NoneType");
startReraise();
assert(!PyErr_Occurred());
throw * exc_info;
}
extern "C" void raise0_capi() noexcept {
ExcInfo exc_info = *getFrameExcInfo();
assert(exc_info.type);
// TODO need to clean up when we call normalize, do_raise, etc
if (exc_info.type == None) {
exc_info.type = TypeError;
exc_info.value = boxString("exceptions must be old-style classes or derived from BaseException, not NoneType");
exc_info.traceback = None;
PyErr_NormalizeException(&exc_info.type, &exc_info.value, &exc_info.traceback);
}
startReraise();
PyErr_Restore(exc_info.type, exc_info.value, exc_info.traceback);
}
extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
bool reraise = arg2 != NULL && arg2 != None;
auto exc_info = excInfoForRaise(arg0, arg1, arg2);
......
......@@ -125,6 +125,7 @@ void force() {
FORCE(callattrCapi);
FORCE(raise0);
FORCE(raise0_capi);
FORCE(raise3);
FORCE(raise3_capi);
FORCE(PyErr_Fetch);
......
......@@ -34,6 +34,7 @@ class BoxedTuple;
// user-level raise functions that implement python-level semantics
ExcInfo excInfoForRaise(Box*, Box*, Box*);
extern "C" void raise0() __attribute__((__noreturn__));
extern "C" void raise0_capi() noexcept;
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3_capi(Box*, Box*, Box*) noexcept;
void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment