Commit ed14dd77 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Templatize getitemInternal

For use of PyObject_GetItem

django_template3 ends up calling this a fair amount via unicode_translate
(ie it checks to see if certain entries are in the translation table).
parent 729feee3
......@@ -457,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 {
......
......@@ -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;
}
......@@ -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();
......
......@@ -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) {
......
......@@ -4625,19 +4625,11 @@ 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) {
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
// The PyObject_GetItem logic is:
// - call mp_subscript if it exists
......@@ -4649,9 +4641,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);
......@@ -4662,12 +4655,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;
}
......@@ -4676,34 +4670,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;
}
......
......@@ -114,6 +114,10 @@ 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);
struct LenRewriteArgs;
template <ExceptionStyle::ExceptionStyle S> BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args);
Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2,
......
......@@ -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;
......
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