Commit 97f3f482 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge commit '0d4b2' into refcounting

parents db8b9589 0d4b2bd7
......@@ -96,6 +96,7 @@ file(GLOB_RECURSE STDOBJECT_SRCS Objects
obmalloc.c
stringobject.c
structseq.c
traceback.c
unicodectype.c
unicodeobject.c
weakrefobject.c
......
......@@ -93,6 +93,8 @@ PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int) PYSTON_NOEXCEPT;
// Pyston addition:
PyAPI_FUNC(int) PyCode_GetArgCount(PyCodeObject *) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject*) PyCode_GetFilename(PyCodeObject *) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject*) PyCode_GetName(PyCodeObject *) PYSTON_NOEXCEPT;
/* for internal use only */
#define _PyCode_GETCODEPTR(co, pp) \
......
......@@ -83,12 +83,18 @@ PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *);
PyAPI_FUNC(int) PyFrame_ClearFreeList(void);
#endif
typedef struct _PyFrameObject PyFrameObject;
typedef struct _frame PyFrameObject;
PyAPI_DATA(PyTypeObject*) frame_cls;
#define PyFrame_Type (*frame_cls)
#define PyFrame_Check(op) (((PyObject*)op)->ob_type == &PyFrame_Type)
/* Return the line of code the frame is currently executing. */
PyAPI_FUNC(int) PyFrame_GetLineNumber(PyFrameObject *) PYSTON_NOEXCEPT;
// Pyston changes: add a function to get globals
PyAPI_FUNC(PyObject *) PyFrame_GetGlobals(PyFrameObject *) PYSTON_NOEXCEPT;
// Pyston changes: add a function to get the code object
PyAPI_FUNC(PyObject *) PyFrame_GetCode(PyFrameObject *) PYSTON_NOEXCEPT;
// Pyston changes: add a function to get frame object by level
PyAPI_FUNC(PyFrameObject *) PyFrame_ForStackLevel(int stack_level) PYSTON_NOEXCEPT;
......
......@@ -10,8 +10,6 @@ struct _frame;
/* Traceback interface */
// Pyston change: not necessarily our object format
#if 0
typedef struct _traceback {
PyObject_HEAD
struct _traceback *tb_next;
......@@ -19,18 +17,16 @@ typedef struct _traceback {
int tb_lasti;
int tb_lineno;
} PyTracebackObject;
#endif
typedef struct _PyTracebackObject PyTracebackObject;
PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *) PYSTON_NOEXCEPT;
PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *) PYSTON_NOEXCEPT;
PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, const char *, int, int) PYSTON_NOEXCEPT;
// Pyston change: this function does not modify curexc_traceback but instead sets the supplied tb
PyAPI_FUNC(int) PyTraceBack_Here_Tb(struct _frame *, PyTracebackObject **) PYSTON_NOEXCEPT;
/* Reveal traceback type so we can typecheck traceback objects */
// Pyston change: not a static type any more
PyAPI_DATA(PyTypeObject*) traceback_cls;
#define PyTraceBack_Type (*traceback_cls)
// PyAPI_DATA(PyTypeObject) PyTraceBack_Type;
PyAPI_DATA(PyTypeObject) PyTraceBack_Type;
#define PyTraceBack_Check(v) (Py_TYPE(v) == &PyTraceBack_Type)
#ifdef __cplusplus
......
// This file is originally from CPython 2.7, with modifications for Pyston
/* Traceback implementation */
#include "Python.h"
#include "code.h"
#include "frameobject.h"
#include "structmember.h"
#include "osdefs.h"
#include "traceback.h"
#define OFF(x) offsetof(PyTracebackObject, x)
static PyMemberDef tb_memberlist[] = {
{"tb_next", T_OBJECT, OFF(tb_next), READONLY},
{"tb_frame", T_OBJECT, OFF(tb_frame), READONLY},
{"tb_lasti", T_INT, OFF(tb_lasti), READONLY},
{"tb_lineno", T_INT, OFF(tb_lineno), READONLY},
{NULL} /* Sentinel */
};
static void
tb_dealloc(PyTracebackObject *tb)
{
PyObject_GC_UnTrack(tb);
Py_TRASHCAN_SAFE_BEGIN(tb)
Py_XDECREF(tb->tb_next);
Py_XDECREF(tb->tb_frame);
PyObject_GC_Del(tb);
Py_TRASHCAN_SAFE_END(tb)
}
static int
tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg)
{
Py_VISIT(tb->tb_next);
Py_VISIT(tb->tb_frame);
return 0;
}
static void
tb_clear(PyTracebackObject *tb)
{
Py_CLEAR(tb->tb_next);
Py_CLEAR(tb->tb_frame);
}
PyTypeObject PyTraceBack_Type = {
// Pyston change:
// PyVarObject_HEAD_INIT(&PyType_Type, 0)
PyVarObject_HEAD_INIT(NULL, 0)
"traceback",
sizeof(PyTracebackObject),
0,
// Pyston change:
//(destructor)tb_dealloc, /*tp_dealloc*/
(destructor)0,
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */
(traverseproc)tb_traverse, /* tp_traverse */
(inquiry)tb_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
tb_memberlist, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
};
static PyTracebackObject *
newtracebackobject(PyTracebackObject *next, PyFrameObject *frame)
{
PyTracebackObject *tb;
if ((next != NULL && !PyTraceBack_Check(next)) ||
frame == NULL || !PyFrame_Check(frame)) {
PyErr_BadInternalCall();
return NULL;
}
tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type);
if (tb != NULL) {
Py_XINCREF(next);
tb->tb_next = next;
Py_XINCREF(frame);
tb->tb_frame = (struct _frame *)frame;
// Pyston change: we don't have tb_lasti
// tb->tb_lasti = frame->f_lasti;
tb->tb_lasti = -1;
tb->tb_lineno = PyFrame_GetLineNumber(frame);
PyObject_GC_Track(tb);
}
return tb;
}
int
PyTraceBack_Here(PyFrameObject *frame)
{
PyThreadState *tstate = PyThreadState_GET();
PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback;
PyTracebackObject *tb = newtracebackobject(oldtb, frame);
if (tb == NULL)
return -1;
tstate->curexc_traceback = (PyObject *)tb;
Py_XDECREF(oldtb);
return 0;
}
// Pyston change: this function does not modify curexc_traceback but instead sets the supplied tb
int
PyTraceBack_Here_Tb(PyFrameObject *frame, PyTracebackObject** tb)
{
if ((PyObject*)*tb == Py_None)
*tb = NULL;
*tb = newtracebackobject(*tb, frame);
if (*tb == NULL)
return -1;
return 0;
}
int
_Py_DisplaySourceLine(PyObject *f, const char *filename, int lineno, int indent)
{
int err = 0;
FILE *xfp = NULL;
char linebuf[2000];
int i;
char namebuf[MAXPATHLEN+1];
if (filename == NULL)
return -1;
/* This is needed by Emacs' compile command */
#define FMT " File \"%.500s\", line %d, in %.500s\n"
xfp = fopen(filename, "r" PY_STDIOTEXTMODE);
if (xfp == NULL) {
/* Search tail of filename in sys.path before giving up */
PyObject *path;
const char *tail = strrchr(filename, SEP);
if (tail == NULL)
tail = filename;
else
tail++;
path = PySys_GetObject("path");
if (path != NULL && PyList_Check(path)) {
Py_ssize_t _npath = PyList_Size(path);
int npath = Py_SAFE_DOWNCAST(_npath, Py_ssize_t, int);
size_t taillen = strlen(tail);
for (i = 0; i < npath; i++) {
PyObject *v = PyList_GetItem(path, i);
if (v == NULL) {
PyErr_Clear();
break;
}
if (PyString_Check(v)) {
size_t len;
len = PyString_GET_SIZE(v);
if (len + 1 + taillen >= MAXPATHLEN)
continue; /* Too long */
strcpy(namebuf, PyString_AsString(v));
if (strlen(namebuf) != len)
continue; /* v contains '\0' */
if (len > 0 && namebuf[len-1] != SEP)
namebuf[len++] = SEP;
strcpy(namebuf+len, tail);
xfp = fopen(namebuf, "r" PY_STDIOTEXTMODE);
if (xfp != NULL) {
break;
}
}
}
}
}
if (xfp == NULL)
return err;
if (err != 0) {
fclose(xfp);
return err;
}
for (i = 0; i < lineno; i++) {
char* pLastChar = &linebuf[sizeof(linebuf)-2];
do {
*pLastChar = '\0';
if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, xfp, NULL) == NULL)
break;
/* fgets read *something*; if it didn't get as
far as pLastChar, it must have found a newline
or hit the end of the file; if pLastChar is \n,
it obviously found a newline; else we haven't
yet seen a newline, so must continue */
} while (*pLastChar != '\0' && *pLastChar != '\n');
}
if (i == lineno) {
char buf[11];
char *p = linebuf;
while (*p == ' ' || *p == '\t' || *p == '\014')
p++;
/* Write some spaces before the line */
strcpy(buf, " ");
assert (strlen(buf) == 10);
while (indent > 0) {
if(indent < 10)
buf[indent] = '\0';
err = PyFile_WriteString(buf, f);
if (err != 0)
break;
indent -= 10;
}
if (err == 0)
err = PyFile_WriteString(p, f);
if (err == 0 && strchr(p, '\n') == NULL)
err = PyFile_WriteString("\n", f);
}
fclose(xfp);
return err;
}
static int
tb_displayline(PyObject *f, const char *filename, int lineno, const char *name)
{
int err = 0;
char linebuf[2000];
if (filename == NULL || name == NULL)
return -1;
/* This is needed by Emacs' compile command */
#define FMT " File \"%.500s\", line %d, in %.500s\n"
PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name);
err = PyFile_WriteString(linebuf, f);
if (err != 0)
return err;
return _Py_DisplaySourceLine(f, filename, lineno, 4);
}
static int
tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit)
{
int err = 0;
long depth = 0;
PyTracebackObject *tb1 = tb;
while (tb1 != NULL) {
depth++;
tb1 = tb1->tb_next;
}
while (tb != NULL && err == 0) {
if (depth <= limit) {
/*
// Pyston change: we can't directly access the fields
err = tb_displayline(f,
PyString_AsString(
tb->tb_frame->f_code->co_filename),
tb->tb_lineno,
PyString_AsString(tb->tb_frame->f_code->co_name));
*/
PyCodeObject* code = (PyCodeObject*)PyFrame_GetCode(tb->tb_frame);
err = tb_displayline(f,
PyString_AsString(PyCode_GetFilename(code)),
tb->tb_lineno,
PyString_AsString(PyCode_GetName(code)));
}
depth--;
tb = tb->tb_next;
if (err == 0)
err = PyErr_CheckSignals();
}
return err;
}
int
PyTraceBack_Print(PyObject *v, PyObject *f)
{
int err;
PyObject *limitv;
long limit = 1000;
if (v == NULL)
return 0;
if (!PyTraceBack_Check(v)) {
PyErr_BadInternalCall();
return -1;
}
limitv = PySys_GetObject("tracebacklimit");
if (limitv && PyInt_Check(limitv)) {
limit = PyInt_AsLong(limitv);
if (limit <= 0)
return 0;
}
err = PyFile_WriteString("Traceback (most recent call last):\n", f);
if (!err)
err = tb_printinternal((PyTracebackObject *)v, f, limit);
return err;
}
......@@ -103,7 +103,6 @@ add_library(PYSTON_OBJECTS OBJECT ${OPTIONAL_SRCS}
runtime/set.cpp
runtime/str.cpp
runtime/super.cpp
runtime/traceback.cpp
runtime/tuple.cpp
runtime/types.cpp
runtime/util.cpp
......
......@@ -538,4 +538,63 @@ extern "C" PyObject* PyErr_ProgramText(const char* filename, int lineno) noexcep
}
return NULL;
}
/* Set file and line information for the current exception.
If the exception is not a SyntaxError, also sets additional attributes
to make printing of exceptions believe it is a syntax error. */
extern "C" void PyErr_SyntaxLocation(const char* filename, int lineno) noexcept {
PyObject* exc, *v, *tb, *tmp;
/* add attributes for the line number and filename for the error */
PyErr_Fetch(&exc, &v, &tb);
PyErr_NormalizeException(&exc, &v, &tb);
/* XXX check that it is, indeed, a syntax error. It might not
* be, though. */
tmp = PyInt_FromLong(lineno);
if (tmp == NULL)
PyErr_Clear();
else {
if (PyObject_SetAttrString(v, "lineno", tmp))
PyErr_Clear();
Py_DECREF(tmp);
}
if (filename != NULL) {
tmp = PyString_FromString(filename);
if (tmp == NULL)
PyErr_Clear();
else {
if (PyObject_SetAttrString(v, "filename", tmp))
PyErr_Clear();
Py_DECREF(tmp);
}
tmp = PyErr_ProgramText(filename, lineno);
if (tmp) {
if (PyObject_SetAttrString(v, "text", tmp))
PyErr_Clear();
Py_DECREF(tmp);
}
}
if (PyObject_SetAttrString(v, "offset", Py_None)) {
PyErr_Clear();
}
if (exc != PyExc_SyntaxError) {
if (!PyObject_HasAttrString(v, "msg")) {
tmp = PyObject_Str(v);
if (tmp) {
if (PyObject_SetAttrString(v, "msg", tmp))
PyErr_Clear();
Py_DECREF(tmp);
} else {
PyErr_Clear();
}
}
if (!PyObject_HasAttrString(v, "print_file_and_line")) {
if (PyObject_SetAttrString(v, "print_file_and_line", Py_None))
PyErr_Clear();
}
}
PyErr_Restore(exc, v, tb);
}
}
......@@ -346,9 +346,8 @@ Box* ASTInterpreter::execJITedBlock(CFGBlock* b) {
assert(getPythonFrameInfo(0) == getFrameInfo());
auto source = getMD()->source.get();
stmt->cxx_exception_count++;
caughtCxxException(LineInfo(stmt->lineno, stmt->col_offset, source->getFn(), source->getName()), &e);
caughtCxxException(&e);
next_block = ((AST_Invoke*)stmt)->exc_dest;
last_exception = e;
......@@ -827,13 +826,13 @@ Value ASTInterpreter::visit_invoke(AST_Invoke* node) {
finishJITing(next_block);
}
} catch (ExcInfo e) {
assert(node == getCurrentStatement());
abortJITing();
assert(getPythonFrameInfo(0) == getFrameInfo());
auto source = getMD()->source.get();
node->cxx_exception_count++;
caughtCxxException(LineInfo(node->lineno, node->col_offset, source->getFn(), source->getName()), &e);
caughtCxxException(&e);
next_block = node->exc_dest;
last_exception = e;
......
......@@ -2929,8 +2929,7 @@ public:
phi_node = emitter.getBuilder()->CreatePHI(g.llvm_aststmt_type_ptr, 0);
emitter.emitSetCurrentStmt(current_stmt);
emitter.getBuilder()->CreateCall(g.funcs.caughtCapiException,
{ phi_node, embedRelocatablePtr(irstate->getSourceInfo(), g.i8_ptr) });
emitter.getBuilder()->CreateCall(g.funcs.caughtCapiException);
if (!final_dest) {
// Propagate the exception out of the function:
......
......@@ -41,7 +41,6 @@
#include "runtime/ctxswitching.h"
#include "runtime/objmodel.h"
#include "runtime/generator.h"
#include "runtime/traceback.h"
#include "runtime/types.h"
......@@ -560,8 +559,7 @@ public:
if (exceptionAtLineCheck()) {
// TODO: shouldn't fetch this multiple times?
frame_iter.getCurrentStatement()->cxx_exception_count++;
auto line_info = lineInfoForFrameInfo(prev_frame_info);
exceptionAtLine(line_info, &exc_info.traceback);
exceptionAtLine(&exc_info.traceback);
}
}
}
......@@ -682,39 +680,6 @@ template <typename Func> void unwindPythonStack(Func func) {
//
// 4. Unless we've hit the end of the stack, go to 2 and keep unwinding.
//
static StatCounter us_gettraceback("us_gettraceback");
Box* getTraceback() {
STAT_TIMER(t0, "us_timer_gettraceback", 20);
if (!ENABLE_FRAME_INTROSPECTION) {
static bool printed_warning = false;
if (!printed_warning) {
printed_warning = true;
fprintf(stderr, "Warning: can't get traceback since ENABLE_FRAME_INTROSPECTION=0\n");
}
return None;
}
if (!ENABLE_TRACEBACKS) {
static bool printed_warning = false;
if (!printed_warning) {
printed_warning = true;
fprintf(stderr, "Warning: can't get traceback since ENABLE_TRACEBACKS=0\n");
}
return None;
}
Timer _t("getTraceback", 1000);
Box* tb = None;
for (FrameInfo* frame_info = getTopFrameInfo(); frame_info; frame_info = frame_info->back) {
BoxedTraceback::here(lineInfoForFrameInfo(frame_info), &tb, getFrame(frame_info));
}
long us = _t.end();
us_gettraceback.log(us);
return static_cast<BoxedTraceback*>(tb);
}
ExcInfo* getFrameExcInfo() {
std::vector<ExcInfo*> to_update;
......@@ -1042,7 +1007,10 @@ void _printStacktrace() {
}
recursive = true;
printTraceback(getTraceback());
Box* file = PySys_GetObject("stderr");
PyTracebackObject* tb = NULL;
PyTraceBack_Here_Tb((struct _frame*)getFrame(0), &tb);
PyTraceBack_Print((Box*)tb, file);
recursive = false;
}
......@@ -1057,26 +1025,23 @@ extern "C" void abort() {
Stats::dump();
fprintf(stderr, "Someone called abort!\n");
// If traceback_cls is NULL, then we somehow died early on, and won't be able to display a traceback.
if (traceback_cls) {
// If we call abort(), things may be seriously wrong. Set an alarm() to
// try to handle cases that we would just hang.
// (Ex if we abort() from a static constructor, and _printStackTrace uses
// that object, _printStackTrace will hang waiting for the first construction
// to finish.)
alarm(1);
try {
_printStacktrace();
} catch (ExcInfo) {
fprintf(stderr, "error printing stack trace during abort()");
}
// Cancel the alarm.
// This is helpful for when running in a debugger, since otherwise the debugger will catch the
// abort and let you investigate, but the alarm will still come back to kill the program.
alarm(0);
// If we call abort(), things may be seriously wrong. Set an alarm() to
// try to handle cases that we would just hang.
// (Ex if we abort() from a static constructor, and _printStackTrace uses
// that object, _printStackTrace will hang waiting for the first construction
// to finish.)
alarm(1);
try {
_printStacktrace();
} catch (ExcInfo) {
fprintf(stderr, "error printing stack trace during abort()");
}
// Cancel the alarm.
// This is helpful for when running in a debugger, since otherwise the debugger will catch the
// abort and let you investigate, but the alarm will still come back to kill the program.
alarm(0);
}
if (PAUSE_AT_ABORT) {
......
......@@ -28,7 +28,6 @@ namespace pyston {
class Box;
class BoxedDict;
class BoxedModule;
class BoxedTraceback;
struct FrameInfo;
void registerDynamicEhFrame(uint64_t code_addr, size_t code_size, uint64_t eh_frame_addr, size_t eh_frame_size);
......@@ -41,8 +40,6 @@ Box* getGlobals(); // returns either the module or a globals dict
Box* getGlobalsDict(); // always returns a dict-like object
CompiledFunction* getCFForAddress(uint64_t addr);
Box* getTraceback();
class PythonUnwindSession;
PythonUnwindSession* beginPythonUnwindSession();
PythonUnwindSession* getActivePythonUnwindSession();
......@@ -54,9 +51,9 @@ void unwindingThroughFrame(PythonUnwindSession* unwind_session, unw_cursor_t* cu
void logException(ExcInfo* exc_info);
void startReraise();
bool exceptionAtLineCheck();
void exceptionAtLine(LineInfo line_info, Box** traceback);
void caughtCxxException(LineInfo line_info, ExcInfo* exc_info);
extern "C" void caughtCapiException(AST_stmt* current_stmt, void* source_info);
void exceptionAtLine(Box** traceback);
void caughtCxxException(ExcInfo* exc_info);
extern "C" void caughtCapiException();
extern "C" void reraiseCapiExcAsCxx() __attribute__((noreturn));
......
......@@ -43,7 +43,6 @@
#include "runtime/import.h"
#include "runtime/objmodel.h"
#include "runtime/rewrite_args.h"
#include "runtime/traceback.h"
#include "runtime/types.h"
namespace pyston {
......@@ -936,13 +935,6 @@ extern "C" PyObject* PyExceptionInstance_Class(PyObject* o) noexcept {
return PyInstance_Check(o) ? (Box*)static_cast<BoxedInstance*>(o)->inst_cls : o->cls;
}
extern "C" int PyTraceBack_Print(PyObject* v, PyObject* f) noexcept {
RELEASE_ASSERT(f->cls == &PyFile_Type && ((PyFileObject*)f)->f_fp == stderr,
"sorry will only print tracebacks to stderr right now");
printTraceback(v);
return 0;
}
#define Py_DEFAULT_RECURSION_LIMIT 1000
static int recursion_limit = Py_DEFAULT_RECURSION_LIMIT;
extern "C" {
......
......@@ -110,6 +110,15 @@ extern "C" int PyCode_GetArgCount(PyCodeObject* op) noexcept {
return unboxInt(BoxedCode::argcount((Box*)op, NULL));
}
extern "C" PyObject* PyCode_GetFilename(PyCodeObject* op) noexcept {
RELEASE_ASSERT(PyCode_Check((Box*)op), "");
return BoxedCode::filename((Box*)op, NULL);
}
extern "C" PyObject* PyCode_GetName(PyCodeObject* op) noexcept {
RELEASE_ASSERT(PyCode_Check((Box*)op), "");
return BoxedCode::name((Box*)op, NULL);
}
void setupCode() {
code_cls
= BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedCode), false, "code", true, NULL, NULL, false);
......
......@@ -27,7 +27,6 @@
#include "core/types.h" // for ExcInfo
#include "core/util.h" // Timer
#include "runtime/generator.h" // generatorEntry
#include "runtime/traceback.h" // BoxedTraceback::addLine
#define UNW_LOCAL_ONLY
#include <libunwind.h>
......
......@@ -20,7 +20,6 @@
#include "core/ast.h"
#include "core/options.h"
#include "runtime/objmodel.h"
#include "runtime/traceback.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -35,8 +34,6 @@ void raiseExc(STOLEN(Box*) exc_obj) {
// of the syntax error in the traceback, even though it is not part of the execution:
void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringRef file, llvm::StringRef func,
bool compiler_error) {
Box* exc;
Box* tb = None;
if (compiler_error) {
// This is how CPython's compiler_error() works:
assert(file.data()[file.size()] == '\0');
......@@ -47,15 +44,14 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, llvm::StringR
}
auto args = BoxedTuple::create({ boxString(file), boxInt(lineno), None, loc });
exc = runtimeCall(SyntaxError, ArgPassSpec(2), boxString(msg), args, NULL, NULL, NULL);
Box* exc = runtimeCall(SyntaxError, ArgPassSpec(2), boxString(msg), args, NULL, NULL, NULL);
assert(!PyErr_Occurred());
throw ExcInfo(exc->cls, exc, None);
} else {
// This is more like how the parser handles it:
exc = runtimeCall(SyntaxError, ArgPassSpec(1), boxString(msg), NULL, NULL, NULL, NULL);
tb = new BoxedTraceback(LineInfo(lineno, col_offset, boxString(file), boxString(func)), None, getFrame(0));
PyErr_SetString(SyntaxError, msg);
PyErr_SyntaxLocation(file.str().c_str(), lineno);
throwCAPIException();
}
assert(!PyErr_Occurred());
throw ExcInfo(exc->cls, exc, tb);
}
void raiseSyntaxErrorHelper(llvm::StringRef file, llvm::StringRef func, AST* node_at, const char* msg, ...) {
......@@ -257,12 +253,9 @@ void logException(ExcInfo* exc_info) {
#endif
}
extern "C" void caughtCapiException(AST_stmt* stmt, void* _source_info) {
SourceInfo* source = static_cast<SourceInfo*>(_source_info);
extern "C" void caughtCapiException() {
PyThreadState* tstate = PyThreadState_GET();
exceptionAtLine(LineInfo(stmt->lineno, stmt->col_offset, source->getFn(), source->getName()),
&tstate->curexc_traceback);
exceptionAtLine(&tstate->curexc_traceback);
}
extern "C" void reraiseCapiExcAsCxx() {
......@@ -275,16 +268,17 @@ extern "C" void reraiseCapiExcAsCxx() {
throw e;
}
// XXX rename this
extern "C" void rawThrow(Box* type, Box* value, Box* tb) {
startReraise();
throw ExcInfo(type, value, tb);
}
void caughtCxxException(LineInfo line_info, ExcInfo* exc_info) {
void caughtCxxException(ExcInfo* exc_info) {
static StatCounter frames_unwound("num_frames_unwound_python");
frames_unwound.log();
exceptionAtLine(line_info, &exc_info->traceback);
exceptionAtLine(&exc_info->traceback);
}
......@@ -302,9 +296,11 @@ bool exceptionAtLineCheck() {
return true;
}
void exceptionAtLine(LineInfo line_info, Box** traceback) {
if (exceptionAtLineCheck())
BoxedTraceback::here(line_info, traceback, autoDecref(getFrame((FrameInfo*)cur_thread_state.frame_info)));
void exceptionAtLine(Box** traceback) {
if (exceptionAtLineCheck()) {
PyTraceBack_Here_Tb((struct _frame*)autoDecref(getFrame((FrameInfo*)cur_thread_state.frame_info)),
(PyTracebackObject**)traceback);
}
}
void startReraise() {
......
......@@ -21,7 +21,9 @@
namespace pyston {
extern "C" {
BoxedClass* frame_cls;
}
// Issues:
// - breaks gdb backtraces
......@@ -225,6 +227,9 @@ extern "C" int PyFrame_GetLineNumber(PyFrameObject* _f) noexcept {
extern "C" PyObject* PyFrame_GetGlobals(PyFrameObject* f) noexcept {
return BoxedFrame::globals((Box*)f, NULL);
}
extern "C" PyObject* PyFrame_GetCode(PyFrameObject* f) noexcept {
return BoxedFrame::code((Box*)f, NULL);
}
extern "C" PyFrameObject* PyFrame_ForStackLevel(int stack_level) noexcept {
return (PyFrameObject*)getFrame(stack_level);
......
......@@ -3034,7 +3034,7 @@ extern "C" bool nonzero(Box* obj) {
}
ASSERT(obj->cls->is_user_defined || obj->cls->instances_are_nonzero || obj->cls == classobj_cls
|| obj->cls == type_cls || isSubclass(obj->cls, Exception) || obj->cls == &PyFile_Type
|| obj->cls == traceback_cls || obj->cls == instancemethod_cls || obj->cls == module_cls
|| obj->cls == &PyTraceBack_Type || obj->cls == instancemethod_cls || obj->cls == module_cls
|| obj->cls == capifunc_cls || obj->cls == builtin_function_or_method_cls
|| obj->cls == method_cls || obj->cls == frame_cls || obj->cls == generator_cls
|| obj->cls == capi_getset_cls || obj->cls == pyston_getset_cls || obj->cls == wrapperdescr_cls
......
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "runtime/traceback.h"
#include <algorithm>
#include <cstring>
#include <sstream>
#include "capi/types.h"
#include "core/ast.h"
#include "core/common.h"
#include "core/stats.h"
#include "core/types.h"
#include "runtime/inline/list.h"
#include "runtime/list.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
namespace pyston {
extern "C" {
BoxedClass* traceback_cls;
}
void printTraceback(Box* b) {
if (b == None)
return;
assert(b->cls == traceback_cls);
BoxedTraceback* tb = static_cast<BoxedTraceback*>(b);
fprintf(stderr, "Traceback (most recent call last):\n");
for (; tb && tb != None; tb = static_cast<BoxedTraceback*>(tb->tb_next)) {
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)
continue;
FILE* f = fopen(line.file->c_str(), "r");
if (f) {
assert(line.line < 10000000 && "Refusing to try to seek that many lines forward");
for (int i = 1; i < line.line; i++) {
char* buf = NULL;
size_t size;
size_t r = getline(&buf, &size, f);
if (r != -1)
free(buf);
}
char* buf = NULL;
size_t size;
size_t r = getline(&buf, &size, f);
if (r != -1) {
while (buf[r - 1] == '\n' or buf[r - 1] == '\r')
r--;
char* ptr = buf;
while (*ptr == ' ' || *ptr == '\t') {
ptr++;
r--;
}
fprintf(stderr, " %.*s\n", (int)r, ptr);
free(buf);
}
fclose(f);
}
}
}
void BoxedTraceback::dealloc(Box* b) noexcept {
BoxedTraceback* self = static_cast<BoxedTraceback*>(b);
Py_DECREF(self->tb_next);
Py_DECREF(self->line.file);
Py_DECREF(self->line.func);
Py_DECREF(self->tb_frame);
PyObject_GC_Del(b);
}
int BoxedTraceback::traverse(Box* self, visitproc visit, void *arg) noexcept {
BoxedTraceback* tb = static_cast<BoxedTraceback*>(self);
Py_VISIT(tb->tb_next);
Py_VISIT(tb->tb_frame);
Py_VISIT(tb->line.file);
Py_VISIT(tb->line.func);
return 0;
}
int BoxedTraceback::clear(Box* self) noexcept {
abort();
}
void BoxedTraceback::here(LineInfo lineInfo, Box** tb, Box* frame) {
Box* old_tb = *tb;
*tb = new BoxedTraceback(std::move(lineInfo), *tb, frame);
Py_DECREF(old_tb);
}
extern "C" int _Py_DisplaySourceLine(PyObject* f, const char* filename, int lineno, int indent) noexcept {
RELEASE_ASSERT(0, "Not implemented.");
}
void setupTraceback() {
traceback_cls = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedTraceback), false, "traceback", true,
(destructor)BoxedTraceback::dealloc, NULL, true,
(traverseproc)BoxedTraceback::traverse, (inquiry)BoxedTraceback::clear);
/*
* Currently not supported.
traceback_cls->giveAttr("tb_lasti", new (pyston_getset_cls) BoxedGetsetDescriptor(traceback_tb_lasti, NULL, NULL));
*/
traceback_cls->giveAttr(
"tb_frame", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedTraceback, tb_frame)));
traceback_cls->giveAttr(
"tb_next", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedTraceback, tb_next)));
traceback_cls->giveAttr("tb_lineno",
new BoxedMemberDescriptor(BoxedMemberDescriptor::INT,
offsetof(BoxedTraceback, line) + offsetof(LineInfo, line)));
traceback_cls->freeze();
}
}
// Copyright (c) 2014-2015 Dropbox, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PYSTON_RUNTIME_TRACEBACK_H
#define PYSTON_RUNTIME_TRACEBACK_H
#include "core/types.h"
#include "runtime/types.h"
namespace pyston {
namespace gc {
class GCVisitor;
}
extern "C" BoxedClass* traceback_cls;
class BoxedTraceback : public Box {
public:
LineInfo line;
Box* tb_next;
Box* tb_frame;
BoxedTraceback(LineInfo line, Box* tb_next, Box* tb_frame)
: line(std::move(line)), tb_next(tb_next), tb_frame(tb_frame) {
Py_INCREF(tb_next);
Py_INCREF(line.file);
Py_INCREF(line.func);
if (!tb_frame)
this->tb_frame = None;
else
assert(tb_frame->cls == frame_cls);
Py_INCREF(this->tb_frame);
}
DEFAULT_CLASS(traceback_cls);
static Box* lineno(Box* obj, void*);
static void gcHandler(gc::GCVisitor* v, Box* b);
// somewhat equivalent to PyTraceBack_Here
static void here(LineInfo lineInfo, Box** tb, Box* frame);
static void dealloc(Box* b) noexcept;
static int traverse(Box* self, visitproc visit, void *arg) noexcept;
static int clear(Box* self) noexcept;
};
void printTraceback(Box* b);
void setupTraceback();
}
#endif
......@@ -47,7 +47,6 @@
#include "runtime/rewrite_args.h"
#include "runtime/set.h"
#include "runtime/super.h"
#include "runtime/traceback.h"
#include "runtime/util.h"
extern "C" void initerrno();
......@@ -4099,7 +4098,6 @@ void setupRuntime() {
_PyWarnings_Init();
_string_init();
setupDescr();
setupTraceback();
setupCode();
setupFrame();
......@@ -4267,6 +4265,7 @@ void setupRuntime() {
PyType_Ready(&PyCObject_Type);
PyType_Ready(&PyDictProxy_Type);
PyType_Ready(&PyTraceBack_Type);
initerrno();
......
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