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 ...@@ -202,6 +202,8 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
exception_style = CAPI; exception_style = CAPI;
if (name == "next") if (name == "next")
exception_style = CAPI; exception_style = CAPI;
if (f->propagated_cxx_exceptions >= 100)
exception_style = CAPI;
if (VERBOSITY("irgen") >= 1) { if (VERBOSITY("irgen") >= 1) {
std::string s; std::string s;
......
...@@ -2296,17 +2296,26 @@ private: ...@@ -2296,17 +2296,26 @@ private:
// It looks like ommitting the second and third arguments are equivalent to passing None, // 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. // but ommitting the first argument is *not* the same as passing None.
ExceptionStyle target_exception_style = CXX; ExceptionStyle target_exception_style;
if (unw_info.preferredExceptionStyle() == CAPI && (node->arg0 && !node->arg2))
if (unw_info.hasHandler())
target_exception_style = CAPI; target_exception_style = CAPI;
else
target_exception_style = irstate->getExceptionStyle();
if (node->arg0 == NULL) { if (node->arg0 == NULL) {
assert(!node->arg1); assert(!node->arg1);
assert(!node->arg2); assert(!node->arg2);
assert(target_exception_style == CXX); if (target_exception_style == CAPI) {
emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>()); emitter.createCall(unw_info, g.funcs.raise0_capi, std::vector<llvm::Value*>(), CAPI);
emitter.getBuilder()->CreateUnreachable(); 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); endBlock(DEAD);
return; return;
......
...@@ -307,6 +307,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -307,6 +307,7 @@ void initGlobalFuncs(GlobalState& g) {
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_); g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
GET(raise0); GET(raise0);
GET(raise0_capi);
GET(raise3); GET(raise3);
GET(raise3_capi); GET(raise3_capi);
GET(PyErr_Fetch); GET(PyErr_Fetch);
......
...@@ -50,7 +50,7 @@ struct GlobalFuncs { ...@@ -50,7 +50,7 @@ struct GlobalFuncs {
llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel; llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel;
llvm::Value* __cxa_end_catch; 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* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *caughtCapiException, *reraiseCapiExcAsCxx;
llvm::Value* deopt; llvm::Value* deopt;
......
...@@ -556,6 +556,8 @@ public: ...@@ -556,6 +556,8 @@ public:
PythonFrameIteratorImpl frame_iter; PythonFrameIteratorImpl frame_iter;
bool found_frame = pystack_extractor.handleCFrame(cursor, &frame_iter); bool found_frame = pystack_extractor.handleCFrame(cursor, &frame_iter);
if (found_frame) { if (found_frame) {
frame_iter.getCL()->propagated_cxx_exceptions++;
if (exceptionAtLineCheck()) { if (exceptionAtLineCheck()) {
// TODO: shouldn't fetch this multiple times? // TODO: shouldn't fetch this multiple times?
frame_iter.getCurrentStatement()->cxx_exception_count++; frame_iter.getCurrentStatement()->cxx_exception_count++;
......
...@@ -376,6 +376,8 @@ public: ...@@ -376,6 +376,8 @@ public:
// Please use codeForFunction() to access this: // Please use codeForFunction() to access this:
BoxedCode* code_obj; BoxedCode* code_obj;
int propagated_cxx_exceptions = 0;
// For use by the interpreter/baseline jit: // For use by the interpreter/baseline jit:
int times_interpreted; int times_interpreted;
std::vector<std::unique_ptr<JitCodeBlock>> code_blocks; std::vector<std::unique_ptr<JitCodeBlock>> code_blocks;
......
...@@ -68,19 +68,6 @@ void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* nod ...@@ -68,19 +68,6 @@ void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* nod
raiseSyntaxError(buf, node_at->lineno, node_at->col_offset, file, ""); 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 { void ExcInfo::printExcAndTraceback() const {
PyErr_Display(type, value, traceback); PyErr_Display(type, value, traceback);
} }
...@@ -148,6 +135,35 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) { ...@@ -148,6 +135,35 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) {
return ExcInfo(type, value, 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) { extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
bool reraise = arg2 != NULL && arg2 != None; bool reraise = arg2 != NULL && arg2 != None;
auto exc_info = excInfoForRaise(arg0, arg1, arg2); auto exc_info = excInfoForRaise(arg0, arg1, arg2);
......
...@@ -125,6 +125,7 @@ void force() { ...@@ -125,6 +125,7 @@ void force() {
FORCE(callattrCapi); FORCE(callattrCapi);
FORCE(raise0); FORCE(raise0);
FORCE(raise0_capi);
FORCE(raise3); FORCE(raise3);
FORCE(raise3_capi); FORCE(raise3_capi);
FORCE(PyErr_Fetch); FORCE(PyErr_Fetch);
......
...@@ -34,6 +34,7 @@ class BoxedTuple; ...@@ -34,6 +34,7 @@ class BoxedTuple;
// user-level raise functions that implement python-level semantics // user-level raise functions that implement python-level semantics
ExcInfo excInfoForRaise(Box*, Box*, Box*); ExcInfo excInfoForRaise(Box*, Box*, Box*);
extern "C" void raise0() __attribute__((__noreturn__)); 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(Box*, Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3_capi(Box*, Box*, Box*) noexcept; extern "C" void raise3_capi(Box*, Box*, Box*) noexcept;
void raiseExc(Box* exc_obj) __attribute__((__noreturn__)); 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