Commit daa197c8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Make raise statements in try blocks use capi exceptions

parent b04977a2
...@@ -107,8 +107,15 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) { ...@@ -107,8 +107,15 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) {
r = CXX; // default r = CXX; // default
// print_ast(invoke); if (invoke->stmt->type == AST_TYPE::Raise) {
// printf("\n"); AST_Raise* raise_stmt = ast_cast<AST_Raise>(invoke->stmt);
// Currently can't do a re-raise with a capi exception:
if (raise_stmt->arg0 && !raise_stmt->arg2) {
r = CAPI;
return r;
}
}
AST_expr* expr = NULL; AST_expr* expr = NULL;
if (invoke->stmt->type == AST_TYPE::Assign) { if (invoke->stmt->type == AST_TYPE::Assign) {
...@@ -298,42 +305,6 @@ private: ...@@ -298,42 +305,6 @@ private:
} }
} }
void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, llvm::Value* exc_val,
bool double_check) override {
assert(!double_check); // need to call PyErr_Occurred
llvm::BasicBlock* normal_dest
= llvm::BasicBlock::Create(g.context, curblock->getName(), irstate->getLLVMFunction());
normal_dest->moveAfter(curblock);
llvm::BasicBlock* exc_dest;
bool exc_caught;
if (unw_info.hasHandler()) {
assert(unw_info.capi_exc_dest);
exc_dest = unw_info.capi_exc_dest;
exc_caught = true;
} else {
exc_dest = llvm::BasicBlock::Create(g.context, curblock->getName() + "_exc", irstate->getLLVMFunction());
exc_dest->moveAfter(curblock);
exc_caught = false;
}
assert(returned_val->getType() == exc_val->getType());
llvm::Value* check_val = getBuilder()->CreateICmpEQ(returned_val, exc_val);
llvm::BranchInst* nullcheck = getBuilder()->CreateCondBr(check_val, exc_dest, normal_dest);
setCurrentBasicBlock(exc_dest);
getBuilder()->CreateCall2(g.funcs.capiExcCaughtInJit,
embedRelocatablePtr(unw_info.current_stmt, g.llvm_aststmt_type_ptr),
embedRelocatablePtr(irstate->getSourceInfo(), g.i8_ptr));
if (!exc_caught) {
RELEASE_ASSERT(0, "need to implement this");
}
setCurrentBasicBlock(normal_dest);
}
llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func, llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func,
const std::vector<llvm::Value*>& args, const std::vector<llvm::Value*>& args,
const std::vector<llvm::Value*>& ic_stackmap_args, const UnwindInfo& unw_info, const std::vector<llvm::Value*>& ic_stackmap_args, const UnwindInfo& unw_info,
...@@ -507,6 +478,42 @@ public: ...@@ -507,6 +478,42 @@ public:
return rtn.getInstruction(); return rtn.getInstruction();
} }
void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, llvm::Value* exc_val,
bool double_check = false) override {
assert(!double_check); // need to call PyErr_Occurred
llvm::BasicBlock* normal_dest
= llvm::BasicBlock::Create(g.context, curblock->getName(), irstate->getLLVMFunction());
normal_dest->moveAfter(curblock);
llvm::BasicBlock* exc_dest;
bool exc_caught;
if (unw_info.hasHandler()) {
assert(unw_info.capi_exc_dest);
exc_dest = unw_info.capi_exc_dest;
exc_caught = true;
} else {
exc_dest = llvm::BasicBlock::Create(g.context, curblock->getName() + "_exc", irstate->getLLVMFunction());
exc_dest->moveAfter(curblock);
exc_caught = false;
}
assert(returned_val->getType() == exc_val->getType());
llvm::Value* check_val = getBuilder()->CreateICmpEQ(returned_val, exc_val);
llvm::BranchInst* nullcheck = getBuilder()->CreateCondBr(check_val, exc_dest, normal_dest);
setCurrentBasicBlock(exc_dest);
getBuilder()->CreateCall2(g.funcs.capiExcCaughtInJit,
embedRelocatablePtr(unw_info.current_stmt, g.llvm_aststmt_type_ptr),
embedRelocatablePtr(irstate->getSourceInfo(), g.i8_ptr));
if (!exc_caught) {
RELEASE_ASSERT(0, "need to implement this");
}
setCurrentBasicBlock(normal_dest);
}
Box* getIntConstant(int64_t n) override { return irstate->getSourceInfo()->parent_module->getIntConstant(n); } Box* getIntConstant(int64_t n) override { return irstate->getSourceInfo()->parent_module->getIntConstant(n); }
Box* getFloatConstant(double d) override { return irstate->getSourceInfo()->parent_module->getFloatConstant(d); } Box* getFloatConstant(double d) override { return irstate->getSourceInfo()->parent_module->getFloatConstant(d); }
...@@ -2310,10 +2317,15 @@ private: ...@@ -2310,10 +2317,15 @@ 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;
if (unw_info.capi_exc_dest)
target_exception_style = CAPI;
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);
emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>()); emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>());
emitter.getBuilder()->CreateUnreachable(); emitter.getBuilder()->CreateUnreachable();
...@@ -2333,7 +2345,13 @@ private: ...@@ -2333,7 +2345,13 @@ private:
} }
} }
emitter.createCall(unw_info, g.funcs.raise3, args); if (target_exception_style == CAPI) {
emitter.createCall(unw_info, g.funcs.raise3_capi, args, CAPI);
emitter.checkAndPropagateCapiException(unw_info, getNullPtr(g.llvm_value_type_ptr),
getNullPtr(g.llvm_value_type_ptr));
} else {
emitter.createCall(unw_info, g.funcs.raise3, args, CXX);
}
emitter.getBuilder()->CreateUnreachable(); emitter.getBuilder()->CreateUnreachable();
endBlock(DEAD); endBlock(DEAD);
......
...@@ -273,6 +273,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -273,6 +273,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(raise3); GET(raise3);
GET(raise3_capi);
GET(PyErr_Fetch); GET(PyErr_Fetch);
GET(PyErr_NormalizeException); GET(PyErr_NormalizeException);
GET(capiExcCaughtInJit); GET(capiExcCaughtInJit);
......
...@@ -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; llvm::Value* raise0, *raise3, *raise3_capi;
llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *capiExcCaughtInJit; llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *capiExcCaughtInJit;
llvm::Value* deopt; llvm::Value* deopt;
......
...@@ -120,6 +120,7 @@ void force() { ...@@ -120,6 +120,7 @@ void force() {
FORCE(raise0); FORCE(raise0);
FORCE(raise3); FORCE(raise3);
FORCE(raise3_capi);
FORCE(PyErr_Fetch); FORCE(PyErr_Fetch);
FORCE(PyErr_NormalizeException); FORCE(PyErr_NormalizeException);
FORCE(capiExcCaughtInJit); FORCE(capiExcCaughtInJit);
......
...@@ -35,6 +35,7 @@ class BoxedTuple; ...@@ -35,6 +35,7 @@ class BoxedTuple;
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 raise3(Box*, Box*, Box*) __attribute__((__noreturn__)); 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__)); void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
void _printStacktrace(); void _printStacktrace();
......
...@@ -272,6 +272,21 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) { ...@@ -272,6 +272,21 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
throw exc_info; throw exc_info;
} }
extern "C" void raise3_capi(Box* arg0, Box* arg1, Box* arg2) noexcept {
bool reraise = arg2 != NULL && arg2 != None;
ExcInfo exc_info(NULL, NULL, NULL);
try {
exc_info = excInfoForRaise(arg0, arg1, arg2);
exc_info.reraise = reraise;
} catch (ExcInfo e) {
exc_info = e;
}
assert(!exc_info.reraise); // would get thrown away
PyErr_Restore(exc_info.type, exc_info.value, exc_info.traceback);
}
void raiseExcHelper(BoxedClass* cls, Box* arg) { void raiseExcHelper(BoxedClass* cls, Box* arg) {
Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL); Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL);
raiseExc(exc_obj); raiseExc(exc_obj);
......
...@@ -114,7 +114,7 @@ Box* BoxedTraceback::getLines(Box* b) { ...@@ -114,7 +114,7 @@ Box* BoxedTraceback::getLines(Box* b) {
} }
void BoxedTraceback::here(LineInfo lineInfo, Box** tb) { void BoxedTraceback::here(LineInfo lineInfo, Box** tb) {
*tb = new BoxedTraceback(lineInfo, *tb); *tb = new BoxedTraceback(std::move(lineInfo), *tb);
} }
void setupTraceback() { void setupTraceback() {
......
...@@ -31,7 +31,7 @@ public: ...@@ -31,7 +31,7 @@ public:
LineInfo line; LineInfo line;
Box* py_lines; Box* py_lines;
BoxedTraceback(LineInfo line, Box* tb_next) : tb_next(tb_next), line(line), py_lines(NULL) {} BoxedTraceback(LineInfo line, Box* tb_next) : tb_next(tb_next), line(std::move(line)), py_lines(NULL) {}
DEFAULT_CLASS(traceback_cls); DEFAULT_CLASS(traceback_cls);
......
# skip-if: True
# expected: fail # expected: fail
# - CPython calls subclasscheck twice, while we call it once. # - CPython calls subclasscheck twice, while we call it once.
# Looks like this is because CPython calls PyErr_NormalizeException # Looks like this is because CPython calls PyErr_NormalizeException
......
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