Commit 75e203a2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #768 from kmod/exceptions2

start templatizing the runtime to be able to choose exception styles
parents 52a94c1d 8170d8ae
...@@ -732,12 +732,10 @@ exit: ...@@ -732,12 +732,10 @@ exit:
} }
extern "C" Py_ssize_t PyObject_Size(PyObject* o) noexcept { extern "C" Py_ssize_t PyObject_Size(PyObject* o) noexcept {
try { BoxedInt* r = lenInternal<ExceptionStyle::CAPI>(o, NULL);
return len(o)->n; if (!r)
} catch (ExcInfo e) {
setCAPIException(e);
return -1; return -1;
} return r->n;
} }
extern "C" PyObject* PyObject_GetIter(PyObject* o) noexcept { extern "C" PyObject* PyObject_GetIter(PyObject* o) noexcept {
......
...@@ -534,7 +534,7 @@ extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w ...@@ -534,7 +534,7 @@ extern "C" int PyObject_SetAttrString(PyObject* v, const char* name, PyObject* w
extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) noexcept { extern "C" PyObject* PyObject_GetAttrString(PyObject* o, const char* attr) noexcept {
try { try {
Box* r = getattrInternal(o, internStringMortal(attr), NULL); Box* r = getattrInternal<ExceptionStyle::CXX>(o, internStringMortal(attr), NULL);
if (!r) if (!r)
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name, attr); PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name, attr);
return r; return r;
......
...@@ -532,8 +532,14 @@ static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** at ...@@ -532,8 +532,14 @@ static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** at
} }
Box* obj = typeLookup(self->cls, (BoxedString*)*attrobj, NULL); Box* obj = typeLookup(self->cls, (BoxedString*)*attrobj, NULL);
if (obj) if (obj) {
return processDescriptor(obj, self, self->cls); try {
return processDescriptor(obj, self, self->cls);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
return obj; return obj;
} }
......
...@@ -68,6 +68,13 @@ enum class EffortLevel { ...@@ -68,6 +68,13 @@ enum class EffortLevel {
MAXIMAL = 3, MAXIMAL = 3,
}; };
namespace ExceptionStyle {
enum ExceptionStyle {
CAPI,
CXX,
};
};
class CompilerType; class CompilerType;
template <class V> class ValuedCompilerType; template <class V> class ValuedCompilerType;
typedef ValuedCompilerType<llvm::Value*> ConcreteCompilerType; typedef ValuedCompilerType<llvm::Value*> ConcreteCompilerType;
......
...@@ -452,24 +452,14 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) { ...@@ -452,24 +452,14 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
raiseExcHelper(TypeError, "getattr(): attribute name must be string"); raiseExcHelper(TypeError, "getattr(): attribute name must be string");
} }
BoxedString* str = static_cast<BoxedString*>(_str); Box* rtn = PyObject_GetAttr(obj, _str);
internStringMortalInplace(str); if (rtn == NULL && default_value != NULL && PyErr_ExceptionMatches(AttributeError)) {
PyErr_Clear();
Box* rtn = NULL; return default_value;
try {
rtn = getattrInternal(obj, str, NULL);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
throw e;
}
if (!rtn) {
if (default_value)
return default_value;
else
raiseExcHelper(AttributeError, "'%s' object has no attribute '%s'", getTypeName(obj), str->data());
} }
if (!rtn)
throwCAPIException();
return rtn; return rtn;
} }
...@@ -499,7 +489,7 @@ Box* hasattr(Box* obj, Box* _str) { ...@@ -499,7 +489,7 @@ Box* hasattr(Box* obj, Box* _str) {
Box* attr; Box* attr;
try { try {
attr = getattrInternal(obj, str, NULL); attr = getattrInternal<ExceptionStyle::CXX>(obj, str, NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (e.matches(Exception)) if (e.matches(Exception))
return False; return False;
......
...@@ -204,13 +204,29 @@ done: ...@@ -204,13 +204,29 @@ done:
} }
extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept { extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr) noexcept {
try { if (!PyString_Check(attr)) {
return getattrMaybeNonstring(o, attr_name); if (PyUnicode_Check(attr)) {
} catch (ExcInfo e) { attr = _PyUnicode_AsDefaultEncodedString(attr, NULL);
setCAPIException(e); if (attr == NULL)
return NULL; return NULL;
} else {
PyErr_Format(TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(attr)->tp_name);
return NULL;
}
} }
BoxedString* s = static_cast<BoxedString*>(attr);
internStringMortalInplace(s);
Box* r = getattrInternal<ExceptionStyle::CAPI>(o, s, NULL);
if (!r && !PyErr_Occurred()) {
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name,
PyString_AS_STRING(attr));
}
return r;
} }
extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept { extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept {
...@@ -441,12 +457,7 @@ done: ...@@ -441,12 +457,7 @@ done:
extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) noexcept { extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) noexcept {
try { return getitemInternal<ExceptionStyle::CAPI>(o, key, NULL);
return getitem(o, key);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} }
extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) noexcept { extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) noexcept {
......
...@@ -46,7 +46,7 @@ static void propertyDocCopy(BoxedProperty* prop, Box* fget) { ...@@ -46,7 +46,7 @@ static void propertyDocCopy(BoxedProperty* prop, Box* fget) {
static BoxedString* doc_str = internStringImmortal("__doc__"); static BoxedString* doc_str = internStringImmortal("__doc__");
try { try {
get_doc = getattrInternal(fget, doc_str, NULL); get_doc = getattrInternal<ExceptionStyle::CXX>(fget, doc_str, NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (!e.matches(Exception)) { if (!e.matches(Exception)) {
throw e; throw e;
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
namespace pyston { namespace pyston {
using namespace pyston::ExceptionStyle;
using pyston::ExceptionStyle::ExceptionStyle;
Box* dictRepr(BoxedDict* self) { Box* dictRepr(BoxedDict* self) {
std::vector<char> chars; std::vector<char> chars;
chars.push_back('{'); chars.push_back('{');
...@@ -183,23 +186,54 @@ extern "C" int PyDict_Update(PyObject* a, PyObject* b) noexcept { ...@@ -183,23 +186,54 @@ extern "C" int PyDict_Update(PyObject* a, PyObject* b) noexcept {
return PyDict_Merge(a, b, 1); return PyDict_Merge(a, b, 1);
} }
Box* dictGetitem(BoxedDict* self, Box* k) { template <enum ExceptionStyle S> Box* dictGetitem(BoxedDict* self, Box* k) noexcept(S == CAPI) {
if (!isSubclass(self->cls, dict_cls)) if (!isSubclass(self->cls, dict_cls)) {
raiseExcHelper(TypeError, "descriptor '__getitem__' requires a 'dict' object but received a '%s'", if (S == CAPI) {
getTypeName(self)); PyErr_Format(TypeError, "descriptor '__getitem__' requires a 'dict' object but received a '%s'",
getTypeName(self));
return NULL;
} else {
raiseExcHelper(TypeError, "descriptor '__getitem__' requires a 'dict' object but received a '%s'",
getTypeName(self));
}
}
BoxedDict::DictMap::iterator it;
try {
it = self->d.find(k);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else {
throw e;
}
}
auto it = self->d.find(k);
if (it == self->d.end()) { if (it == self->d.end()) {
// Try calling __missing__ if this is a subclass // Try calling __missing__ if this is a subclass
if (self->cls != dict_cls) { if (self->cls != dict_cls) {
static BoxedString* missing_str = internStringImmortal("__missing__"); static BoxedString* missing_str = internStringImmortal("__missing__");
CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(1) }; CallattrFlags callattr_flags{.cls_only = true, .null_on_nonexistent = true, .argspec = ArgPassSpec(1) };
Box* r = callattr(self, missing_str, callattr_flags, k, NULL, NULL, NULL, NULL); Box* r;
try {
r = callattr(self, missing_str, callattr_flags, k, NULL, NULL, NULL, NULL);
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else
throw e;
}
if (r) if (r)
return r; return r;
} }
raiseExcHelper(KeyError, k); if (S == CAPI) {
PyErr_SetObject(KeyError, k);
return NULL;
} else
raiseExcHelper(KeyError, k);
} }
return it->second; return it->second;
} }
...@@ -588,7 +622,7 @@ Box* dictUpdate(BoxedDict* self, BoxedTuple* args, BoxedDict* kwargs) { ...@@ -588,7 +622,7 @@ Box* dictUpdate(BoxedDict* self, BoxedTuple* args, BoxedDict* kwargs) {
if (args->size()) { if (args->size()) {
Box* arg = args->elts[0]; Box* arg = args->elts[0];
static BoxedString* keys_str = internStringImmortal("keys"); static BoxedString* keys_str = internStringImmortal("keys");
if (getattrInternal(arg, keys_str, NULL)) { if (getattrInternal<ExceptionStyle::CXX>(arg, keys_str, NULL)) {
dictMerge(self, arg); dictMerge(self, arg);
} else { } else {
dictMergeFromSeq2(self, arg); dictMergeFromSeq2(self, arg);
...@@ -715,7 +749,7 @@ void setupDict() { ...@@ -715,7 +749,7 @@ void setupDict() {
dict_cls->giveAttr("setdefault", dict_cls->giveAttr("setdefault",
new BoxedFunction(boxRTFunction((void*)dictSetdefault, UNKNOWN, 3, 1, false, false), { None })); new BoxedFunction(boxRTFunction((void*)dictSetdefault, UNKNOWN, 3, 1, false, false), { None }));
dict_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)dictGetitem, UNKNOWN, 2))); dict_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)dictGetitem<CXX>, UNKNOWN, 2)));
dict_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)dictSetitem, NONE, 3))); dict_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)dictSetitem, NONE, 3)));
dict_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)dictDelitem, UNKNOWN, 2))); dict_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)dictDelitem, UNKNOWN, 2)));
dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2))); dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2)));
...@@ -747,6 +781,8 @@ void setupDict() { ...@@ -747,6 +781,8 @@ void setupDict() {
dict_cls->tp_init = dict_init; dict_cls->tp_init = dict_init;
dict_cls->tp_repr = dict_repr; dict_cls->tp_repr = dict_repr;
dict_cls->tp_as_mapping->mp_subscript = (binaryfunc)dictGetitem<CAPI>;
dict_keys_cls->giveAttr( dict_keys_cls->giveAttr(
"__iter__", new BoxedFunction(boxRTFunction((void*)dictViewKeysIter, typeFromClass(dict_iterator_cls), 1))); "__iter__", new BoxedFunction(boxRTFunction((void*)dictViewKeysIter, typeFromClass(dict_iterator_cls), 1)));
dict_keys_cls->freeze(); dict_keys_cls->freeze();
......
...@@ -382,7 +382,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box ...@@ -382,7 +382,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box
path_list = NULL; path_list = NULL;
} else { } else {
static BoxedString* path_str = internStringImmortal("__path__"); static BoxedString* path_str = internStringImmortal("__path__");
path_list = static_cast<BoxedList*>(getattrInternal(parent_module, path_str, NULL)); path_list = static_cast<BoxedList*>(getattrInternal<ExceptionStyle::CXX>(parent_module, path_str, NULL));
if (path_list == NULL || path_list->cls != list_cls) { if (path_list == NULL || path_list->cls != list_cls) {
return None; return None;
} }
...@@ -562,7 +562,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re ...@@ -562,7 +562,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
static BoxedString* path_str = internStringImmortal("__path__"); static BoxedString* path_str = internStringImmortal("__path__");
Box* pathlist = NULL; Box* pathlist = NULL;
try { try {
pathlist = getattrInternal(module, path_str, NULL); pathlist = getattrInternal<ExceptionStyle::CXX>(module, path_str, NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
if (!e.matches(AttributeError)) if (!e.matches(AttributeError))
throw e; throw e;
...@@ -584,14 +584,14 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re ...@@ -584,14 +584,14 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
continue; continue;
static BoxedString* all_str = internStringImmortal("__all__"); static BoxedString* all_str = internStringImmortal("__all__");
Box* all = getattrInternal(module, all_str, NULL); Box* all = getattrInternal<ExceptionStyle::CXX>(module, all_str, NULL);
if (all) { if (all) {
ensureFromlist(module, all, buf, true); ensureFromlist(module, all, buf, true);
} }
continue; continue;
} }
Box* attr = getattrInternal(module, s, NULL); Box* attr = getattrInternal<ExceptionStyle::CXX>(module, s, NULL);
if (attr != NULL) if (attr != NULL)
continue; continue;
......
...@@ -49,42 +49,24 @@ bool seqiterHasnextUnboxed(Box* s) { ...@@ -49,42 +49,24 @@ bool seqiterHasnextUnboxed(Box* s) {
return false; return false;
} }
Box* next; Box* next = getitemInternal<ExceptionStyle::CAPI>(self->b, boxInt(self->idx), NULL);
try { if (!next) {
next = getitem(self->b, boxInt(self->idx)); if (PyErr_ExceptionMatches(IndexError) || PyErr_ExceptionMatches(StopIteration)) {
} catch (ExcInfo e) { PyErr_Clear();
if (e.matches(IndexError) || e.matches(StopIteration)) {
self->b = NULL; self->b = NULL;
return false; return false;
} else } else {
throw e; throwCAPIException();
}
} }
self->idx++; self->idx++;
self->next = next; self->next = next;
return true; return true;
} }
Box* seqiterHasnext(Box* s) { Box* seqiterHasnext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, ""); return boxBool(seqiterHasnextUnboxed(s));
BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s);
if (!self->b) {
return False;
}
Box* next;
try {
next = getitem(self->b, boxInt(self->idx));
} catch (ExcInfo e) {
if (e.matches(IndexError) || e.matches(StopIteration)) {
self->b = NULL;
return False;
} else
throw e;
}
self->idx++;
self->next = next;
return True;
} }
Box* seqreviterHasnext(Box* s) { Box* seqreviterHasnext(Box* s) {
......
This diff is collapsed.
...@@ -114,6 +114,13 @@ struct CallRewriteArgs; ...@@ -114,6 +114,13 @@ struct CallRewriteArgs;
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
Box** args, const std::vector<BoxedString*>* keyword_names); Box** args, const std::vector<BoxedString*>* keyword_names);
struct GetitemRewriteArgs;
template <ExceptionStyle::ExceptionStyle S>
Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI);
struct LenRewriteArgs;
template <ExceptionStyle::ExceptionStyle S>
BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI);
Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names); Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names);
...@@ -134,7 +141,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -134,7 +141,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
// This is the equivalent of PyObject_GetAttr. Unlike getattrInternalGeneric, it checks for custom __getattr__ or // This is the equivalent of PyObject_GetAttr. Unlike getattrInternalGeneric, it checks for custom __getattr__ or
// __getattribute__ methods. // __getattribute__ methods.
Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args); template <ExceptionStyle::ExceptionStyle S>
Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI);
// This is the equivalent of PyObject_GenericGetAttr, which performs the default lookup rules for getattr() (check for // This is the equivalent of PyObject_GenericGetAttr, which performs the default lookup rules for getattr() (check for
// data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or // data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or
......
...@@ -97,6 +97,24 @@ struct CallRewriteArgs { ...@@ -97,6 +97,24 @@ struct CallRewriteArgs {
out_rtn(NULL) {} out_rtn(NULL) {}
}; };
struct GetitemRewriteArgs {
Rewriter* rewriter;
RewriterVar* target;
RewriterVar* slice;
Location destination;
bool out_success;
RewriterVar* out_rtn;
GetitemRewriteArgs(Rewriter* rewriter, RewriterVar* target, RewriterVar* slice, Location destination)
: rewriter(rewriter),
target(target),
slice(slice),
destination(destination),
out_success(false),
out_rtn(NULL) {}
};
struct BinopRewriteArgs { struct BinopRewriteArgs {
Rewriter* rewriter; Rewriter* rewriter;
RewriterVar* lhs; RewriterVar* lhs;
......
...@@ -1654,7 +1654,7 @@ static Box* instancemethodRepr(Box* b) { ...@@ -1654,7 +1654,7 @@ static Box* instancemethodRepr(Box* b) {
const char* sfuncname = "?", * sklassname = "?"; const char* sfuncname = "?", * sklassname = "?";
static BoxedString* name_str = internStringImmortal("__name__"); static BoxedString* name_str = internStringImmortal("__name__");
funcname = getattrInternal(func, name_str, NULL); funcname = getattrInternal<ExceptionStyle::CXX>(func, name_str, NULL);
if (funcname != NULL) { if (funcname != NULL) {
if (!PyString_Check(funcname)) { if (!PyString_Check(funcname)) {
...@@ -1666,7 +1666,7 @@ static Box* instancemethodRepr(Box* b) { ...@@ -1666,7 +1666,7 @@ static Box* instancemethodRepr(Box* b) {
if (klass == NULL) { if (klass == NULL) {
klassname = NULL; klassname = NULL;
} else { } else {
klassname = getattrInternal(klass, name_str, NULL); klassname = getattrInternal<ExceptionStyle::CXX>(klass, name_str, NULL);
if (klassname != NULL) { if (klassname != NULL) {
if (!PyString_Check(klassname)) { if (!PyString_Check(klassname)) {
klassname = NULL; klassname = NULL;
......
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