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:
}
extern "C" Py_ssize_t PyObject_Size(PyObject* o) noexcept {
try {
return len(o)->n;
} catch (ExcInfo e) {
setCAPIException(e);
BoxedInt* r = lenInternal<ExceptionStyle::CAPI>(o, NULL);
if (!r)
return -1;
}
return r->n;
}
extern "C" PyObject* PyObject_GetIter(PyObject* o) noexcept {
......
......@@ -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 {
try {
Box* r = getattrInternal(o, internStringMortal(attr), NULL);
Box* r = getattrInternal<ExceptionStyle::CXX>(o, internStringMortal(attr), NULL);
if (!r)
PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name, attr);
return r;
......
......@@ -532,8 +532,14 @@ static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** at
}
Box* obj = typeLookup(self->cls, (BoxedString*)*attrobj, NULL);
if (obj)
return processDescriptor(obj, self, self->cls);
if (obj) {
try {
return processDescriptor(obj, self, self->cls);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
return obj;
}
......
......@@ -68,6 +68,13 @@ enum class EffortLevel {
MAXIMAL = 3,
};
namespace ExceptionStyle {
enum ExceptionStyle {
CAPI,
CXX,
};
};
class CompilerType;
template <class V> class ValuedCompilerType;
typedef ValuedCompilerType<llvm::Value*> ConcreteCompilerType;
......
......@@ -452,24 +452,14 @@ Box* getattrFunc(Box* obj, Box* _str, Box* default_value) {
raiseExcHelper(TypeError, "getattr(): attribute name must be string");
}
BoxedString* str = static_cast<BoxedString*>(_str);
internStringMortalInplace(str);
Box* rtn = NULL;
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());
Box* rtn = PyObject_GetAttr(obj, _str);
if (rtn == NULL && default_value != NULL && PyErr_ExceptionMatches(AttributeError)) {
PyErr_Clear();
return default_value;
}
if (!rtn)
throwCAPIException();
return rtn;
}
......@@ -499,7 +489,7 @@ Box* hasattr(Box* obj, Box* _str) {
Box* attr;
try {
attr = getattrInternal(obj, str, NULL);
attr = getattrInternal<ExceptionStyle::CXX>(obj, str, NULL);
} catch (ExcInfo e) {
if (e.matches(Exception))
return False;
......
......@@ -204,13 +204,29 @@ done:
}
extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept {
try {
return getattrMaybeNonstring(o, attr_name);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr) noexcept {
if (!PyString_Check(attr)) {
if (PyUnicode_Check(attr)) {
attr = _PyUnicode_AsDefaultEncodedString(attr, NULL);
if (attr == 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 {
......@@ -441,12 +457,7 @@ done:
extern "C" PyObject* PyObject_GetItem(PyObject* o, PyObject* key) noexcept {
try {
return getitem(o, key);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
return getitemInternal<ExceptionStyle::CAPI>(o, key, NULL);
}
extern "C" int PyObject_SetItem(PyObject* o, PyObject* key, PyObject* v) noexcept {
......
......@@ -46,7 +46,7 @@ static void propertyDocCopy(BoxedProperty* prop, Box* fget) {
static BoxedString* doc_str = internStringImmortal("__doc__");
try {
get_doc = getattrInternal(fget, doc_str, NULL);
get_doc = getattrInternal<ExceptionStyle::CXX>(fget, doc_str, NULL);
} catch (ExcInfo e) {
if (!e.matches(Exception)) {
throw e;
......
......@@ -27,6 +27,9 @@
namespace pyston {
using namespace pyston::ExceptionStyle;
using pyston::ExceptionStyle::ExceptionStyle;
Box* dictRepr(BoxedDict* self) {
std::vector<char> chars;
chars.push_back('{');
......@@ -183,23 +186,54 @@ extern "C" int PyDict_Update(PyObject* a, PyObject* b) noexcept {
return PyDict_Merge(a, b, 1);
}
Box* dictGetitem(BoxedDict* self, Box* k) {
if (!isSubclass(self->cls, dict_cls))
raiseExcHelper(TypeError, "descriptor '__getitem__' requires a 'dict' object but received a '%s'",
getTypeName(self));
template <enum ExceptionStyle S> Box* dictGetitem(BoxedDict* self, Box* k) noexcept(S == CAPI) {
if (!isSubclass(self->cls, dict_cls)) {
if (S == CAPI) {
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()) {
// Try calling __missing__ if this is a subclass
if (self->cls != dict_cls) {
static BoxedString* missing_str = internStringImmortal("__missing__");
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)
return r;
}
raiseExcHelper(KeyError, k);
if (S == CAPI) {
PyErr_SetObject(KeyError, k);
return NULL;
} else
raiseExcHelper(KeyError, k);
}
return it->second;
}
......@@ -588,7 +622,7 @@ Box* dictUpdate(BoxedDict* self, BoxedTuple* args, BoxedDict* kwargs) {
if (args->size()) {
Box* arg = args->elts[0];
static BoxedString* keys_str = internStringImmortal("keys");
if (getattrInternal(arg, keys_str, NULL)) {
if (getattrInternal<ExceptionStyle::CXX>(arg, keys_str, NULL)) {
dictMerge(self, arg);
} else {
dictMergeFromSeq2(self, arg);
......@@ -715,7 +749,7 @@ void setupDict() {
dict_cls->giveAttr("setdefault",
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("__delitem__", new BoxedFunction(boxRTFunction((void*)dictDelitem, UNKNOWN, 2)));
dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2)));
......@@ -747,6 +781,8 @@ void setupDict() {
dict_cls->tp_init = dict_init;
dict_cls->tp_repr = dict_repr;
dict_cls->tp_as_mapping->mp_subscript = (binaryfunc)dictGetitem<CAPI>;
dict_keys_cls->giveAttr(
"__iter__", new BoxedFunction(boxRTFunction((void*)dictViewKeysIter, typeFromClass(dict_iterator_cls), 1)));
dict_keys_cls->freeze();
......
......@@ -382,7 +382,7 @@ static Box* importSub(const std::string& name, const std::string& full_name, Box
path_list = NULL;
} else {
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) {
return None;
}
......@@ -562,7 +562,7 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
static BoxedString* path_str = internStringImmortal("__path__");
Box* pathlist = NULL;
try {
pathlist = getattrInternal(module, path_str, NULL);
pathlist = getattrInternal<ExceptionStyle::CXX>(module, path_str, NULL);
} catch (ExcInfo e) {
if (!e.matches(AttributeError))
throw e;
......@@ -584,14 +584,14 @@ static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool re
continue;
static BoxedString* all_str = internStringImmortal("__all__");
Box* all = getattrInternal(module, all_str, NULL);
Box* all = getattrInternal<ExceptionStyle::CXX>(module, all_str, NULL);
if (all) {
ensureFromlist(module, all, buf, true);
}
continue;
}
Box* attr = getattrInternal(module, s, NULL);
Box* attr = getattrInternal<ExceptionStyle::CXX>(module, s, NULL);
if (attr != NULL)
continue;
......
......@@ -49,42 +49,24 @@ bool seqiterHasnextUnboxed(Box* s) {
return false;
}
Box* next;
try {
next = getitem(self->b, boxInt(self->idx));
} catch (ExcInfo e) {
if (e.matches(IndexError) || e.matches(StopIteration)) {
Box* next = getitemInternal<ExceptionStyle::CAPI>(self->b, boxInt(self->idx), NULL);
if (!next) {
if (PyErr_ExceptionMatches(IndexError) || PyErr_ExceptionMatches(StopIteration)) {
PyErr_Clear();
self->b = NULL;
return false;
} else
throw e;
} else {
throwCAPIException();
}
}
self->idx++;
self->next = next;
return true;
}
Box* seqiterHasnext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
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;
return boxBool(seqiterHasnextUnboxed(s));
}
Box* seqreviterHasnext(Box* s) {
......
This diff is collapsed.
......@@ -114,6 +114,13 @@ struct CallRewriteArgs;
Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3,
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* arg3, Box** args, const std::vector<BoxedString*>* keyword_names);
......@@ -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
// __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
// data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or
......
......@@ -97,6 +97,24 @@ struct CallRewriteArgs {
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 {
Rewriter* rewriter;
RewriterVar* lhs;
......
......@@ -1654,7 +1654,7 @@ static Box* instancemethodRepr(Box* b) {
const char* sfuncname = "?", * sklassname = "?";
static BoxedString* name_str = internStringImmortal("__name__");
funcname = getattrInternal(func, name_str, NULL);
funcname = getattrInternal<ExceptionStyle::CXX>(func, name_str, NULL);
if (funcname != NULL) {
if (!PyString_Check(funcname)) {
......@@ -1666,7 +1666,7 @@ static Box* instancemethodRepr(Box* b) {
if (klass == NULL) {
klassname = NULL;
} else {
klassname = getattrInternal(klass, name_str, NULL);
klassname = getattrInternal<ExceptionStyle::CXX>(klass, name_str, NULL);
if (klassname != NULL) {
if (!PyString_Check(klassname)) {
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