Commit 20d98b25 authored by Chris Toshok's avatar Chris Toshok

create an UnwindSession type (gc allocated) per thread to contain all the python unwinding state.

parent 8e88774f
...@@ -632,19 +632,8 @@ Value ASTInterpreter::visit_invoke(AST_Invoke* node) { ...@@ -632,19 +632,8 @@ Value ASTInterpreter::visit_invoke(AST_Invoke* node) {
next_block = node->normal_dest; next_block = node->normal_dest;
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (threading::ThreadStateInternal::getUnwindState() == UNWIND_STATE_NORMAL) { auto source = getCF()->clfunc->source.get();
// when generating the traceback incrementally we only exceptionCaughtInInterpreter(LineInfo(node->lineno, node->col_offset, source->fn, source->getName()), &e);
// include an interpreter frame if we unwind through
// ASTInterpreter::execute_inner. this will keep a toplevel
// invoke from showing up, since we catch the exception
// here.
auto source = getCF()->clfunc->source.get();
BoxedTraceback::Here(LineInfo(node->lineno, node->col_offset, source->fn, source->getName()),
reinterpret_cast<BoxedTraceback**>(&e.traceback));
}
threading::ThreadStateInternal::setUnwindState(UNWIND_STATE_NORMAL);
next_block = node->exc_dest; next_block = node->exc_dest;
last_exception = e; last_exception = e;
......
...@@ -110,8 +110,8 @@ static llvm::Value* getClosureElementGep(IREmitter& emitter, llvm::Value* closur ...@@ -110,8 +110,8 @@ static llvm::Value* getClosureElementGep(IREmitter& emitter, llvm::Value* closur
static llvm::Value* getBoxedLocalsGep(llvm::IRBuilder<true>& builder, llvm::Value* v) { static llvm::Value* getBoxedLocalsGep(llvm::IRBuilder<true>& builder, llvm::Value* v) {
static_assert(offsetof(FrameInfo, exc) == 0, ""); static_assert(offsetof(FrameInfo, exc) == 0, "");
static_assert(sizeof(ExcInfo) == 24, ""); static_assert(sizeof(ExcInfo) == 32, "");
static_assert(offsetof(FrameInfo, boxedLocals) == 24, ""); static_assert(offsetof(FrameInfo, boxedLocals) == 32, "");
return builder.CreateConstInBoundsGEP2_32(v, 0, 1); return builder.CreateConstInBoundsGEP2_32(v, 0, 1);
} }
...@@ -122,9 +122,9 @@ static llvm::Value* getExcinfoGep(llvm::IRBuilder<true>& builder, llvm::Value* v ...@@ -122,9 +122,9 @@ static llvm::Value* getExcinfoGep(llvm::IRBuilder<true>& builder, llvm::Value* v
static llvm::Value* getFrameObjGep(llvm::IRBuilder<true>& builder, llvm::Value* v) { static llvm::Value* getFrameObjGep(llvm::IRBuilder<true>& builder, llvm::Value* v) {
static_assert(offsetof(FrameInfo, exc) == 0, ""); static_assert(offsetof(FrameInfo, exc) == 0, "");
static_assert(sizeof(ExcInfo) == 24, ""); static_assert(sizeof(ExcInfo) == 32, "");
static_assert(sizeof(Box*) == 8, ""); static_assert(sizeof(Box*) == 8, "");
static_assert(offsetof(FrameInfo, frame_obj) == 32, ""); static_assert(offsetof(FrameInfo, frame_obj) == 40, "");
return builder.CreateConstInBoundsGEP2_32(v, 0, 2); return builder.CreateConstInBoundsGEP2_32(v, 0, 2);
// TODO: this could be made more resilient by doing something like // TODO: this could be made more resilient by doing something like
// gep->accumulateConstantOffset(g.tm->getDataLayout(), ap_offset) // gep->accumulateConstantOffset(g.tm->getDataLayout(), ap_offset)
......
...@@ -58,6 +58,10 @@ struct uw_table_entry { ...@@ -58,6 +58,10 @@ struct uw_table_entry {
namespace pyston { namespace pyston {
namespace {
static BoxedClass* unwind_session_cls;
}
// Parse an .eh_frame section, and construct a "binary search table" such as you would find in a .eh_frame_hdr section. // Parse an .eh_frame section, and construct a "binary search table" such as you would find in a .eh_frame_hdr section.
// Currently only supports .eh_frame sections with exactly one fde. // Currently only supports .eh_frame sections with exactly one fde.
// See http://www.airs.com/blog/archives/460 for some useful info. // See http://www.airs.com/blog/archives/460 for some useful info.
...@@ -441,8 +445,7 @@ static inline unw_word_t get_cursor_bp(unw_cursor_t* cursor) { ...@@ -441,8 +445,7 @@ static inline unw_word_t get_cursor_bp(unw_cursor_t* cursor) {
return get_cursor_reg(cursor, UNW_TDEP_BP); return get_cursor_reg(cursor, UNW_TDEP_BP);
} }
template <typename FrameFunc> bool unwindProcessFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, PythonFrameIteratorImpl* info) {
bool unwindProcessFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, FrameFunc func) {
CompiledFunction* cf = getCFForAddress(ip); CompiledFunction* cf = getCFForAddress(ip);
bool jitted = cf != NULL; bool jitted = cf != NULL;
if (!cf) { if (!cf) {
...@@ -455,7 +458,7 @@ bool unwindProcessFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, Fram ...@@ -455,7 +458,7 @@ bool unwindProcessFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, Fram
if (!cf) if (!cf)
return false; return false;
PythonFrameIteratorImpl info(jitted ? PythonFrameId::COMPILED : PythonFrameId::INTERPRETED, ip, bp, cf); *info = PythonFrameIteratorImpl(jitted ? PythonFrameId::COMPILED : PythonFrameId::INTERPRETED, ip, bp, cf);
if (jitted) { if (jitted) {
// Try getting all the callee-save registers, and save the ones we were able to get. // Try getting all the callee-save registers, and save the ones we were able to get.
// Some of them may be inaccessible, I think because they weren't defined by that // Some of them may be inaccessible, I think because they weren't defined by that
...@@ -467,22 +470,56 @@ bool unwindProcessFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, Fram ...@@ -467,22 +470,56 @@ bool unwindProcessFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, Fram
int code = unw_get_reg(cursor, i, &r); int code = unw_get_reg(cursor, i, &r);
ASSERT(code == 0 || code == -UNW_EBADREG, "%d %d", code, i); ASSERT(code == 0 || code == -UNW_EBADREG, "%d %d", code, i);
if (code == 0) { if (code == 0) {
info.regs[i] = r; info->regs[i] = r;
info.regs_valid |= (1 << i); info->regs_valid |= (1 << i);
} }
} }
} }
return func(&info); return true;
} }
class UnwindSession : public Box {
ExcInfo exc_info;
bool skip;
public:
DEFAULT_CLASS_SIMPLE(unwind_session_cls);
UnwindSession() : exc_info(NULL, NULL, NULL), skip(false) {}
ExcInfo* getExcInfoStorage() { return &exc_info; }
bool shouldSkipFrame() const { return skip; }
void setShouldSkipNextFrame(bool skip) { this->skip = skip; }
void clear() {
exc_info = ExcInfo(NULL, NULL, NULL);
skip = false;
}
void addTraceback(const LineInfo& line_info) {
if (exc_info.reraise) {
exc_info.reraise = false;
return;
}
BoxedTraceback::Here(line_info, reinterpret_cast<BoxedTraceback**>(&exc_info.traceback));
}
static void gcHandler(GCVisitor* v, Box* _o) {
// assert(_o->cls == unwind_session_cls)
UnwindSession* o = static_cast<UnwindSession*>(_o);
v->visitIf(o->exc_info.type);
v->visitIf(o->exc_info.value);
v->visitIf(o->exc_info.traceback);
}
};
// While I'm not a huge fan of the callback-passing style, libunwind cursors are only valid for // While I'm not a huge fan of the callback-passing style, libunwind cursors are only valid for
// the stack frame that they were created in, so we need to use this approach (as opposed to // the stack frame that they were created in, so we need to use this approach (as opposed to
// C++11 range loops, for example). // C++11 range loops, for example).
// Return true from the handler to stop iteration at that frame. // Return true from the handler to stop iteration at that frame.
template <typename Func> void unwindPythonStack(Func func) { template <typename Func> void unwindPythonStack(Func func) {
threading::ThreadStateInternal::setUnwindState( UnwindSession* unwind_state = (UnwindSession*)beginUnwind();
UNWIND_STATE_NORMAL); // ensure we won't be skipping any python frames at the start
unw_context_t ctx; unw_context_t ctx;
unw_cursor_t cursor; unw_cursor_t cursor;
unw_getcontext(&ctx); unw_getcontext(&ctx);
...@@ -498,20 +535,20 @@ template <typename Func> void unwindPythonStack(Func func) { ...@@ -498,20 +535,20 @@ template <typename Func> void unwindPythonStack(Func func) {
unw_word_t ip = get_cursor_ip(&cursor); unw_word_t ip = get_cursor_ip(&cursor);
unw_word_t bp = get_cursor_bp(&cursor); unw_word_t bp = get_cursor_bp(&cursor);
bool stop_unwinding = unwindProcessFrame(ip, bp, &cursor, [&](PythonFrameIteratorImpl* frame_iter) { bool stop_unwinding = false;
bool rtn = false;
if (threading::ThreadStateInternal::getUnwindState() == UNWIND_STATE_NORMAL)
rtn = func(frame_iter);
threading::ThreadStateInternal::setUnwindState( PythonFrameIteratorImpl frame_iter;
(bool)frame_iter->cf->entry_descriptor ? UNWIND_STATE_SKIPNEXT : UNWIND_STATE_NORMAL); if (unwindProcessFrame(ip, bp, &cursor, &frame_iter)) {
return rtn; if (!unwind_state->shouldSkipFrame())
}); stop_unwinding = func(&frame_iter);
if (stop_unwinding) { // frame_iter->cf->entry_descriptor will be non-null for OSR frames.
break; unwind_state->setShouldSkipNextFrame((bool)frame_iter.cf->entry_descriptor);
} }
if (stop_unwinding)
break;
if (inGeneratorEntry(ip)) { if (inGeneratorEntry(ip)) {
// for generators continue unwinding in the context in which the generator got called // for generators continue unwinding in the context in which the generator got called
Context* remote_ctx = getReturnContextForGeneratorFrame((void*)bp); Context* remote_ctx = getReturnContextForGeneratorFrame((void*)bp);
...@@ -530,6 +567,8 @@ template <typename Func> void unwindPythonStack(Func func) { ...@@ -530,6 +567,8 @@ template <typename Func> void unwindPythonStack(Func func) {
// keep unwinding // keep unwinding
} }
endUnwind(unwind_state);
} }
static std::unique_ptr<PythonFrameIteratorImpl> getTopPythonFrame() { static std::unique_ptr<PythonFrameIteratorImpl> getTopPythonFrame() {
...@@ -552,23 +591,58 @@ static const LineInfo lineInfoForFrame(PythonFrameIteratorImpl* frame_it) { ...@@ -552,23 +591,58 @@ static const LineInfo lineInfoForFrame(PythonFrameIteratorImpl* frame_it) {
return LineInfo(current_stmt->lineno, current_stmt->col_offset, source->fn, source->getName()); return LineInfo(current_stmt->lineno, current_stmt->col_offset, source->fn, source->getName());
} }
void maybeTracebackHere(void* unw_cursor) {
void exceptionCaughtInInterpreter(LineInfo line_info, ExcInfo* exc_info) {
if (exc_info->reraise) {
exc_info->reraise = false;
return;
}
BoxedTraceback::Here(line_info, reinterpret_cast<BoxedTraceback**>(&exc_info->traceback));
}
static __thread UnwindSession* cur_unwind;
void* beginUnwind() {
if (!cur_unwind) {
cur_unwind = new UnwindSession();
pyston::gc::registerPermanentRoot(cur_unwind);
}
// if we can figure out a way to make endUnwind in cxx_uwind.cpp work, we can remove this.
cur_unwind->clear();
return cur_unwind;
}
void* getUnwind() {
RELEASE_ASSERT(cur_unwind, "");
return cur_unwind;
}
void endUnwind(void* unwind) {
RELEASE_ASSERT(unwind && unwind == cur_unwind, "");
cur_unwind->clear();
}
void* getExceptionFerry(void* unwind) {
RELEASE_ASSERT(unwind && unwind == cur_unwind, "");
UnwindSession* state = static_cast<UnwindSession*>(unwind);
return state->getExcInfoStorage();
}
void maybeTracebackHere(void* unw_cursor, void* unwind_token) {
unw_cursor_t* cursor = (unw_cursor_t*)unw_cursor; unw_cursor_t* cursor = (unw_cursor_t*)unw_cursor;
UnwindSession* state = (UnwindSession*)unwind_token;
unw_word_t ip = get_cursor_ip(cursor); unw_word_t ip = get_cursor_ip(cursor);
unw_word_t bp = get_cursor_bp(cursor); unw_word_t bp = get_cursor_bp(cursor);
BoxedTraceback** tb_loc PythonFrameIteratorImpl frame_iter;
= reinterpret_cast<BoxedTraceback**>(&threading::ThreadStateInternal::getExceptionFerry()->traceback); if (unwindProcessFrame(ip, bp, cursor, &frame_iter)) {
if (!state->shouldSkipFrame()) {
unwindProcessFrame(ip, bp, cursor, [&](PythonFrameIteratorImpl* frame_iter) { state->addTraceback(lineInfoForFrame(&frame_iter));
if (threading::ThreadStateInternal::getUnwindState() == UNWIND_STATE_NORMAL) }
BoxedTraceback::Here(lineInfoForFrame(frame_iter), tb_loc);
threading::ThreadStateInternal::setUnwindState((bool)frame_iter->cf->entry_descriptor ? UNWIND_STATE_SKIPNEXT // frame_iter->cf->entry_descriptor will be non-null for OSR frames.
: UNWIND_STATE_NORMAL); state->setShouldSkipNextFrame((bool)frame_iter.cf->entry_descriptor);
return false; }
});
} }
// To produce a traceback, we: // To produce a traceback, we:
...@@ -1053,4 +1127,10 @@ void logByCurrentPythonLine(const std::string& stat_name) { ...@@ -1053,4 +1127,10 @@ void logByCurrentPythonLine(const std::string& stat_name) {
llvm::JITEventListener* makeTracebacksListener() { llvm::JITEventListener* makeTracebacksListener() {
return new TracebacksEventListener(); return new TracebacksEventListener();
} }
void setupUnwinding() {
unwind_session_cls = BoxedHeapClass::create(type_cls, object_cls, UnwindSession::gcHandler, 0, 0,
sizeof(UnwindSession), false, "unwind_session");
unwind_session_cls->freeze();
}
} }
...@@ -29,6 +29,7 @@ struct FrameInfo; ...@@ -29,6 +29,7 @@ struct FrameInfo;
void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size); void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size);
void setupUnwinding();
BoxedModule* getCurrentModule(); BoxedModule* getCurrentModule();
Box* getGlobals(); // returns either the module or a globals dict Box* getGlobals(); // returns either the module or a globals dict
Box* getGlobalsDict(); // always returns a dict-like object Box* getGlobalsDict(); // always returns a dict-like object
...@@ -36,7 +37,13 @@ CompiledFunction* getCFForAddress(uint64_t addr); ...@@ -36,7 +37,13 @@ CompiledFunction* getCFForAddress(uint64_t addr);
BoxedTraceback* getTraceback(); BoxedTraceback* getTraceback();
void maybeTracebackHere(void* unw_cursor); void* beginUnwind();
void* getUnwind();
void endUnwind(void* unwind_token);
void* getExceptionFerry(void* unwind_token);
void exceptionCaughtInInterpreter(LineInfo line_info, ExcInfo* exc_info);
void maybeTracebackHere(void* unw_cursor, void* unwind_token);
struct ExecutionPoint { struct ExecutionPoint {
CompiledFunction* cf; CompiledFunction* cf;
......
...@@ -52,12 +52,7 @@ PthreadFastMutex threading_lock; ...@@ -52,12 +52,7 @@ PthreadFastMutex threading_lock;
int num_starting_threads(0); int num_starting_threads(0);
ThreadStateInternal::ThreadStateInternal(void* stack_start, pthread_t pthread_id, PyThreadState* public_thread_state) ThreadStateInternal::ThreadStateInternal(void* stack_start, pthread_t pthread_id, PyThreadState* public_thread_state)
: saved(false), : saved(false), stack_start(stack_start), pthread_id(pthread_id), public_thread_state(public_thread_state) {
stack_start(stack_start),
pthread_id(pthread_id),
unwind_state(UNWIND_STATE_NORMAL),
exc_info(NULL, NULL, NULL),
public_thread_state(public_thread_state) {
} }
void ThreadStateInternal::accept(gc::GCVisitor* v) { void ThreadStateInternal::accept(gc::GCVisitor* v) {
...@@ -67,10 +62,6 @@ void ThreadStateInternal::accept(gc::GCVisitor* v) { ...@@ -67,10 +62,6 @@ void ThreadStateInternal::accept(gc::GCVisitor* v) {
v->visitIf(pub_state->curexc_traceback); v->visitIf(pub_state->curexc_traceback);
v->visitIf(pub_state->dict); v->visitIf(pub_state->dict);
v->visitIf(exc_info.type);
v->visitIf(exc_info.value);
v->visitIf(exc_info.traceback);
for (auto& stack_info : previous_stacks) { for (auto& stack_info : previous_stacks) {
v->visit(stack_info.next_generator); v->visit(stack_info.next_generator);
#if STACK_GROWS_DOWN #if STACK_GROWS_DOWN
......
...@@ -32,13 +32,6 @@ namespace gc { ...@@ -32,13 +32,6 @@ namespace gc {
class GCVisitor; class GCVisitor;
} }
// somewhat similar to CPython's WHY_* enum
// UNWIND_STATE_NORMAL : == WHY_EXCEPTION. we call it "NORMAL" since we often unwind due to things other than
// exceptions (getGlobals, getLocals, etc)
// UNWIND_STATE_SKIPNEXT: skip this frame (do not include it in tracebacks). this happens when re-raising an exception
// and also when dealing with osr replacements (we skip the frame we OSR).
enum UnwindState { UNWIND_STATE_NORMAL = 0, UNWIND_STATE_SKIPNEXT };
namespace threading { namespace threading {
class ThreadStateInternal { class ThreadStateInternal {
...@@ -82,9 +75,6 @@ public: ...@@ -82,9 +75,6 @@ public:
std::vector<StackInfo> previous_stacks; std::vector<StackInfo> previous_stacks;
pthread_t pthread_id; pthread_t pthread_id;
UnwindState unwind_state;
ExcInfo exc_info;
PyThreadState* public_thread_state; PyThreadState* public_thread_state;
ThreadStateInternal(void* stack_start, pthread_t pthread_id, PyThreadState* public_thread_state); ThreadStateInternal(void* stack_start, pthread_t pthread_id, PyThreadState* public_thread_state);
...@@ -117,21 +107,6 @@ public: ...@@ -117,21 +107,6 @@ public:
assert(ThreadStateInternal::current); assert(ThreadStateInternal::current);
current->_popGenerator(); current->_popGenerator();
} }
inline static void setUnwindState(UnwindState state) {
assert(ThreadStateInternal::current);
current->unwind_state = state;
}
inline static UnwindState getUnwindState() {
assert(ThreadStateInternal::current);
return current->unwind_state;
}
static ExcInfo* getExceptionFerry() {
assert(ThreadStateInternal::current);
return &current->exc_info;
}
}; };
// Whether or not a second thread was ever started: // Whether or not a second thread was ever started:
......
...@@ -679,11 +679,12 @@ public: ...@@ -679,11 +679,12 @@ public:
struct ExcInfo { struct ExcInfo {
Box* type, *value, *traceback; Box* type, *value, *traceback;
bool reraise;
#ifndef NDEBUG #ifndef NDEBUG
ExcInfo(Box* type, Box* value, Box* traceback); ExcInfo(Box* type, Box* value, Box* traceback);
#else #else
ExcInfo(Box* type, Box* value, Box* traceback) : type(type), value(value), traceback(traceback) {} ExcInfo(Box* type, Box* value, Box* traceback) : type(type), value(value), traceback(traceback), reraise(false) {}
#endif #endif
bool matches(BoxedClass* cls) const; bool matches(BoxedClass* cls) const;
void printExcAndTraceback() const; void printExcAndTraceback() const;
......
...@@ -493,12 +493,14 @@ static inline void unwind_loop(ExcInfo* exc_data) { ...@@ -493,12 +493,14 @@ static inline void unwind_loop(ExcInfo* exc_data) {
unw_getcontext(&uc); unw_getcontext(&uc);
unw_init_local(&cursor, &uc); unw_init_local(&cursor, &uc);
void* unwind_token = getUnwind();
while (unw_step(&cursor) > 0) { while (unw_step(&cursor) > 0) {
unw_proc_info_t pip; unw_proc_info_t pip;
{
// NB. unw_get_proc_info is slow; a significant chunk of all time spent unwinding is spent here. // NB. unw_get_proc_info is slow; a significant chunk of all time spent unwinding is spent here.
check(unw_get_proc_info(&cursor, &pip)); check(unw_get_proc_info(&cursor, &pip));
}
assert((pip.lsda == 0) == (pip.handler == 0)); assert((pip.lsda == 0) == (pip.handler == 0));
assert(pip.flags == 0); assert(pip.flags == 0);
...@@ -506,7 +508,7 @@ static inline void unwind_loop(ExcInfo* exc_data) { ...@@ -506,7 +508,7 @@ static inline void unwind_loop(ExcInfo* exc_data) {
print_frame(&cursor, &pip); print_frame(&cursor, &pip);
} }
maybeTracebackHere(&cursor); maybeTracebackHere(&cursor, unwind_token);
// Skip frames without handlers // Skip frames without handlers
if (pip.handler == 0) { if (pip.handler == 0) {
...@@ -554,6 +556,10 @@ static inline void unwind_loop(ExcInfo* exc_data) { ...@@ -554,6 +556,10 @@ static inline void unwind_loop(ExcInfo* exc_data) {
} }
int64_t switch_value = determine_action(&info, &entry); int64_t switch_value = determine_action(&info, &entry);
if (switch_value != CLEANUP_ACTION) {
// printf ("cleanup action == %ld, should end unwind session\n", switch_value);
// endUnwind(unwind_token);
}
resume(&cursor, entry.landing_pad, switch_value, exc_data); resume(&cursor, entry.landing_pad, switch_value, exc_data);
} }
...@@ -631,7 +637,7 @@ extern "C" void* __cxa_allocate_exception(size_t size) noexcept { ...@@ -631,7 +637,7 @@ extern "C" void* __cxa_allocate_exception(size_t size) noexcept {
// our exception info in curexc_*, and then unset these in __cxa_end_catch, then we'll wipe our exception info // our exception info in curexc_*, and then unset these in __cxa_end_catch, then we'll wipe our exception info
// during unwinding! // during unwinding!
return pyston::threading::ThreadStateInternal::getExceptionFerry(); return pyston::getExceptionFerry(pyston::getUnwind());
} }
// Takes the value that resume() sent us in RAX, and returns a pointer to the exception object actually thrown. In our // Takes the value that resume() sent us in RAX, and returns a pointer to the exception object actually thrown. In our
......
...@@ -72,11 +72,12 @@ void raiseRaw(const ExcInfo& e) { ...@@ -72,11 +72,12 @@ void raiseRaw(const ExcInfo& e) {
#endif #endif
#endif #endif
// printf ("beginning unwind\n");
beginUnwind();
throw e; throw e;
} }
void raiseExc(Box* exc_obj) { void raiseExc(Box* exc_obj) {
threading::ThreadStateInternal::setUnwindState(UNWIND_STATE_NORMAL);
raiseRaw(ExcInfo(exc_obj->cls, exc_obj, new BoxedTraceback())); raiseRaw(ExcInfo(exc_obj->cls, exc_obj, new BoxedTraceback()));
} }
...@@ -205,13 +206,13 @@ extern "C" void raise0() { ...@@ -205,13 +206,13 @@ extern "C" void raise0() {
if (exc_info->type == None) if (exc_info->type == None)
raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not NoneType"); raiseExcHelper(TypeError, "exceptions must be old-style classes or derived from BaseException, not NoneType");
exc_info->reraise = true;
threading::ThreadStateInternal::setUnwindState(UNWIND_STATE_SKIPNEXT);
raiseRaw(*exc_info); raiseRaw(*exc_info);
} }
#ifndef NDEBUG #ifndef NDEBUG
ExcInfo::ExcInfo(Box* type, Box* value, Box* traceback) : type(type), value(value), traceback(traceback) { ExcInfo::ExcInfo(Box* type, Box* value, Box* traceback)
: type(type), value(value), traceback(traceback), reraise(false) {
} }
#endif #endif
...@@ -286,7 +287,7 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) { ...@@ -286,7 +287,7 @@ 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);
threading::ThreadStateInternal::setUnwindState(reraise ? UNWIND_STATE_SKIPNEXT : UNWIND_STATE_NORMAL); exc_info.reraise = reraise;
raiseRaw(exc_info); raiseRaw(exc_info);
} }
......
...@@ -2703,6 +2703,7 @@ void setupRuntime() { ...@@ -2703,6 +2703,7 @@ void setupRuntime() {
closure_cls->freeze(); closure_cls->freeze();
setupUnwinding();
setupInterpreter(); setupInterpreter();
setupCAPI(); setupCAPI();
......
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