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();
......
......@@ -15,6 +15,7 @@
#include <sstream>
#include <unordered_map>
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instructions.h"
......@@ -30,6 +31,8 @@
#include "codegen/irgen/hooks.h"
#include "codegen/irgen/util.h"
extern "C" void* __cxa_allocate_exception(size_t);
namespace pyston {
union Val {
......@@ -62,7 +65,7 @@ int width(llvm::Value* v, const llvm::DataLayout& dl) {
//#undef VERBOSITY
//#define VERBOSITY(x) 2
#define TIME_INTERPRETS
//#define TIME_INTERPRETS
Val fetch(llvm::Value* v, const llvm::DataLayout& dl, const SymMap& symbols) {
assert(v);
......@@ -180,6 +183,8 @@ Val fetch(llvm::Value* v, const llvm::DataLayout& dl, const SymMap& symbols) {
// maybe-defined Python variable; we won't actually read from it if
// it's undef, since it should be guarded by an !is_defined variable.
return (int64_t) - 1337;
case llvm::Value::ConstantPointerNullVal:
return (int64_t)0;
default:
v->dump();
RELEASE_ASSERT(0, "%d", v->getValueID());
......@@ -279,6 +284,10 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
llvm::BasicBlock* prevblock = NULL;
llvm::BasicBlock* curblock = &f->getEntryBlock();
struct {
Box* exc_obj;
int64_t exc_selector;
} landingpad_value;
while (true) {
for (llvm::Instruction& _inst : *curblock) {
......@@ -292,7 +301,25 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
}
#define SET(v) set(symbols, inst, (v))
if (llvm::LoadInst* li = llvm::dyn_cast<llvm::LoadInst>(inst)) {
if (llvm::LandingPadInst* lpad = llvm::dyn_cast<llvm::LandingPadInst>(inst)) {
SET((intptr_t) & landingpad_value);
continue;
} else if (llvm::ExtractValueInst* ev = llvm::dyn_cast<llvm::ExtractValueInst>(inst)) {
Val r = fetch(ev->getAggregateOperand(), dl, symbols);
llvm::ArrayRef<unsigned> indexes = ev->getIndices();
#ifndef NDEBUG
assert(indexes.size() == 1);
llvm::Type* t = llvm::ExtractValueInst::getIndexedType(ev->getAggregateOperand()->getType(), indexes);
assert(width(t, dl) == 8);
#endif
int64_t* ptr = (int64_t*)r.n;
int64_t val = ptr[indexes[0]];
SET(val);
continue;
} else if (llvm::LoadInst* li = llvm::dyn_cast<llvm::LoadInst>(inst)) {
llvm::Value* ptr = li->getOperand(0);
Val v = fetch(ptr, dl, symbols);
// printf("loading from %p\n", v.o);
......@@ -470,18 +497,22 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
assert(width(bc->getOperand(0), dl) == 8);
SET(fetch(bc->getOperand(0), dl, symbols));
continue;
} else if (llvm::CallInst* ci = llvm::dyn_cast<llvm::CallInst>(inst)) {
//} else if (llvm::CallInst* ci = llvm::dyn_cast<llvm::CallInst>(inst)) {
} else if (llvm::isa<llvm::CallInst>(inst) || llvm::isa<llvm::InvokeInst>(inst)) {
llvm::CallSite cs(inst);
llvm::InvokeInst* invoke = llvm::dyn_cast<llvm::InvokeInst>(inst);
void* f;
int arg_start;
if (ci->getCalledFunction()
&& (ci->getCalledFunction()->getName() == "llvm.experimental.patchpoint.void"
|| ci->getCalledFunction()->getName() == "llvm.experimental.patchpoint.i64")) {
// ci->dump();
if (cs.getCalledFunction()
&& (cs.getCalledFunction()->getName() == "llvm.experimental.patchpoint.void"
|| cs.getCalledFunction()->getName() == "llvm.experimental.patchpoint.i64")) {
// cs.dump();
assert(0 && "shouldn't be generating patchpoints for interpretation!");
f = (void*)fetch(ci->getArgOperand(2), dl, symbols).n;
f = (void*)fetch(cs.getArgument(2), dl, symbols).n;
arg_start = 4;
} else {
f = (void*)fetch(ci->getCalledValue(), dl, symbols).n;
f = (void*)fetch(cs.getCalledValue(), dl, symbols).n;
arg_start = 0;
}
......@@ -489,10 +520,10 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
printf("calling %s\n", g.func_addr_registry.getFuncNameAtAddress(f, true).c_str());
std::vector<Val> args;
int nargs = ci->getNumArgOperands();
int nargs = cs.arg_size();
for (int i = arg_start; i < nargs; i++) {
// ci->getArgOperand(i)->dump();
args.push_back(fetch(ci->getArgOperand(i), dl, symbols));
// cs.getArgument(i)->dump();
args.push_back(fetch(cs.getArgument(i), dl, symbols));
}
int npassed_args = nargs - arg_start;
......@@ -504,97 +535,118 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
// This is dumb but I don't know how else to do it:
int mask = 1;
if (ci->getType() == g.double_)
if (cs.getType() == g.double_)
mask = 3;
else
mask = 2;
for (int i = 0; i < npassed_args; i++) {
mask <<= 1;
if (ci->getOperand(i)->getType() == g.double_)
if (cs.getArgument(i)->getType() == g.double_)
mask |= 1;
}
Val r((int64_t)0);
switch (mask) {
case 0b10:
r = reinterpret_cast<int64_t (*)()>(f)();
break;
case 0b11:
r = reinterpret_cast<double (*)()>(f)();
break;
case 0b100:
r = reinterpret_cast<int64_t (*)(int64_t)>(f)(args[0].n);
break;
case 0b101:
r = reinterpret_cast<int64_t (*)(double)>(f)(args[0].d);
break;
case 0b110:
r = reinterpret_cast<double (*)(int64_t)>(f)(args[0].n);
break;
case 0b1000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t)>(f)(args[0].n, args[1].n);
break;
case 0b1001:
r = reinterpret_cast<int64_t (*)(int64_t, double)>(f)(args[0].n, args[1].d);
break;
case 0b1011:
r = reinterpret_cast<int64_t (*)(double, double)>(f)(args[0].d, args[1].d);
break;
case 0b1111:
r = reinterpret_cast<double (*)(double, double)>(f)(args[0].d, args[1].d);
break;
case 0b10000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t)>(f)(args[0].n, args[1].n,
args[2].n);
break;
case 0b10001:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, double)>(f)(args[0].n, args[1].n, args[2].d);
break;
case 0b10011:
r = reinterpret_cast<int64_t (*)(int64_t, double, double)>(f)(args[0].n, args[1].d, args[2].d);
break;
case 0b100000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t)>(f)(args[0].n, args[1].n,
args[2].n, args[3].n);
break;
case 0b100001:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, double)>(f)(args[0].n, args[1].n,
args[2].n, args[3].d);
break;
case 0b100110:
r = reinterpret_cast<int64_t (*)(int64_t, double, double, int64_t)>(f)(args[0].n, args[1].d,
try {
switch (mask) {
case 0b10:
r = reinterpret_cast<int64_t (*)()>(f)();
break;
case 0b11:
r = reinterpret_cast<double (*)()>(f)();
break;
case 0b100:
r = reinterpret_cast<int64_t (*)(int64_t)>(f)(args[0].n);
break;
case 0b101:
r = reinterpret_cast<int64_t (*)(double)>(f)(args[0].d);
break;
case 0b110:
r = reinterpret_cast<double (*)(int64_t)>(f)(args[0].n);
break;
case 0b1000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t)>(f)(args[0].n, args[1].n);
break;
case 0b1001:
r = reinterpret_cast<int64_t (*)(int64_t, double)>(f)(args[0].n, args[1].d);
break;
case 0b1011:
r = reinterpret_cast<int64_t (*)(double, double)>(f)(args[0].d, args[1].d);
break;
case 0b1111:
r = reinterpret_cast<double (*)(double, double)>(f)(args[0].d, args[1].d);
break;
case 0b10000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t)>(f)(args[0].n, args[1].n,
args[2].n);
break;
case 0b10001:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, double)>(f)(args[0].n, args[1].n,
args[2].d);
break;
case 0b10011:
r = reinterpret_cast<int64_t (*)(int64_t, double, double)>(f)(args[0].n, args[1].d,
args[2].d);
break;
case 0b100000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n);
break;
case 0b100001:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, double)>(f)(
args[0].n, args[1].n, args[2].n, args[3].d);
break;
case 0b100110:
r = reinterpret_cast<int64_t (*)(int64_t, double, double, int64_t)>(f)(
args[0].n, args[1].d, args[2].d, args[3].n);
break;
case 0b101010:
r = reinterpret_cast<int64_t (*)(double, int, double, int64_t)>(f)(args[0].d, args[1].n,
args[2].d, args[3].n);
break;
case 0b101010:
r = reinterpret_cast<int64_t (*)(double, int, double, int64_t)>(f)(args[0].d, args[1].n,
args[2].d, args[3].n);
break;
case 0b1000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n);
break;
case 0b10000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n);
break;
case 0b100000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t,
int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n,
args[4].n, args[5].n, args[6].n);
break;
case 0b1000000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int64_t,
int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n,
args[4].n, args[5].n, args[6].n, args[7].n);
break;
default:
inst->dump();
RELEASE_ASSERT(0, "%d", mask);
break;
break;
case 0b1000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n);
break;
case 0b10000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t)>(f)(
args[0].n, args[1].n, args[2].n, args[3].n, args[4].n, args[5].n);
break;
case 0b100000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t,
int64_t)>(f)(args[0].n, args[1].n, args[2].n, args[3].n,
args[4].n, args[5].n, args[6].n);
break;
case 0b1000000000:
r = reinterpret_cast<int64_t (*)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t,
int64_t, int64_t)>(f)(args[0].n, args[1].n, args[2].n,
args[3].n, args[4].n, args[5].n,
args[6].n, args[7].n);
break;
default:
inst->dump();
RELEASE_ASSERT(0, "%d", mask);
break;
}
if (cs.getType() != g.void_)
SET(r);
if (invoke != nullptr) {
prevblock = curblock;
curblock = invoke->getNormalDest();
}
}
catch (Box* e) {
if (invoke == nullptr)
throw;
prevblock = curblock;
curblock = invoke->getUnwindDest();
landingpad_value.exc_obj = e;
landingpad_value.exc_selector
= 1; // I don't think it's possible to determine what the value should be
}
if (ci->getType() != g.void_)
SET(r);
#ifdef TIME_INTERPRETS
......@@ -647,7 +699,7 @@ Box* interpretFunction(llvm::Function* f, int nargs, Box* arg1, Box* arg2, Box*
inst->dump();
RELEASE_ASSERT(1, "");
RELEASE_ASSERT(0, "");
}
}
......
......@@ -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);
......
......@@ -238,39 +238,34 @@ extern "C" void my_assert(bool b) {
extern "C" void assertFail(BoxedModule* inModule, Box* msg) {
if (msg) {
BoxedString* tostr = str(msg);
fprintf(stderr, "AssertionError: %s\n", tostr->s.c_str());
raiseExc();
raiseExcHelper(AssertionError, "%s", tostr->s.c_str());
} else {
fprintf(stderr, "AssertionError\n");
raiseExc();
raiseExcHelper(AssertionError, NULL);
}
}
extern "C" void assertNameDefined(bool b, const char* name) {
if (!b) {
fprintf(stderr, "UnboundLocalError: local variable '%s' referenced before assignment\n", name);
raiseExc();
raiseExcHelper(UnboundLocalError, "local variable '%s' referenced before assignment", name);
}
}
extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) {
fprintf(stderr, "AttributeError: '%s' object has no attribute '%s'\n", typeName, attr);
raiseExc();
raiseExcHelper(AttributeError, "'%s' object has no attribute '%s'", typeName, attr);
}
extern "C" void raiseAttributeError(Box* obj, const char* attr) {
if (obj->cls == type_cls) {
fprintf(stderr, "AttributeError: type object '%s' has no attribute '%s'\n",
getNameOfClass(static_cast<BoxedClass*>(obj))->c_str(), attr);
// Slightly different error message:
raiseExcHelper(AttributeError, "type object '%s' has no attribute '%s'",
getNameOfClass(static_cast<BoxedClass*>(obj))->c_str(), attr);
} else {
raiseAttributeErrorStr(getTypeName(obj)->c_str(), attr);
}
raiseExc();
}
extern "C" void raiseNotIterableError(const char* typeName) {
fprintf(stderr, "TypeError: '%s' object is not iterable\n", typeName);
raiseExc();
raiseExcHelper(TypeError, "'%s' object is not iterable", typeName);
}
extern "C" void checkUnpackingLength(i64 expected, i64 given) {
......@@ -278,14 +273,13 @@ extern "C" void checkUnpackingLength(i64 expected, i64 given) {
return;
if (given > expected)
fprintf(stderr, "ValueError: too many values to unpack\n");
raiseExcHelper(ValueError, "too many values to unpack");
else {
if (given == 1)
fprintf(stderr, "ValueError: need more than %ld value to unpack\n", given);
raiseExcHelper(ValueError, "need more than %ld value to unpack", given);
else
fprintf(stderr, "ValueError: need more than %ld values to unpack\n", given);
raiseExcHelper(ValueError, "need more than %ld values to unpack", given);
}
raiseExc();
}
BoxedClass::BoxedClass(bool hasattrs, BoxedClass::Dtor dtor)
......@@ -852,9 +846,8 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) {
if (obj->cls == type_cls) {
BoxedClass* cobj = static_cast<BoxedClass*>(obj);
if (!isUserDefined(cobj)) {
fprintf(stderr, "TypeError: can't set attributes of built-in/extension type '%s'\n",
getNameOfClass(cobj)->c_str());
raiseExc();
raiseExcHelper(TypeError, "can't set attributes of built-in/extension type '%s'",
getNameOfClass(cobj)->c_str());
}
}
......@@ -961,8 +954,7 @@ extern "C" bool nonzero(Box* obj) {
bool rtn = b->n != 0;
return rtn;
} else {
fprintf(stderr, "TypeError: __nonzero__ should return bool or int, returned %s\n", getTypeName(r)->c_str());
raiseExc();
raiseExcHelper(TypeError, "__nonzero__ should return bool or int, returned %s", getTypeName(r)->c_str());
}
}
......@@ -1012,8 +1004,7 @@ extern "C" Box* repr(Box* obj) {
}
if (obj->cls != str_cls) {
fprintf(stderr, "__repr__ did not return a string!\n");
raiseExc();
raiseExcHelper(TypeError, "__repr__ did not return a string!");
}
return static_cast<BoxedString*>(obj);
}
......@@ -1047,8 +1038,7 @@ extern "C" BoxedInt* hash(Box* obj) {
Box* rtn = runtimeCall0(hash, 0);
if (rtn->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "an integer is required");
}
return static_cast<BoxedInt*>(rtn);
}
......@@ -1069,13 +1059,11 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
}
if (rtn == NULL) {
fprintf(stderr, "TypeError: object of type '%s' has no len()\n", getTypeName(obj)->c_str());
raiseExc();
raiseExcHelper(TypeError, "object of type '%s' has no len()", getTypeName(obj)->c_str());
}
if (rtn->cls != int_cls) {
fprintf(stderr, "TypeError: an integer is required\n");
raiseExc();
raiseExcHelper(TypeError, "an integer is required");
}
if (rewrite_args)
......@@ -1220,8 +1208,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
}
if (!rtn) {
fprintf(stderr, "TypeError: '%s' object is not callable\n", getTypeName(inst_attr)->c_str());
raiseExc();
raiseExcHelper(TypeError, "'%s' object is not callable", getTypeName(inst_attr)->c_str());
}
return rtn;
......@@ -1409,8 +1396,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
}
if (!rtn) {
fprintf(stderr, "TypeError: '%s' object is not callable\n", getTypeName(clsattr)->c_str());
raiseExc();
raiseExcHelper(TypeError, "'%s' object is not callable", getTypeName(clsattr)->c_str());
}
if (rewrite_args)
......@@ -1755,13 +1741,12 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
// printf("rfunc doesn't exist\n");
}
llvm::StringRef op_sym = getOpSymbol(op_type);
const char* op_sym_suffix = "";
if (inplace) {
fprintf(stderr, "TypeError: unsupported operand type(s) for %s: '%s' and '%s'\n",
getInplaceOpSymbol(op_type).c_str(), getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str());
} else {
fprintf(stderr, "TypeError: unsupported operand type(s) for %s: '%s' and '%s'\n", getOpSymbol(op_type).c_str(),
getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str());
op_sym_suffix = "=";
}
if (VERBOSITY()) {
if (inplace) {
if (irtn)
......@@ -1780,7 +1765,9 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
else
fprintf(stderr, "%s does not have %s\n", getTypeName(rhs)->c_str(), rop_name.c_str());
}
raiseExc();
raiseExcHelper(TypeError, "unsupported operand type(s) for %s%s: '%s' and '%s'", op_sym.data(), op_sym_suffix,
getTypeName(lhs)->c_str(), getTypeName(rhs)->c_str());
}
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type) {
......@@ -1893,8 +1880,7 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
ASSERT(isUserDefined(rhs->cls), "%s should probably have a __contains__", getTypeName(rhs)->c_str());
RELEASE_ASSERT(getitem == NULL, "need to try old iteration protocol");
fprintf(stderr, "TypeError: argument of type '%s' is not iterable\n", getTypeName(rhs)->c_str());
raiseExc();
raiseExcHelper(TypeError, "argument of type '%s' is not iterable", getTypeName(rhs)->c_str());
}
bool b = nonzero(contained);
......@@ -2043,6 +2029,10 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
}
extern "C" Box* getitem(Box* value, Box* slice) {
// This possibly could just be represented as a single callattr; the only tricky part
// are the error messages.
// Ex "(1)[1]" and "(1).__getitem__(1)" give different error messages.
static StatCounter slowpath_getitem("slowpath_getitem");
slowpath_getitem.log();
static std::string str_getitem("__getitem__");
......@@ -2068,14 +2058,13 @@ extern "C" Box* getitem(Box* value, Box* slice) {
if (rtn == NULL) {
// different versions of python give different error messages for this:
if (PYTHON_VERSION_MAJOR == 2 && PYTHON_VERSION_MINOR < 7) {
fprintf(stderr, "TypeError: '%s' object is unsubscriptable\n", getTypeName(value)->c_str()); // 2.6.6
raiseExcHelper(TypeError, "'%s' object is unsubscriptable", getTypeName(value)->c_str()); // 2.6.6
} else if (PYTHON_VERSION_MAJOR == 2 && PYTHON_VERSION_MINOR == 7 && PYTHON_VERSION_MICRO < 3) {
fprintf(stderr, "TypeError: '%s' object is not subscriptable\n", getTypeName(value)->c_str()); // 2.7.1
raiseExcHelper(TypeError, "'%s' object is not subscriptable", getTypeName(value)->c_str()); // 2.7.1
} else {
fprintf(stderr, "TypeError: '%s' object has no attribute '__getitem__'\n",
getTypeName(value)->c_str()); // 2.7.3
raiseExcHelper(TypeError, "'%s' object has no attribute '__getitem__'",
getTypeName(value)->c_str()); // 2.7.3
}
raiseExc();
}
if (rewriter.get())
......@@ -2110,8 +2099,7 @@ extern "C" void setitem(Box* target, Box* slice, Box* value) {
}
if (rtn == NULL) {
fprintf(stderr, "TypeError: '%s' object does not support item assignment\n", getTypeName(target)->c_str());
raiseExc();
raiseExcHelper(TypeError, "'%s' object does not support item assignment", getTypeName(target)->c_str());
}
if (rewriter.get()) {
......@@ -2128,8 +2116,7 @@ static Box* makeHCBox(ObjectFlavor* flavor, BoxedClass* cls) {
// For use on __init__ return values
static void assertInitNone(Box* obj) {
if (obj != None) {
fprintf(stderr, "TypeError: __init__() should return None, not '%s'\n", getTypeName(obj)->c_str());
raiseExc();
raiseExcHelper(TypeError, "__init__() should return None, not '%s'", getTypeName(obj)->c_str());
}
}
......@@ -2160,9 +2147,8 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
Box* cls = arg1;
if (cls->cls != type_cls) {
fprintf(stderr, "TypeError: descriptor '__call__' requires a 'type' object but received an '%s'\n",
getTypeName(cls)->c_str());
raiseExc();
raiseExcHelper(TypeError, "descriptor '__call__' requires a 'type' object but received an '%s'",
getTypeName(cls)->c_str());
}
BoxedClass* ccls = static_cast<BoxedClass*>(cls);
......@@ -2289,7 +2275,7 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
// Not sure what type of object to make here; maybe an HCBox? would be disastrous if it ever
// made the wrong one though, so just err for now:
fprintf(stderr, "no __new__ defined for %s!\n", getNameOfClass(ccls)->c_str());
raiseExc();
abort();
}
}
......@@ -2333,8 +2319,7 @@ Box* typeCallInternal(CallRewriteArgs* rewrite_args, int64_t nargs, Box* arg1, B
assertInitNone(initrtn);
} else {
if (new_attr == NULL && nargs != 1) {
fprintf(stderr, "TypeError: object.__new__() takes no parameters\n");
raiseExc();
raiseExcHelper(TypeError, "object.__new__() takes no parameters");
}
}
......@@ -2433,10 +2418,9 @@ extern "C" Box* getGlobal(BoxedModule* m, std::string* name, bool from_global) {
}
if (from_global)
fprintf(stderr, "NameError: name '%s' is not defined\n", name->c_str());
raiseExcHelper(NameError, "name '%s' is not defined", name->c_str());
else
fprintf(stderr, "NameError: global name '%s' is not defined\n", name->c_str());
raiseExc();
raiseExcHelper(NameError, "global name '%s' is not defined", name->c_str());
}
// TODO I feel like importing should go somewhere else; it's more closely tied to codegen
......@@ -2454,8 +2438,7 @@ extern "C" Box* import(const std::string* name) {
BoxedList* sys_path = getSysPath();
if (sys_path->cls != list_cls) {
fprintf(stderr, "RuntimeError: sys.path must be a list of directory name\n");
raiseExc();
raiseExcHelper(RuntimeError, "sys.path must be a list of directory name");
}
llvm::SmallString<128> joined_path;
......@@ -2492,7 +2475,6 @@ extern "C" Box* import(const std::string* name) {
return getTestModule();
}
fprintf(stderr, "ImportError: No module named %s\n", name->c_str());
raiseExc();
raiseExcHelper(ImportError, "No module named %s", name->c_str());
}
}
......@@ -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