Commit cc5ec558 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Exceptions part #4: runtime support

There's still vestiges of the libunwind experiment; I'm leaving those in even
though they're dead since I think we should move soon back to that approach.
parent cd769bc5
......@@ -35,6 +35,13 @@
#include "analysis/scoping_analysis.h"
#include "analysis/type_analysis.h"
extern "C" {
// Hack: we only need RTTI for a single type (Box*), which we know will get emmitted,
// so just use the mangled name directly instead of using typeid() since that requires
// turning on RTTI for *everything* (including llvm)
extern void* _ZTIPN6pyston3BoxE;
}
namespace pyston {
llvm::Value* IRGenState::getScratchSpace(int min_bytes) {
......@@ -1693,7 +1700,7 @@ private:
emitter.getBuilder()->CreateStore(converted_arg0->getValue(), bitcasted);
converted_arg0->decvref(emitter);
void* type_id = NULL;
void* type_id = &_ZTIPN6pyston3BoxE /* &typeid(Box*) */;
emitter.createCall(exc_info, g.funcs.__cxa_throw,
{ exc_mem, embedConstantPtr(type_id, g.i8_ptr), embedConstantPtr(nullptr, g.i8_ptr) });
emitter.getBuilder()->CreateUnreachable();
......
This diff is collapsed.
......@@ -46,6 +46,17 @@ public:
virtual void NotifyObjectEmitted(const llvm::ObjectImage&);
};
// LLVM will silently not register the eh frames with libgcc if these functions don't exist;
// make sure that these functions exist.
// TODO I think this breaks it for windows, which apparently loads these dynamically?
// see llvm/lib/ExecutionEngine/RTDyldMemoryManager.cpp
extern "C" void __register_frame(void*);
extern "C" void __deregister_frame(void*);
extern void _force_link() {
__register_frame(nullptr);
__deregister_frame(nullptr);
}
void StackmapJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
// llvm::outs() << "An object has been emitted:\n";
......
......@@ -23,8 +23,54 @@
#include "codegen/codegen.h"
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#ifndef LIBUNWIND_PYSTON_PATCH_VERSION
#error "Please use a patched version of libunwind; see docs/INSTALLING.md"
#elif LIBUNWIND_PYSTON_PATCH_VERSION != 0x01
#error "Please repatch your version of libunwind; see docs/INSTALLING.md"
#endif
// Definition from libunwind, but standardized I suppose by the format of the .eh_frame_hdr section:
struct uw_table_entry {
int32_t start_ip_offset;
int32_t fde_offset;
};
namespace pyston {
// 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.
void parseEhFrame(uint64_t start_addr, uint64_t size, uint64_t* out_data, uint64_t* out_len) {
union {
uint8_t* u8;
uint32_t* u32;
};
u32 = (uint32_t*)start_addr;
int cie_length = *u32;
*u32++;
assert(*u32 == 0); // CIE ID
u8 += cie_length;
int fde_length = *u32;
u32++;
assert(cie_length + fde_length + 8 == size && "more than one fde! (supportable, but not implemented)");
int nentries = 1;
uw_table_entry* table_data = new uw_table_entry[nentries];
table_data->start_ip_offset = 0;
table_data->fde_offset = 4 + cie_length;
*out_data = (uintptr_t)table_data;
*out_len = nentries;
}
class TracebacksEventListener : public llvm::JITEventListener {
public:
void NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
......@@ -56,6 +102,62 @@ public:
}
}
}
// Currently-unused libunwind support:
llvm::error_code code;
bool found_text = false, found_eh_frame = false;
uint64_t text_addr, text_size;
uint64_t eh_frame_addr, eh_frame_size;
for (llvm::object::section_iterator I = Obj.begin_sections(), E = Obj.end_sections(); I != E; ++I) {
llvm::StringRef name;
code = I->getName(name);
assert(!code);
uint64_t addr, size;
if (name == ".eh_frame") {
assert(!found_eh_frame);
found_eh_frame = true;
if (I->getAddress(eh_frame_addr))
continue;
if (I->getSize(eh_frame_size))
continue;
if (VERBOSITY())
printf("eh_frame: %lx %lx\n", eh_frame_addr, eh_frame_size);
} else if (name == ".text") {
assert(!found_text);
found_text = true;
if (I->getAddress(text_addr))
continue;
if (I->getSize(text_size))
continue;
if (VERBOSITY())
printf("text: %lx %lx\n", text_addr, text_size);
}
}
assert(found_text);
assert(found_eh_frame);
unw_dyn_info_t* dyn_info = new unw_dyn_info_t();
dyn_info->start_ip = text_addr;
dyn_info->end_ip = text_addr + text_size;
dyn_info->format = UNW_INFO_FORMAT_REMOTE_TABLE;
dyn_info->u.rti.name_ptr = 0;
dyn_info->u.rti.segbase = eh_frame_addr;
parseEhFrame(eh_frame_addr, eh_frame_size, &dyn_info->u.rti.table_data, &dyn_info->u.rti.table_len);
if (VERBOSITY())
printf("dyn_info = %p, table_data = %p\n", dyn_info, (void*)dyn_info->u.rti.table_data);
_U_dyn_register(dyn_info);
// TODO: it looks like libunwind does a linear search over anything dynamically registered,
// as opposed to the binary search it can do within a dyn_info.
// If we're registering a lot of dyn_info's, it might make sense to coalesce them into a single
// dyn_info that contains a binary search table.
}
};
......
......@@ -25,7 +25,7 @@
namespace pyston {
std::string getOpSymbol(int op_type) {
llvm::StringRef getOpSymbol(int op_type) {
switch (op_type) {
case AST_TYPE::Add:
return "+";
......@@ -86,7 +86,7 @@ std::string getOpSymbol(int op_type) {
}
std::string getInplaceOpSymbol(int op_type) {
return getOpSymbol(op_type) + '=';
return std::string(getOpSymbol(op_type)) + '=';
}
std::string getOpName(int op_type) {
......
......@@ -23,6 +23,8 @@
#include <vector>
#include <string>
#include "llvm/ADT/StringRef.h"
namespace pyston {
namespace AST_TYPE {
......@@ -1096,7 +1098,7 @@ template <class T, class R> void findNodes(const R& roots, std::vector<T*>& outp
}
}
std::string getOpSymbol(int op_type);
llvm::StringRef getOpSymbol(int op_type);
};
#endif
......@@ -369,6 +369,8 @@ std::string getPythonFuncAt(void* ip, void* sp);
// TODO where to put this
void addToSysPath(const std::string& path);
void addToSysArgv(const char* str);
std::string formatException(Box* e);
}
#endif
......@@ -143,7 +143,14 @@ int main(int argc, char** argv) {
fprintf(stderr, "==============\n");
}
compileAndRunModule(m, main);
try {
compileAndRunModule(m, main);
}
catch (Box* b) {
std::string msg = formatException(b);
fprintf(stderr, "%s\n", msg.c_str());
exit(1);
}
}
}
......@@ -179,7 +186,8 @@ int main(int argc, char** argv) {
}
if (repl) {
printf("Pyston v0.1, rev " STRINGIFY(GITREV) "\n");
printf("Pyston v0.1 (rev " STRINGIFY(GITREV) ")");
printf(", targeting Python %d.%d.%d\n", PYTHON_VERSION_MAJOR, PYTHON_VERSION_MINOR, PYTHON_VERSION_MICRO);
BoxedModule* main = createModule("__main__", "<stdin>");
......@@ -193,8 +201,7 @@ int main(int argc, char** argv) {
if ((read = getline(&line, &size, stdin)) == -1) {
repl = false;
} else {
timeval start, end;
gettimeofday(&start, NULL);
Timer _t("repl");
char buf[] = "pystontmp_XXXXXX";
char* tmpdir = mkdtemp(buf);
......@@ -221,12 +228,6 @@ int main(int argc, char** argv) {
}
compileAndRunModule(m, main);
if (VERBOSITY() >= 1) {
gettimeofday(&end, NULL);
long ms = 1000 * (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000;
printf("%ldms\n", ms);
}
}
}
}
......
......@@ -71,12 +71,12 @@ extern "C" Box* open2(Box* arg1, Box* arg2) {
if (arg1->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n",
getTypeName(arg1)->c_str());
raiseExc();
raiseExcHelper(TypeError, "");
}
if (arg2->cls != str_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n",
getTypeName(arg2)->c_str());
raiseExc();
raiseExcHelper(TypeError, "");
}
const std::string& fn = static_cast<BoxedString*>(arg1)->s;
......@@ -97,7 +97,7 @@ extern "C" Box* open1(Box* arg) {
extern "C" Box* chr(Box* arg) {
if (arg->cls != int_cls) {
fprintf(stderr, "TypeError: coercing to Unicode: need string of buffer, %s found\n", getTypeName(arg)->c_str());
raiseExc();
raiseExcHelper(TypeError, "");
}
i64 n = static_cast<BoxedInt*>(arg)->n;
RELEASE_ASSERT(n >= 0 && n < 256, "");
......@@ -183,22 +183,22 @@ Box* sorted(Box* obj) {
}
Box* isinstance_func(Box* obj, Box* cls) {
assert(cls->cls == type_cls);
BoxedClass* ccls = static_cast<BoxedClass*>(cls);
return boxBool(isinstance(obj, cls, 0));
}
Box* getattr2(Box* obj, Box* _str) {
if (_str->cls != str_cls) {
fprintf(stderr, "TypeError: getattr(): attribute name must be string\n");
raiseExc();
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
BoxedString* str = static_cast<BoxedString*>(_str);
Box* rtn = getattr_internal(obj, str->s.c_str(), true, true, NULL, NULL);
if (!rtn) {
fprintf(stderr, "AttributeError: '%s' object has no attribute '%s'\n", getTypeName(obj)->c_str(),
str->s.c_str());
raiseExc();
raiseExcHelper(AttributeError, "'%s' object has no attribute '%s'", getTypeName(obj)->c_str(), str->s.c_str());
}
return rtn;
......@@ -206,8 +206,7 @@ Box* getattr2(Box* obj, Box* _str) {
Box* getattr3(Box* obj, Box* _str, Box* default_value) {
if (_str->cls != str_cls) {
fprintf(stderr, "TypeError: getattr(): attribute name must be string\n");
raiseExc();
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
BoxedString* str = static_cast<BoxedString*>(_str);
......@@ -247,6 +246,60 @@ extern "C" const ObjectFlavor notimplemented_flavor(&boxGCHandler, NULL);
BoxedClass* notimplemented_cls;
BoxedModule* builtins_module;
// TODO looks like CPython and pypy put this into an "exceptions" module:
BoxedClass* Exception, *AssertionError, *AttributeError, *TypeError, *NameError, *KeyError, *IndexError, *IOError,
*OSError, *ZeroDivisionError, *ValueError, *UnboundLocalError, *RuntimeError, *ImportError;
const ObjectFlavor exception_flavor(&boxGCHandler, NULL);
Box* exceptionNew1(BoxedClass* cls) {
return exceptionNew2(cls, boxStrConstant(""));
}
Box* exceptionNew2(BoxedClass* cls, Box* message) {
HCBox* r = new HCBox(&exception_flavor, cls);
r->giveAttr("message", message);
return r;
}
Box* exceptionStr(Box* b) {
HCBox* hcb = static_cast<HCBox*>(b);
// TODO In CPython __str__ and __repr__ pull from an internalized message field, but for now do this:
Box* message = hcb->peekattr("message");
assert(message);
message = str(message);
assert(message->cls == str_cls);
return message;
}
Box* exceptionRepr(Box* b) {
HCBox* hcb = static_cast<HCBox*>(b);
// TODO In CPython __str__ and __repr__ pull from an internalized message field, but for now do this:
Box* message = hcb->peekattr("message");
assert(message);
message = repr(message);
assert(message->cls == str_cls);
BoxedString* message_s = static_cast<BoxedString*>(message);
return boxString(*getTypeName(b) + "(" + message_s->s + ",)");
}
static BoxedClass* makeBuiltinException(const char* name) {
BoxedClass* cls = new BoxedClass(true, NULL);
cls->giveAttr("__name__", boxStrConstant(name));
// TODO these should be on the base Exception class:
cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)exceptionNew1, NULL, 1, false)));
cls->giveAttr("__str__", new BoxedFunction(boxRTFunction((void*)exceptionStr, NULL, 1, false)));
cls->giveAttr("__repr__", new BoxedFunction(boxRTFunction((void*)exceptionRepr, NULL, 1, false)));
cls->freeze();
builtins_module->giveAttr(name, cls);
return cls;
}
void setupBuiltins() {
builtins_module = createModule("__builtin__", "__builtin__");
......@@ -263,6 +316,21 @@ void setupBuiltins() {
builtins_module->giveAttr("NotImplemented", NotImplemented);
builtins_module->giveAttr("NotImplementedType", notimplemented_cls);
Exception = makeBuiltinException("Exception");
AssertionError = makeBuiltinException("AssertionError");
AttributeError = makeBuiltinException("AttributeError");
TypeError = makeBuiltinException("TypeError");
NameError = makeBuiltinException("NameError");
KeyError = makeBuiltinException("KeyError");
IndexError = makeBuiltinException("IndexError");
IOError = makeBuiltinException("IOError");
OSError = makeBuiltinException("OSError");
ZeroDivisionError = makeBuiltinException("ZeroDivisionError");
ValueError = makeBuiltinException("ValueError");
UnboundLocalError = makeBuiltinException("UnboundLocalError");
RuntimeError = makeBuiltinException("RuntimeError");
ImportError = makeBuiltinException("ImportError");
repr_obj = new BoxedFunction(boxRTFunction((void*)repr, NULL, 1, false));
builtins_module->giveAttr("repr", repr_obj);
len_obj = new BoxedFunction(boxRTFunction((void*)len, NULL, 1, false));
......
......@@ -31,7 +31,7 @@ BoxedModule* math_module;
static double _extractFloat(Box* b) {
if (b->cls != int_cls && b->cls != float_cls) {
fprintf(stderr, "TypeError: a float is required\n");
raiseExc();
raiseExcHelper(TypeError, "");
}
if (b->cls == int_cls)
......@@ -45,7 +45,7 @@ Box* mathSqrtFloat(Box* b) {
double d = static_cast<BoxedFloat*>(b)->d;
if (d < 0) {
fprintf(stderr, "ValueError: math domain error\n");
raiseExc();
raiseExcHelper(ValueError, "");
}
return boxFloat(sqrt(d));
}
......@@ -55,7 +55,7 @@ Box* mathSqrtInt(Box* b) {
double d = static_cast<BoxedInt*>(b)->n;
if (d < 0) {
fprintf(stderr, "ValueError: math domain error\n");
raiseExc();
raiseExcHelper(ValueError, "");
}
return boxFloat(sqrt(d));
}
......@@ -65,7 +65,7 @@ Box* mathSqrt(Box* b) {
double d = _extractFloat(b);
if (d < 0) {
fprintf(stderr, "ValueError: math domain error\n");
raiseExc();
raiseExcHelper(ValueError, "");
}
return boxFloat(sqrt(d));
}
......
......@@ -46,7 +46,7 @@ BoxedList* getSysPath() {
if (_sys_path->cls != list_cls) {
fprintf(stderr, "RuntimeError: sys.path must be a list of directory name\n");
raiseExc();
raiseExcHelper(RuntimeError, "");
}
assert(_sys_path->cls == list_cls);
......
......@@ -81,7 +81,7 @@ Box* dictGetitem(BoxedDict* self, Box* k) {
if (pos == NULL) {
BoxedString* s = static_cast<BoxedString*>(repr(k));
fprintf(stderr, "KeyError: %s\n", s->s.c_str());
raiseExc();
raiseExcHelper(KeyError, "");
}
return pos;
......
......@@ -36,7 +36,7 @@ Box* fileRepr(BoxedFile* self) {
static Box* _fileRead(BoxedFile* self, i64 size) {
if (self->closed) {
fprintf(stderr, "IOError: file not open for reading\n");
raiseExc();
raiseExcHelper(IOError, "");
}
std::ostringstream os("");
......@@ -88,7 +88,7 @@ Box* fileRead2(BoxedFile* self, Box* size) {
assert(self->cls == file_cls);
if (size->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "");
}
return _fileRead(self, static_cast<BoxedInt*>(size)->n);
}
......@@ -98,7 +98,7 @@ Box* fileWrite(BoxedFile* self, Box* val) {
if (self->closed) {
fprintf(stderr, "IOError: file is closed\n");
raiseExc();
raiseExcHelper(IOError, "");
}
......@@ -119,7 +119,7 @@ Box* fileWrite(BoxedFile* self, Box* val) {
if (!new_written) {
int error = ferror(self->f);
fprintf(stderr, "IOError %d\n", error);
raiseExc();
raiseExcHelper(IOError, "");
}
written += new_written;
......@@ -127,8 +127,8 @@ Box* fileWrite(BoxedFile* self, Box* val) {
return None;
} else {
fprintf(stderr, "str expected\n");
raiseExc();
fprintf(stderr, "TypeError: expected a character buffer object\n");
raiseExcHelper(TypeError, "");
}
}
......@@ -136,7 +136,7 @@ Box* fileClose(BoxedFile* self) {
assert(self->cls == file_cls);
if (self->closed) {
fprintf(stderr, "IOError: file is closed\n");
raiseExc();
raiseExcHelper(IOError, "");
}
fclose(self->f);
......
......@@ -30,8 +30,7 @@ namespace pyston {
template <typename T> static inline void raiseDivZeroExcIfZero(T var) {
if (var == 0) {
fprintf(stderr, "float divide by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "float divide by zero");
}
}
......
......@@ -48,8 +48,7 @@ extern "C" i64 sub_i64_i64(i64 lhs, i64 rhs) {
extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) {
if (rhs == 0) {
fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero");
}
if (lhs < 0 && rhs > 0)
return (lhs - rhs + 1) / rhs;
......@@ -60,8 +59,7 @@ extern "C" i64 div_i64_i64(i64 lhs, i64 rhs) {
extern "C" i64 mod_i64_i64(i64 lhs, i64 rhs) {
if (rhs == 0) {
fprintf(stderr, "ZeroDivisionError: integer division or modulo by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "integer division or modulo by zero");
}
if (lhs < 0 && rhs > 0)
return ((lhs + 1) % rhs) + (rhs - 1);
......@@ -163,8 +161,7 @@ extern "C" Box* intDivFloat(BoxedInt* lhs, BoxedFloat* rhs) {
assert(rhs->cls == float_cls);
if (rhs->d == 0) {
fprintf(stderr, "float divide by zero\n");
raiseExc();
raiseExcHelper(ZeroDivisionError, "float divide by zero");
}
return boxFloat(lhs->n / rhs->d);
}
......@@ -445,8 +442,9 @@ extern "C" Box* intNew2(Box* cls, Box* val) {
return boxInt(d);
} else {
fprintf(stderr, "int() argument must be a string or a number, not '%s'\n", getTypeName(val)->c_str());
raiseExc();
fprintf(stderr, "TypeError: int() argument must be a string or a number, not '%s'\n",
getTypeName(val)->c_str());
raiseExcHelper(TypeError, "");
}
}
......
......@@ -54,8 +54,7 @@ extern "C" Box* listNonzero(BoxedList* self) {
extern "C" Box* listPop1(BoxedList* self) {
if (self->size == 0) {
fprintf(stderr, "IndexError: pop from empty list\n");
raiseExc();
raiseExcHelper(IndexError, "pop from empty list");
}
self->size--;
......@@ -65,8 +64,7 @@ extern "C" Box* listPop1(BoxedList* self) {
extern "C" Box* listPop2(BoxedList* self, Box* idx) {
if (idx->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "an integer is required");
}
int64_t n = static_cast<BoxedInt*>(idx)->n;
......@@ -78,7 +76,7 @@ extern "C" Box* listPop2(BoxedList* self, Box* idx) {
fprintf(stderr, "IndexError: pop from empty list\n");
else
fprintf(stderr, "IndexError: pop index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "");
}
Box* rtn = self->elts->elts[n];
......@@ -126,8 +124,7 @@ extern "C" Box* listGetitemInt(BoxedList* self, BoxedInt* slice) {
n = self->size + n;
if (n < 0 || n >= self->size) {
fprintf(stderr, "IndexError: list index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "list index out of range");
}
Box* rtn = self->elts->elts[n];
return rtn;
......@@ -148,8 +145,7 @@ extern "C" Box* listGetitem(BoxedList* self, Box* slice) {
} else if (slice->cls == slice_cls) {
return listGetitemSlice(self, static_cast<BoxedSlice*>(slice));
} else {
fprintf(stderr, "TypeError: list indices must be integers, not %s\n", getTypeName(slice)->c_str());
raiseExc();
raiseExcHelper(TypeError, "list indices must be integers, not %s", getTypeName(slice)->c_str());
}
}
......@@ -162,8 +158,7 @@ extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
n = self->size + n;
if (n < 0 || n >= self->size) {
fprintf(stderr, "IndexError: list index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "list index out of range");
}
self->elts->elts[n] = v;
......@@ -206,15 +201,13 @@ extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) {
} else if (slice->cls == slice_cls) {
return listSetitemSlice(self, static_cast<BoxedSlice*>(slice), v);
} else {
fprintf(stderr, "TypeError: list indices must be integers, not %s\n", getTypeName(slice)->c_str());
raiseExc();
raiseExcHelper(TypeError, "list indices must be integers, not %s", getTypeName(slice)->c_str());
}
}
extern "C" Box* listInsert(BoxedList* self, Box* idx, Box* v) {
if (idx->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "an integer is required");
}
int64_t n = static_cast<BoxedInt*>(idx)->n;
......@@ -240,8 +233,7 @@ extern "C" Box* listInsert(BoxedList* self, Box* idx, Box* v) {
Box* listMul(BoxedList* self, Box* rhs) {
if (rhs->cls != int_cls) {
fprintf(stderr, "TypeError: can't multiply sequence by non-int of type '%s'\n", getTypeName(rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can't multiply sequence by non-int of type '%s'", getTypeName(rhs)->c_str());
}
int n = static_cast<BoxedInt*>(rhs)->n;
......@@ -264,8 +256,7 @@ Box* listMul(BoxedList* self, Box* rhs) {
Box* listIAdd(BoxedList* self, Box* _rhs) {
if (_rhs->cls != list_cls) {
fprintf(stderr, "TypeError: can only concatenate list (not \"%s\") to list\n", getTypeName(_rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can only concatenate list (not \"%s\") to list", getTypeName(_rhs)->c_str());
}
BoxedList* rhs = static_cast<BoxedList*>(_rhs);
......@@ -281,8 +272,7 @@ Box* listIAdd(BoxedList* self, Box* _rhs) {
Box* listAdd(BoxedList* self, Box* _rhs) {
if (_rhs->cls != list_cls) {
fprintf(stderr, "TypeError: can only concatenate list (not \"%s\") to list\n", getTypeName(_rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can only concatenate list (not \"%s\") to list", getTypeName(_rhs)->c_str());
}
BoxedList* rhs = static_cast<BoxedList*>(_rhs);
......
This diff is collapsed.
......@@ -28,6 +28,9 @@ class BoxedInt;
class BoxedList;
class BoxedString;
void raiseExc(Box*) __attribute__((__noreturn__));
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__));
extern "C" const std::string* getTypeName(Box* o);
extern "C" const std::string* getNameOfClass(BoxedClass* cls);
......
......@@ -22,11 +22,14 @@
#endif
#include "core/options.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
#include "core/options.h"
#include <stdarg.h>
namespace pyston {
// from http://www.nongnu.org/libunwind/man/libunwind(3).html
......@@ -50,12 +53,102 @@ void showBacktrace() {
}
}
void raiseExc() {
if (VERBOSITY())
showBacktrace();
// if (VERBOSITY()) raise(SIGTRAP);
if (VERBOSITY())
abort();
exit(1);
// Currently-unused libunwind-based unwinding:
void unwindExc(Box* exc_obj) __attribute__((noreturn));
void unwindExc(Box* exc_obj) {
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
int code;
unw_proc_info_t pip;
while (unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
printf("ip = %lx, sp = %lx\n", (long)ip, (long)sp);
code = unw_get_proc_info(&cursor, &pip);
RELEASE_ASSERT(code == 0, "");
// printf("%lx %lx %lx %lx %lx %lx %d %d %p\n", pip.start_ip, pip.end_ip, pip.lsda, pip.handler, pip.gp,
// pip.flags, pip.format, pip.unwind_info_size, pip.unwind_info);
assert((pip.lsda == 0) == (pip.handler == 0));
assert(pip.flags == 0);
if (pip.handler == 0) {
if (VERBOSITY())
printf("Skipping frame without handler\n");
continue;
}
printf("%lx %lx %lx\n", pip.lsda, pip.handler, pip.flags);
// assert(pip.handler == (uintptr_t)__gxx_personality_v0 || pip.handler == (uintptr_t)__py_personality_v0);
// auto handler_fn = (int (*)(int, int, uint64_t, void*, void*))pip.handler;
////handler_fn(1, 1 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL);
// handler_fn(2, 2 /* _UA_SEARCH_PHASE */, 0 /* exc_class */, NULL, NULL);
unw_set_reg(&cursor, UNW_REG_IP, 1);
// TODO testing:
// unw_resume(&cursor);
}
abort();
}
void raiseExc(Box* exc_obj) {
// Using libgcc:
throw exc_obj;
// Using libunwind
// unwindExc(exc_obj);
abort();
}
void raiseExcHelper(BoxedClass* cls, const char* msg, ...) {
if (msg != NULL) {
va_list ap;
va_start(ap, msg);
char buf[1024];
vsnprintf(buf, sizeof(buf), msg, ap);
va_end(ap);
BoxedString* message = boxStrConstant(buf);
Box* exc_obj = exceptionNew2(cls, message);
raiseExc(exc_obj);
} else {
Box* exc_obj = exceptionNew1(cls);
raiseExc(exc_obj);
}
}
std::string formatException(Box* b) {
const std::string* name = getTypeName(b);
HCBox* hcb = static_cast<HCBox*>(b);
Box* attr = hcb->peekattr("message");
if (attr == nullptr)
return *name;
Box* r;
try {
r = str(attr);
}
catch (Box* b) {
return *name;
}
assert(r->cls == str_cls);
const std::string* msg = &static_cast<BoxedString*>(r)->s;
return *name + ": " + *msg;
}
}
......@@ -37,8 +37,7 @@ extern "C" BoxedString* strAdd(BoxedString* lhs, Box* _rhs) {
assert(lhs->cls == str_cls);
if (_rhs->cls != str_cls) {
fprintf(stderr, "TypeError: cannot concatenate 'str' and '%s' objects", getTypeName(_rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "cannot concatenate 'str' and '%s' objects", getTypeName(_rhs)->c_str());
}
BoxedString* rhs = static_cast<BoxedString*>(_rhs);
......@@ -336,8 +335,7 @@ Box* strJoin(BoxedString* self, Box* rhs) {
}
return boxString(os.str());
} else {
fprintf(stderr, "TypeError\n");
raiseExc();
raiseExcHelper(TypeError, "");
}
}
......@@ -376,14 +374,12 @@ Box* strSplit2(BoxedString* self, BoxedString* sep) {
listAppendInternal(rtn, boxString(s.str()));
return rtn;
} else {
fprintf(stderr, "ValueError: empty separator\n");
raiseExc();
raiseExcHelper(ValueError, "empty separator");
}
} else if (sep->cls == none_cls) {
return strSplit1(self);
} else {
fprintf(stderr, "TypeError: expected a character buffer object\n");
raiseExc();
raiseExcHelper(TypeError, "expected a character buffer object");
}
}
......@@ -397,8 +393,7 @@ extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
n = size + n;
if (n < 0 || n >= size) {
fprintf(stderr, "IndexError: string index out of range\n");
raiseExc();
raiseExcHelper(IndexError, "string index out of range");
}
char c = self->s[n];
......@@ -410,8 +405,7 @@ extern "C" Box* strGetitem(BoxedString* self, Box* slice) {
parseSlice(sslice, self->s.size(), &start, &stop, &step);
return _strSlice(self, start, stop, step);
} else {
fprintf(stderr, "TypeError: string indices must be integers, not %s\n", getTypeName(slice)->c_str());
raiseExc();
raiseExcHelper(TypeError, "string indices must be integers, not %s", getTypeName(slice)->c_str());
}
}
......
......@@ -47,8 +47,8 @@ Box* tupleGetitem(BoxedTuple* self, Box* slice) {
if (n < 0)
n = size - n;
if (n < 0 || n >= size) {
fprintf(stderr, "indexerror\n");
raiseExc();
fprintf(stderr, "IndexError: tuple index out of range\n");
raiseExcHelper(IndexError, "");
}
Box* rtn = self->elts[n];
......
......@@ -272,5 +272,11 @@ public:
};
extern "C" void boxGCHandler(GCVisitor* v, void* p);
Box* exceptionNew1(BoxedClass* cls);
Box* exceptionNew2(BoxedClass* cls, Box* message);
extern BoxedClass* Exception, *AssertionError, *AttributeError, *TypeError, *NameError, *KeyError, *IndexError,
*IOError, *OSError, *ZeroDivisionError, *ValueError, *UnboundLocalError, *RuntimeError, *ImportError;
}
#endif
......@@ -14,6 +14,7 @@
#include "core/options.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -64,7 +65,7 @@ void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64*
if (istep == 0) {
fprintf(stderr, "ValueError: slice step cannot be zero\n");
raiseExc();
raiseExcHelper(ValueError, "");
}
if (istep > 0) {
......
......@@ -22,7 +22,5 @@ namespace pyston {
class BoxedSlice;
void parseSlice(BoxedSlice* slice, int size, i64* out_start, i64* out_stop, i64* out_end);
void raiseExc() __attribute__((__noreturn__));
}
#endif
# expected: fail
# - exceptions
def f(x):
print x
......
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