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) {
......
......@@ -59,6 +59,9 @@
namespace pyston {
using namespace pyston::ExceptionStyle;
using pyston::ExceptionStyle::ExceptionStyle;
static const std::string delitem_str("__delitem__");
static const std::string getattribute_str("__getattribute__");
static const std::string getattr_str("__getattr__");
......@@ -196,7 +199,7 @@ extern "C" bool softspace(Box* b, bool newval) {
bool r;
Box* gotten = NULL;
try {
Box* gotten = getattrInternal(b, softspace_str, NULL);
Box* gotten = getattrInternal<CXX>(b, softspace_str, NULL);
if (!gotten) {
r = 0;
} else {
......@@ -1470,10 +1473,16 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
return NULL;
}
template <enum ExceptionStyle S>
Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call,
Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == ExceptionStyle::CAPI) {
assert(gc::isValidGCObject(attr));
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
if (!cls_only) {
BoxedClass* cls = obj->cls;
......@@ -1486,10 +1495,20 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
STAT_TIMER(t0, "us_timer_slowpath_tpgetattro", 10);
if (obj->cls->tp_getattro == slot_tp_getattr_hook) {
return slotTpGetattrHookInternal(obj, attr, rewrite_args);
if (S == CAPI) {
assert(!rewrite_args && "implement me");
return obj->cls->tp_getattro(obj, attr);
} else {
return slotTpGetattrHookInternal(obj, attr, rewrite_args);
}
}
Box* r = obj->cls->tp_getattro(obj, attr);
if (S == CAPI) {
assert(!rewrite_args && "implement me");
return r;
}
if (!r)
throwCAPIException();
......@@ -1517,20 +1536,35 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
STAT_TIMER(t0, "us_timer_slowpath_tpgetattr", 10);
assert(attr->data()[attr->size()] == '\0');
Box* r = obj->cls->tp_getattr(obj, const_cast<char*>(attr->data()));
if (!r)
throwCAPIException();
return r;
if (S == CAPI) {
return r;
} else {
if (!r)
throwCAPIException();
return r;
}
}
}
return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out);
if (S == CAPI) {
try {
return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} else {
return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out);
}
}
inline Box* getclsattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
return getattrInternalEx(obj, attr, rewrite_args,
/* cls_only */ true,
/* for_call */ false, NULL, NULL);
return getattrInternalEx<CXX>(obj, attr, rewrite_args,
/* cls_only */ true,
/* for_call */ false, NULL, NULL);
}
extern "C" Box* getclsattr(Box* obj, BoxedString* attr) {
......@@ -1935,8 +1969,8 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
// TODO this shouldn't go here; it should be in instancemethod_cls->tp_getattr[o]
if (obj->cls == instancemethod_cls) {
assert(!rewrite_args || !rewrite_args->out_success);
return getattrInternalEx(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call,
bind_obj_out, NULL);
return getattrInternalEx<CXX>(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call,
bind_obj_out, NULL);
}
if (rewrite_args) {
......@@ -1945,12 +1979,18 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
return NULL;
}
Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
return getattrInternalEx(obj, attr, rewrite_args,
/* cls_only */ false,
/* for_call */ false, NULL, NULL);
template <enum ExceptionStyle S>
Box* getattrInternal(Box* obj, BoxedString* attr,
GetattrRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI) {
return getattrInternalEx<S>(obj, attr, rewrite_args,
/* cls_only */ false,
/* for_call */ false, NULL, NULL);
}
// Force instantiation of the template
template Box* getattrInternal<CAPI>(Box*, BoxedString*, GetattrRewriteArgs*);
template Box* getattrInternal<CXX>(Box*, BoxedString*, GetattrRewriteArgs*);
Box* getattrMaybeNonstring(Box* obj, Box* attr) {
if (!PyString_Check(attr)) {
if (PyUnicode_Check(attr)) {
......@@ -1964,7 +2004,11 @@ Box* getattrMaybeNonstring(Box* obj, Box* attr) {
BoxedString* s = static_cast<BoxedString*>(attr);
internStringMortalInplace(s);
return getattr(obj, s);
Box* r = getattrInternal<CXX>(obj, s, NULL);
if (!r)
raiseAttributeError(obj, s->s());
return r;
}
extern "C" Box* getattr(Box* obj, BoxedString* attr) {
......@@ -2018,7 +2062,7 @@ extern "C" Box* getattr(Box* obj, BoxedString* attr) {
else
dest = rewriter->getReturnDestination();
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), dest);
val = getattrInternal(obj, attr, &rewrite_args);
val = getattrInternal<CXX>(obj, attr, &rewrite_args);
if (rewrite_args.out_success) {
if (!val) {
......@@ -2040,7 +2084,7 @@ extern "C" Box* getattr(Box* obj, BoxedString* attr) {
}
}
} else {
val = getattrInternal(obj, attr, NULL);
val = getattrInternal<CXX>(obj, attr, NULL);
}
if (val) {
......@@ -2550,13 +2594,21 @@ extern "C" BoxedInt* hash(Box* obj) {
return new BoxedInt(r);
}
extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
template <enum ExceptionStyle S>
BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI) {
static BoxedString* len_str = internStringImmortal("__len__");
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
// Corresponds to the first part of PyObject_Size:
PySequenceMethods* m = obj->cls->tp_as_sequence;
if (m != NULL && m->sq_length != NULL && m->sq_length != slot_sq_length) {
if (rewrite_args) {
assert(S == CXX);
RewriterVar* r_obj = rewrite_args->obj;
RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls));
RewriterVar* r_m = r_cls->getAttr(offsetof(BoxedClass, tp_as_sequence));
......@@ -2577,29 +2629,50 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
}
int r = (*m->sq_length)(obj);
if (r == -1)
throwCAPIException();
if (r == -1) {
if (S == CAPI)
return NULL;
else
throwCAPIException();
}
return (BoxedInt*)boxInt(r);
}
Box* rtn;
if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0));
if (!crewrite_args.out_success)
rewrite_args = NULL;
else if (rtn)
rewrite_args->out_rtn = crewrite_args.out_rtn;
} else {
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, NULL, ArgPassSpec(0));
try {
if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0));
if (!crewrite_args.out_success)
rewrite_args = NULL;
else if (rtn)
rewrite_args->out_rtn = crewrite_args.out_rtn;
} else {
rtn = callattrInternal0(obj, len_str, CLASS_ONLY, NULL, ArgPassSpec(0));
}
} catch (ExcInfo e) {
if (S == CAPI) {
setCAPIException(e);
return NULL;
} else {
throw e;
}
}
if (rtn == NULL) {
raiseExcHelper(TypeError, "object of type '%s' has no len()", getTypeName(obj));
if (S == CAPI) {
PyErr_Format(TypeError, "object of type '%s' has no len()", getTypeName(obj));
return NULL;
} else
raiseExcHelper(TypeError, "object of type '%s' has no len()", getTypeName(obj));
}
if (rtn->cls != int_cls) {
raiseExcHelper(TypeError, "an integer is required");
if (S == CAPI) {
PyErr_Format(TypeError, "an integer is required");
return NULL;
} else
raiseExcHelper(TypeError, "an integer is required");
}
if (rewrite_args)
......@@ -2607,6 +2680,10 @@ extern "C" BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) {
return static_cast<BoxedInt*>(rtn);
}
// force template instantiation:
template BoxedInt* lenInternal<CAPI>(Box*, LenRewriteArgs*);
template BoxedInt* lenInternal<CXX>(Box*, LenRewriteArgs*);
Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
Box* arg3, Box** args, const std::vector<BoxedString*>* keyword_names) {
if (argspec != ArgPassSpec(1))
......@@ -2614,7 +2691,7 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg
if (rewrite_args) {
LenRewriteArgs lrewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
Box* rtn = lenInternal(arg1, &lrewrite_args);
Box* rtn = lenInternal<CXX>(arg1, &lrewrite_args);
if (!lrewrite_args.out_success) {
rewrite_args = 0;
} else {
......@@ -2623,7 +2700,7 @@ Box* lenCallInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, Arg
}
return rtn;
}
return lenInternal(arg1, NULL);
return lenInternal<CXX>(arg1, NULL);
}
extern "C" BoxedInt* len(Box* obj) {
......@@ -2632,7 +2709,7 @@ extern "C" BoxedInt* len(Box* obj) {
static StatCounter slowpath_len("slowpath_len");
slowpath_len.log();
return lenInternal(obj, NULL);
return lenInternal<CXX>(obj, NULL);
}
extern "C" i64 unboxedLen(Box* obj) {
......@@ -2649,14 +2726,14 @@ extern "C" i64 unboxedLen(Box* obj) {
if (rewriter.get()) {
// rewriter->trap();
LenRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
lobj = lenInternal(obj, &rewrite_args);
lobj = lenInternal<CXX>(obj, &rewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
} else
r_boxed = rewrite_args.out_rtn;
} else {
lobj = lenInternal(obj, NULL);
lobj = lenInternal<CXX>(obj, NULL);
}
assert(lobj->cls == int_cls);
......@@ -2885,14 +2962,14 @@ extern "C" Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope,
RewriterVar* r_val = NULL;
if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any());
val = getattrInternalEx(obj, attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
val = getattrInternalEx<CXX>(obj, attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
if (!grewrite_args.out_success) {
rewrite_args = NULL;
} else if (val) {
r_val = grewrite_args.out_rtn;
}
} else {
val = getattrInternalEx(obj, attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
val = getattrInternalEx<CXX>(obj, attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
}
if (val == NULL) {
......@@ -4551,19 +4628,12 @@ Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_
}
}
// target[slice]
extern "C" Box* getitem(Box* target, Box* slice) {
STAT_TIMER(t0, "us_timer_slowpath_getitem", 10);
// 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();
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getitem"));
template <enum ExceptionStyle S>
Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI) {
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
// The PyObject_GetItem logic is:
// - call mp_subscript if it exists
......@@ -4575,9 +4645,10 @@ extern "C" Box* getitem(Box* target, Box* slice) {
// exist if mp_subscript exists.
PyMappingMethods* m = target->cls->tp_as_mapping;
if (m && m->mp_subscript && m->mp_subscript != slot_mp_subscript) {
if (rewriter.get()) {
RewriterVar* r_obj = rewriter->getArg(0);
RewriterVar* r_slice = rewriter->getArg(1);
if (rewrite_args) {
assert(S == CXX);
RewriterVar* r_obj = rewrite_args->target;
RewriterVar* r_slice = rewrite_args->slice;
RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls));
RewriterVar* r_m = r_cls->getAttr(offsetof(BoxedClass, tp_as_mapping));
r_m->addGuardNotEq(0);
......@@ -4588,12 +4659,13 @@ extern "C" Box* getitem(Box* target, Box* slice) {
// (after guarding it's not null), or maybe not. But the rewriter doesn't currently
// support calling a RewriterVar (can only call fixed function addresses).
r_m->addAttrGuard(offsetof(PyMappingMethods, mp_subscript), (intptr_t)m->mp_subscript);
RewriterVar* r_rtn = rewriter->call(true, (void*)m->mp_subscript, r_obj, r_slice);
rewriter->call(true, (void*)checkAndThrowCAPIException);
rewriter->commitReturning(r_rtn);
RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)m->mp_subscript, r_obj, r_slice);
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_success = true;
rewrite_args->out_rtn = r_rtn;
}
Box* r = m->mp_subscript(target, slice);
if (!r)
if (S == CXX && !r)
throwCAPIException();
return r;
}
......@@ -4602,34 +4674,92 @@ extern "C" Box* getitem(Box* target, Box* slice) {
static BoxedString* getslice_str = internStringImmortal("__getslice__");
Box* rtn;
if (rewriter.get()) {
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
rewrite_args.arg1 = rewriter->getArg(1);
if (S == CAPI) {
assert(!rewrite_args);
try {
rtn = callItemOrSliceAttr(target, getitem_str, getslice_str, slice, NULL, NULL);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} else {
if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->target, rewrite_args->destination);
crewrite_args.arg1 = rewrite_args->slice;
rtn = callItemOrSliceAttr(target, getitem_str, getslice_str, slice, NULL, &rewrite_args);
rtn = callItemOrSliceAttr(target, getitem_str, getslice_str, slice, NULL, &crewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
} else if (rtn) {
rewriter->commitReturning(rewrite_args.out_rtn);
if (!crewrite_args.out_success) {
rewrite_args = NULL;
} else if (rtn) {
rewrite_args->out_rtn = crewrite_args.out_rtn;
}
} else {
rtn = callItemOrSliceAttr(target, getitem_str, getslice_str, slice, NULL, NULL);
}
} else {
rtn = callItemOrSliceAttr(target, getitem_str, getslice_str, slice, NULL, NULL);
}
if (rtn == NULL) {
// different versions of python give different error messages for this:
if (PYTHON_VERSION_MAJOR == 2 && PYTHON_VERSION_MINOR < 7) {
raiseExcHelper(TypeError, "'%s' object is unsubscriptable", getTypeName(target)); // tested on 2.6.6
if (S == CAPI)
PyErr_Format(TypeError, "'%s' object is unsubscriptable", getTypeName(target)); // tested on 2.6.6
else
raiseExcHelper(TypeError, "'%s' object is unsubscriptable", getTypeName(target)); // tested on 2.6.6
} else if (PYTHON_VERSION_MAJOR == 2 && PYTHON_VERSION_MINOR == 7 && PYTHON_VERSION_MICRO < 3) {
raiseExcHelper(TypeError, "'%s' object is not subscriptable", getTypeName(target)); // tested on 2.7.1
if (S == CAPI)
PyErr_Format(TypeError, "'%s' object is not subscriptable", getTypeName(target)); // tested on 2.7.1
else
raiseExcHelper(TypeError, "'%s' object is not subscriptable", getTypeName(target)); // tested on 2.7.1
} else {
// Changed to this in 2.7.3:
raiseExcHelper(TypeError, "'%s' object has no attribute '__getitem__'",
getTypeName(target)); // tested on 2.7.3
if (S == CAPI)
PyErr_Format(TypeError, "'%s' object has no attribute '__getitem__'", getTypeName(target));
else
raiseExcHelper(TypeError, "'%s' object has no attribute '__getitem__'", getTypeName(target));
}
}
if (rewrite_args)
rewrite_args->out_success = true;
return rtn;
}
// Force instantiation of the template
template Box* getitemInternal<CAPI>(Box*, Box*, GetitemRewriteArgs*);
template Box* getitemInternal<CXX>(Box*, Box*, GetitemRewriteArgs*);
// target[slice]
extern "C" Box* getitem(Box* target, Box* slice) {
STAT_TIMER(t0, "us_timer_slowpath_getitem", 10);
// 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();
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getitem"));
Box* rtn;
if (rewriter.get()) {
GetitemRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1),
rewriter->getReturnDestination());
rtn = getitemInternal<CXX>(target, slice, &rewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
} else {
rewriter->commitReturning(rewrite_args.out_rtn);
}
} else {
rtn = getitemInternal<CXX>(target, slice, NULL);
}
assert(rtn);
return rtn;
}
......@@ -5370,7 +5500,7 @@ void setGlobal(Box* globals, BoxedString* name, Box* value) {
extern "C" Box* importFrom(Box* _m, BoxedString* name) {
STAT_TIMER(t0, "us_timer_importFrom", 10);
Box* r = getattrInternal(_m, name, NULL);
Box* r = getattrInternal<CXX>(_m, name, NULL);
if (r)
return r;
......
......@@ -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