Commit 9067a589 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #564 from toshok/incremental-traceback

Incremental traceback
parents cf145fb8 d034a63e
...@@ -69,13 +69,10 @@ private: ...@@ -69,13 +69,10 @@ private:
ASTInterpreter* interpreter; ASTInterpreter* interpreter;
public: public:
RegisterHelper(ASTInterpreter* interpreter, void* frame_addr); RegisterHelper();
~RegisterHelper(); ~RegisterHelper();
void doRegister(void* frame_addr, ASTInterpreter* interpreter);
static void deregister(void* frame_addr) { static void deregister(void* frame_addr);
assert(s_interpreterMap.count(frame_addr));
s_interpreterMap.erase(frame_addr);
}
}; };
union Value { union Value {
...@@ -102,11 +99,13 @@ public: ...@@ -102,11 +99,13 @@ public:
void initArguments(int nargs, BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3, void initArguments(int nargs, BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3,
Box** args); Box** args);
static Value execute(ASTInterpreter& interpreter, CFGBlock* start_block = NULL, AST_stmt* start_at = NULL);
// This must not be inlined, because we rely on being able to detect when we're inside of it (by checking whether // This must not be inlined, because we rely on being able to detect when we're inside of it (by checking whether
// %rip is inside its instruction range) during a stack-trace in order to produce tracebacks inside interpreted // %rip is inside its instruction range) during a stack-trace in order to produce tracebacks inside interpreted
// code. // code.
__attribute__((__no_inline__)) static Value __attribute__((__no_inline__)) static Value
execute(ASTInterpreter& interpreter, CFGBlock* start_block = NULL, AST_stmt* start_at = NULL); executeInner(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at, RegisterHelper* reg);
private: private:
Box* createFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body); Box* createFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body);
...@@ -318,22 +317,35 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener ...@@ -318,22 +317,35 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener
} }
} }
RegisterHelper::RegisterHelper(ASTInterpreter* interpreter, void* frame_addr) RegisterHelper::RegisterHelper() : frame_addr(NULL), interpreter(NULL) {
: frame_addr(frame_addr), interpreter(interpreter) {
interpreter->frame_addr = frame_addr;
s_interpreterMap[frame_addr] = interpreter;
} }
RegisterHelper::~RegisterHelper() { RegisterHelper::~RegisterHelper() {
assert(interpreter);
assert(interpreter->frame_addr == frame_addr);
interpreter->frame_addr = nullptr; interpreter->frame_addr = nullptr;
deregister(frame_addr); deregister(frame_addr);
} }
Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at) { void RegisterHelper::doRegister(void* frame_addr, ASTInterpreter* interpreter) {
STAT_TIMER(t0, "us_timer_astinterpreter_execute"); assert(!this->interpreter);
assert(!this->frame_addr);
this->frame_addr = frame_addr;
this->interpreter = interpreter;
interpreter->frame_addr = frame_addr;
s_interpreterMap[frame_addr] = interpreter;
}
void RegisterHelper::deregister(void* frame_addr) {
assert(frame_addr);
assert(s_interpreterMap.count(frame_addr));
s_interpreterMap.erase(frame_addr);
}
Value ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at,
RegisterHelper* reg) {
void* frame_addr = __builtin_frame_address(0); void* frame_addr = __builtin_frame_address(0);
RegisterHelper frame_registerer(&interpreter, frame_addr); reg->doRegister(frame_addr, &interpreter);
Value v; Value v;
...@@ -373,6 +385,14 @@ Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block ...@@ -373,6 +385,14 @@ Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block
return v; return v;
} }
Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at) {
STAT_TIMER(t0, "us_timer_astinterpreter_execute");
RegisterHelper frame_registerer;
return executeInner(interpreter, start_block, start_at, &frame_registerer);
}
Value ASTInterpreter::doBinOp(Box* left, Box* right, int op, BinExpType exp_type) { Value ASTInterpreter::doBinOp(Box* left, Box* right, int op, BinExpType exp_type) {
switch (exp_type) { switch (exp_type) {
case BinExpType::AugBinOp: case BinExpType::AugBinOp:
...@@ -610,6 +630,10 @@ Value ASTInterpreter::visit_invoke(AST_Invoke* node) { ...@@ -610,6 +630,10 @@ Value ASTInterpreter::visit_invoke(AST_Invoke* node) {
v = visit_stmt(node->stmt); v = visit_stmt(node->stmt);
next_block = node->normal_dest; next_block = node->normal_dest;
} catch (ExcInfo e) { } catch (ExcInfo e) {
auto source = getCF()->clfunc->source.get();
exceptionCaughtInInterpreter(LineInfo(node->lineno, node->col_offset, source->fn, source->getName()), &e);
next_block = node->exc_dest; next_block = node->exc_dest;
last_exception = e; last_exception = e;
} }
...@@ -1269,7 +1293,7 @@ Value ASTInterpreter::visit_attribute(AST_Attribute* node) { ...@@ -1269,7 +1293,7 @@ Value ASTInterpreter::visit_attribute(AST_Attribute* node) {
} }
} }
const void* interpreter_instr_addr = (void*)&ASTInterpreter::execute; const void* interpreter_instr_addr = (void*)&ASTInterpreter::executeInner;
Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1, Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1,
Box* arg2, Box* arg3, Box** args) { Box* arg2, Box* arg3, Box** args) {
......
...@@ -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)
......
This diff is collapsed.
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#include "codegen/codegen.h" #include "codegen/codegen.h"
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#undef UNW_LOCAL_ONLY
namespace pyston { namespace pyston {
class Box; class Box;
...@@ -29,6 +33,7 @@ struct FrameInfo; ...@@ -29,6 +33,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,6 +41,16 @@ CompiledFunction* getCFForAddress(uint64_t addr); ...@@ -36,6 +41,16 @@ CompiledFunction* getCFForAddress(uint64_t addr);
BoxedTraceback* getTraceback(); BoxedTraceback* getTraceback();
class PythonUnwindSession;
PythonUnwindSession* beginPythonUnwindSession();
PythonUnwindSession* getActivePythonUnwindSession();
void throwingException(PythonUnwindSession* unwind_session);
void endPythonUnwindSession(PythonUnwindSession* unwind_session);
void* getPythonUnwindSessionExceptionStorage(PythonUnwindSession* unwind_session);
void unwindingThroughFrame(PythonUnwindSession* unwind_session, unw_cursor_t* cursor);
void exceptionCaughtInInterpreter(LineInfo line_info, ExcInfo* exc_info);
struct ExecutionPoint { struct ExecutionPoint {
CompiledFunction* cf; CompiledFunction* cf;
AST_stmt* current_stmt; AST_stmt* current_stmt;
......
...@@ -88,6 +88,10 @@ public: ...@@ -88,6 +88,10 @@ public:
GCVisitor(TraceStack* stack) : stack(stack) {} GCVisitor(TraceStack* stack) : stack(stack) {}
// These all work on *user* pointers, ie pointers to the user_data section of GCAllocations // These all work on *user* pointers, ie pointers to the user_data section of GCAllocations
void visitIf(void* p) {
if (p)
visit(p);
}
void visit(void* p); void visit(void* p);
void visitRange(void* const* start, void* const* end); void visitRange(void* const* start, void* const* end);
void visitPotential(void* p); void visitPotential(void* p);
...@@ -666,7 +670,7 @@ void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* nod ...@@ -666,7 +670,7 @@ void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* nod
struct LineInfo { struct LineInfo {
public: public:
const int line, column; int line, column;
std::string file, func; std::string file, func;
LineInfo(int line, int column, llvm::StringRef file, llvm::StringRef func) LineInfo(int line, int column, llvm::StringRef file, llvm::StringRef func)
...@@ -675,11 +679,12 @@ public: ...@@ -675,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;
......
...@@ -926,7 +926,7 @@ void checkAndThrowCAPIException() { ...@@ -926,7 +926,7 @@ void checkAndThrowCAPIException() {
RELEASE_ASSERT(value->cls == type, "unsupported"); RELEASE_ASSERT(value->cls == type, "unsupported");
if (tb != None) if (tb != None)
raiseRaw(ExcInfo(value->cls, value, tb)); throw ExcInfo(value->cls, value, tb);
raiseExc(value); raiseExc(value);
} }
} }
......
...@@ -162,7 +162,7 @@ static Box* classobjGetattribute(Box* _cls, Box* _attr) { ...@@ -162,7 +162,7 @@ static Box* classobjGetattribute(Box* _cls, Box* _attr) {
} }
} }
Box* r = classLookup(cls, std::string(attr->s())); Box* r = classLookup(cls, attr->s());
if (!r) if (!r)
raiseExcHelper(AttributeError, "class %s has no attribute '%s'", cls->name->data(), attr->data()); raiseExcHelper(AttributeError, "class %s has no attribute '%s'", cls->name->data(), attr->data());
......
This diff is collapsed.
...@@ -155,7 +155,7 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) { ...@@ -155,7 +155,7 @@ static void generatorSendInternal(BoxedGenerator* self, Box* v) {
freeGeneratorStack(self); freeGeneratorStack(self);
// don't raise StopIteration exceptions because those are handled specially. // don't raise StopIteration exceptions because those are handled specially.
if (!self->exception.matches(StopIteration)) if (!self->exception.matches(StopIteration))
raiseRaw(self->exception); throw self->exception;
return; return;
} }
...@@ -193,7 +193,7 @@ Box* generatorSend(Box* s, Box* v) { ...@@ -193,7 +193,7 @@ Box* generatorSend(Box* s, Box* v) {
self->exception = ExcInfo(nullptr, nullptr, nullptr); self->exception = ExcInfo(nullptr, nullptr, nullptr);
if (old_exc.type == NULL) if (old_exc.type == NULL)
raiseExcHelper(StopIteration, (const char*)nullptr); raiseExcHelper(StopIteration, (const char*)nullptr);
raiseRaw(old_exc); throw old_exc;
} }
return self->returnValue; return self->returnValue;
...@@ -272,7 +272,7 @@ extern "C" Box* yield(BoxedGenerator* obj, Box* value) { ...@@ -272,7 +272,7 @@ extern "C" Box* yield(BoxedGenerator* obj, Box* value) {
if (self->exception.type) { if (self->exception.type) {
ExcInfo e = self->exception; ExcInfo e = self->exception;
self->exception = ExcInfo(NULL, NULL, NULL); self->exception = ExcInfo(NULL, NULL, NULL);
raiseRaw(e); throw e;
} }
return self->returnValue; return self->returnValue;
} }
......
...@@ -49,7 +49,7 @@ Box* createAndRunModule(const std::string& name, const std::string& fn) { ...@@ -49,7 +49,7 @@ Box* createAndRunModule(const std::string& name, const std::string& fn) {
compileAndRunModule(ast, module); compileAndRunModule(ast, module);
} catch (ExcInfo e) { } catch (ExcInfo e) {
removeModule(name); removeModule(name);
raiseRaw(e); throw e;
} }
Box* r = getSysModulesDict()->getOrNull(boxString(name)); Box* r = getSysModulesDict()->getOrNull(boxString(name));
...@@ -74,7 +74,7 @@ static Box* createAndRunModule(const std::string& name, const std::string& fn, c ...@@ -74,7 +74,7 @@ static Box* createAndRunModule(const std::string& name, const std::string& fn, c
compileAndRunModule(ast, module); compileAndRunModule(ast, module);
} catch (ExcInfo e) { } catch (ExcInfo e) {
removeModule(name); removeModule(name);
raiseRaw(e); throw e;
} }
Box* r = getSysModulesDict()->getOrNull(boxString(name)); Box* r = getSysModulesDict()->getOrNull(boxString(name));
...@@ -223,7 +223,7 @@ SearchResult findModule(const std::string& name, const std::string& full_name, B ...@@ -223,7 +223,7 @@ SearchResult findModule(const std::string& name, const std::string& full_name, B
BoxedString* p = static_cast<BoxedString*>(_p); BoxedString* p = static_cast<BoxedString*>(_p);
joined_path.clear(); joined_path.clear();
llvm::sys::path::append(joined_path, std::string(p->s()), name); llvm::sys::path::append(joined_path, p->s(), name);
std::string dn(joined_path.str()); std::string dn(joined_path.str());
llvm::sys::path::append(joined_path, "__init__.py"); llvm::sys::path::append(joined_path, "__init__.py");
...@@ -406,7 +406,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box ...@@ -406,7 +406,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box
RELEASE_ASSERT(0, "%d", sr.type); RELEASE_ASSERT(0, "%d", sr.type);
} catch (ExcInfo e) { } catch (ExcInfo e) {
removeModule(name); removeModule(name);
raiseRaw(e); throw e;
} }
if (parent_module && parent_module != None) if (parent_module && parent_module != None)
...@@ -560,7 +560,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re ...@@ -560,7 +560,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
pathlist = getattrInternal(module, path_str, NULL); pathlist = getattrInternal(module, path_str, NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (!e.matches(AttributeError)) if (!e.matches(AttributeError))
raiseRaw(e); throw e;
} }
if (pathlist == NULL) { if (pathlist == NULL) {
......
...@@ -727,7 +727,7 @@ void listSort(BoxedList* self, Box* cmp, Box* key, Box* reverse) { ...@@ -727,7 +727,7 @@ void listSort(BoxedList* self, Box* cmp, Box* key, Box* reverse) {
std::stable_sort<Box**, PyLt>(self->elts->elts, self->elts->elts + self->size, PyLt()); std::stable_sort<Box**, PyLt>(self->elts->elts, self->elts->elts + self->size, PyLt());
} catch (ExcInfo e) { } catch (ExcInfo e) {
remove_keys(); remove_keys();
raiseRaw(e); throw e;
} }
remove_keys(); remove_keys();
......
...@@ -36,7 +36,6 @@ ExcInfo excInfoForRaise(Box*, Box*, Box*); ...@@ -36,7 +36,6 @@ 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__));
void raiseExc(Box* exc_obj) __attribute__((__noreturn__)); void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
void raiseRaw(const ExcInfo& e) __attribute__((__noreturn__));
void _printStacktrace(); void _printStacktrace();
extern "C" Box* deopt(AST_expr* expr, Box* value); extern "C" Box* deopt(AST_expr* expr, Box* value);
......
...@@ -46,37 +46,8 @@ void showBacktrace() { ...@@ -46,37 +46,8 @@ void showBacktrace() {
} }
} }
void raiseRaw(const ExcInfo& e) __attribute__((__noreturn__));
void raiseRaw(const ExcInfo& e) {
STAT_TIMER(t0, "us_timer_raiseraw");
// Should set these to None rather than null before getting here:
assert(e.type);
assert(e.value);
assert(e.traceback);
assert(gc::isValidGCObject(e.type));
assert(gc::isValidGCObject(e.value));
assert(gc::isValidGCObject(e.traceback));
#if STAT_EXCEPTIONS
static StatCounter num_exceptions("num_exceptions");
num_exceptions.log();
std::string stat_name;
if (PyType_Check(e.type))
stat_name = "num_exceptions_" + std::string(static_cast<BoxedClass*>(e.type)->tp_name);
else
stat_name = "num_exceptions_" + std::string(e.value->cls->tp_name);
Stats::log(Stats::getStatCounter(stat_name));
#if STAT_EXCEPTIONS_LOCATION
logByCurrentPythonLine(stat_name);
#endif
#endif
throw e;
}
void raiseExc(Box* exc_obj) { void raiseExc(Box* exc_obj) {
raiseRaw(ExcInfo(exc_obj->cls, exc_obj, getTraceback())); throw ExcInfo(exc_obj->cls, exc_obj, new BoxedTraceback());
} }
// Have a special helper function for syntax errors, since we want to include the location // Have a special helper function for syntax errors, since we want to include the location
...@@ -84,10 +55,8 @@ void raiseExc(Box* exc_obj) { ...@@ -84,10 +55,8 @@ void raiseExc(Box* exc_obj) {
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func) { void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func) {
Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL); Box* exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL);
auto tb = getTraceback(); auto tb = new BoxedTraceback(LineInfo(lineno, col_offset, file, func), None);
std::vector<const LineInfo*> entries = tb->lines; throw ExcInfo(exc->cls, exc, tb);
entries.push_back(new LineInfo(lineno, col_offset, file, func));
raiseRaw(ExcInfo(exc->cls, exc, new BoxedTraceback(std::move(entries))));
} }
void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...) { void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...) {
...@@ -205,11 +174,13 @@ extern "C" void raise0() { ...@@ -205,11 +174,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");
raiseRaw(*exc_info); exc_info->reraise = true;
throw * 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
...@@ -229,8 +200,12 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) { ...@@ -229,8 +200,12 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) {
assert(type && value && tb); // use None for default behavior, not nullptr assert(type && value && tb); // use None for default behavior, not nullptr
// TODO switch this to PyErr_Normalize // TODO switch this to PyErr_Normalize
if (tb == None) if (tb == None) {
tb = getTraceback(); tb = NULL;
} else if (tb != NULL && !PyTraceBack_Check(tb)) {
raiseExcHelper(TypeError, "raise: arg 3 must be a traceback or None");
}
/* Next, repeatedly, replace a tuple exception with its first item */ /* Next, repeatedly, replace a tuple exception with its first item */
while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { while (PyTuple_Check(type) && PyTuple_Size(type) > 0) {
...@@ -242,6 +217,7 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) { ...@@ -242,6 +217,7 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) {
if (PyExceptionClass_Check(type)) { if (PyExceptionClass_Check(type)) {
PyErr_NormalizeException(&type, &value, &tb); PyErr_NormalizeException(&type, &value, &tb);
if (!PyExceptionInstance_Check(value)) { if (!PyExceptionInstance_Check(value)) {
raiseExcHelper(TypeError, "calling %s() should have returned an instance of " raiseExcHelper(TypeError, "calling %s() should have returned an instance of "
"BaseException, not '%s'", "BaseException, not '%s'",
...@@ -268,11 +244,19 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) { ...@@ -268,11 +244,19 @@ ExcInfo excInfoForRaise(Box* type, Box* value, Box* tb) {
assert(PyExceptionClass_Check(type)); assert(PyExceptionClass_Check(type));
if (tb == NULL) {
tb = new BoxedTraceback();
}
return ExcInfo(type, value, tb); return ExcInfo(type, value, tb);
} }
extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) { extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
raiseRaw(excInfoForRaise(arg0, arg1, arg2)); bool reraise = arg2 != NULL && arg2 != None;
auto exc_info = excInfoForRaise(arg0, arg1, arg2);
exc_info.reraise = reraise;
throw exc_info;
} }
void raiseExcHelper(BoxedClass* cls, Box* arg) { void raiseExcHelper(BoxedClass* cls, Box* arg) {
......
...@@ -128,7 +128,7 @@ Box* superGetattribute(Box* _s, Box* _attr) { ...@@ -128,7 +128,7 @@ Box* superGetattribute(Box* _s, Box* _attr) {
} }
} }
Box* r = typeLookup(s->cls, std::string(attr->s()), NULL); Box* r = typeLookup(s->cls, attr->s(), NULL);
// TODO implement this // TODO implement this
RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here"); RELEASE_ASSERT(r, "should call the equivalent of objectGetattr here");
return processDescriptor(r, s, s->cls); return processDescriptor(r, s, s->cls);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
#include "gc/collector.h" #include "gc/collector.h"
#include "runtime/list.h"
#include "runtime/objmodel.h" #include "runtime/objmodel.h"
#include "runtime/types.h" #include "runtime/types.h"
#include "runtime/util.h" #include "runtime/util.h"
...@@ -40,6 +41,8 @@ void BoxedTraceback::gcHandler(GCVisitor* v, Box* b) { ...@@ -40,6 +41,8 @@ void BoxedTraceback::gcHandler(GCVisitor* v, Box* b) {
if (self->py_lines) if (self->py_lines)
v->visit(self->py_lines); v->visit(self->py_lines);
if (self->tb_next)
v->visit(self->tb_next);
boxGCHandler(v, b); boxGCHandler(v, b);
} }
...@@ -53,16 +56,17 @@ void printTraceback(Box* b) { ...@@ -53,16 +56,17 @@ void printTraceback(Box* b) {
fprintf(stderr, "Traceback (most recent call last):\n"); fprintf(stderr, "Traceback (most recent call last):\n");
for (auto line : tb->lines) { for (; tb && tb != None; tb = static_cast<BoxedTraceback*>(tb->tb_next)) {
fprintf(stderr, " File \"%s\", line %d, in %s:\n", line->file.c_str(), line->line, line->func.c_str()); auto& line = tb->line;
fprintf(stderr, " File \"%s\", line %d, in %s:\n", line.file.c_str(), line.line, line.func.c_str());
if (line->line < 0) if (line.line < 0)
continue; continue;
FILE* f = fopen(line->file.c_str(), "r"); FILE* f = fopen(line.file.c_str(), "r");
if (f) { if (f) {
assert(line->line < 10000000 && "Refusing to try to seek that many lines forward"); assert(line.line < 10000000 && "Refusing to try to seek that many lines forward");
for (int i = 1; i < line->line; i++) { for (int i = 1; i < line.line; i++) {
char* buf = NULL; char* buf = NULL;
size_t size; size_t size;
size_t r = getline(&buf, &size, f); size_t r = getline(&buf, &size, f);
...@@ -97,10 +101,12 @@ Box* BoxedTraceback::getLines(Box* b) { ...@@ -97,10 +101,12 @@ Box* BoxedTraceback::getLines(Box* b) {
if (!tb->py_lines) { if (!tb->py_lines) {
BoxedList* lines = new BoxedList(); BoxedList* lines = new BoxedList();
lines->ensure(tb->lines.size()); for (BoxedTraceback* wtb = tb; wtb && wtb != None; wtb = static_cast<BoxedTraceback*>(wtb->tb_next)) {
for (auto line : tb->lines) { if (wtb->has_line) {
auto l = BoxedTuple::create({ boxString(line->file), boxString(line->func), boxInt(line->line) }); auto& line = wtb->line;
listAppendInternal(lines, l); auto l = BoxedTuple::create({ boxString(line.file), boxString(line.func), boxInt(line.line) });
listAppendInternal(lines, l);
}
} }
tb->py_lines = lines; tb->py_lines = lines;
} }
...@@ -108,6 +114,10 @@ Box* BoxedTraceback::getLines(Box* b) { ...@@ -108,6 +114,10 @@ Box* BoxedTraceback::getLines(Box* b) {
return tb->py_lines; return tb->py_lines;
} }
void BoxedTraceback::here(LineInfo lineInfo, Box** tb) {
*tb = new BoxedTraceback(lineInfo, *tb);
}
void setupTraceback() { void setupTraceback() {
traceback_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedTraceback::gcHandler, 0, 0, traceback_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedTraceback::gcHandler, 0, 0,
sizeof(BoxedTraceback), false, "traceback"); sizeof(BoxedTraceback), false, "traceback");
......
...@@ -27,19 +27,22 @@ class GCVisitor; ...@@ -27,19 +27,22 @@ class GCVisitor;
extern "C" BoxedClass* traceback_cls; extern "C" BoxedClass* traceback_cls;
class BoxedTraceback : public Box { class BoxedTraceback : public Box {
public: public:
std::vector<const LineInfo*> lines; Box* tb_next;
bool has_line;
LineInfo line;
Box* py_lines; Box* py_lines;
BoxedTraceback(std::vector<const LineInfo*> lines) : lines(std::move(lines)), py_lines(NULL) {} BoxedTraceback(LineInfo line, Box* tb_next) : tb_next(tb_next), has_line(true), line(line), py_lines(NULL) {}
BoxedTraceback() : py_lines(NULL) {} BoxedTraceback() : tb_next(None), has_line(false), line(-1, -1, "", ""), py_lines(NULL) {}
DEFAULT_CLASS(traceback_cls); DEFAULT_CLASS(traceback_cls);
void addLine(const LineInfo* line);
static Box* getLines(Box* b); static Box* getLines(Box* b);
static void gcHandler(gc::GCVisitor* v, Box* b); static void gcHandler(gc::GCVisitor* v, Box* b);
// somewhat equivalent to PyTraceBack_Here
static void here(LineInfo lineInfo, Box** tb);
}; };
void printTraceback(Box* b); void printTraceback(Box* b);
......
...@@ -2703,6 +2703,7 @@ void setupRuntime() { ...@@ -2703,6 +2703,7 @@ void setupRuntime() {
closure_cls->freeze(); closure_cls->freeze();
setupUnwinding();
setupInterpreter(); setupInterpreter();
setupCAPI(); setupCAPI();
......
import traceback
import sys
def f():
a, b, c = sys.exc_info()
raise a, b, c
et0, ev0, tb0 = None, None, None
try:
1/0
except:
pass
for i in xrange(10):
try:
f()
except:
et0, ev0, tb0 = sys.exc_info()
print "******** 0", ''.join(traceback.format_exception(et0, ev0, tb0))
et1, ev1, tb1 = None, None, None
et2, ev2, tb2 = None, None, None
def f1():
raise
def f2():
f1()
def f21():
raise Exception()
def f3():
try:
f21()
except:
global et1, tv1, tb1
et1, tv1, tb1 = sys.exc_info()
f2()
try:
f3()
except:
et2, tv2, tb2 = sys.exc_info()
print "******** 1", ''.join(traceback.format_exception(et1, ev1, tb1))
print "******** 2", ''.join(traceback.format_exception(et2, ev2, tb2))
print et1 is et2
print ev1 is ev2
print tb1 is tb2
# expected: fail
# - we don't stop tracebacks at the catching except handler. this is hard do the way it gets added to
# (ie a bare "raise" statement will add more traceback entries to the traceback it raises)
import sys import sys
import traceback import traceback
......
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