Commit c0bbdfb4 authored by Rudi Chen's avatar Rudi Chen

Inherit special protocol tp_* slots.

C extensions (NumPy) might inherit classes in C code and expect to find
tp_number. This is just copied from CPython's PyType_Ready.

This requires assigning some of the runtime functions to thesq_ and mp_ slots
otherwise there are infinite loops from Pyston attributes.
parent b42cb293
......@@ -3278,6 +3278,19 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
assert(cls->tp_name);
// Inherit some special protocols. Normally methods are automatically inherited,
// when a Python class is declared, but that may not be the case with C extensions.
if (base != NULL) {
if (cls->tp_as_number == NULL)
cls->tp_as_number = base->tp_as_number;
if (cls->tp_as_sequence == NULL)
cls->tp_as_sequence = base->tp_as_sequence;
if (cls->tp_as_mapping == NULL)
cls->tp_as_mapping = base->tp_as_mapping;
if (cls->tp_as_buffer == NULL)
cls->tp_as_buffer = base->tp_as_buffer;
}
if (cls->tp_call) {
cls->tpp_call.capi_val = tppProxyToTpCall<CAPI>;
cls->tpp_call.cxx_val = tppProxyToTpCall<CXX>;
......
......@@ -174,6 +174,11 @@ Box* dictViewItems(BoxedDict* self) {
return rtn;
}
// Analoguous to CPython's, used for sq_ slots.
static Py_ssize_t dict_length(PyDictObject* mp) {
return ((BoxedDict*)mp)->d.size();
}
Box* dictLen(BoxedDict* self) {
if (!isSubclass(self->cls, dict_cls))
raiseExcHelper(TypeError, "descriptor '__len__' requires a 'dict' object but received a '%s'",
......@@ -374,9 +379,7 @@ extern "C" PyObject* PyDict_GetItemString(PyObject* dict, const char* key) noexc
}
Box* dictSetitem(BoxedDict* self, Box* k, Box* v) {
// printf("Starting setitem\n");
Box*& pos = self->d[k];
// printf("Got the pos\n");
if (pos != NULL) {
pos = v;
......@@ -402,6 +405,22 @@ Box* dictDelitem(BoxedDict* self, Box* k) {
return None;
}
// Analoguous to CPython's, used for sq_ slots.
static int dict_ass_sub(PyDictObject* mp, PyObject* v, PyObject* w) noexcept {
try {
Box* res;
if (w == NULL) {
res = dictDelitem((BoxedDict*)mp, v);
} else {
res = dictSetitem((BoxedDict*)mp, v, w);
}
assert(res == None);
} catch (ExcInfo e) {
setCAPIException(e);
}
return 0;
}
extern "C" int PyDict_DelItem(PyObject* op, PyObject* key) noexcept {
ASSERT(isSubclass(op->cls, dict_cls) || op->cls == attrwrapper_cls, "%s", getTypeName(op));
try {
......@@ -824,7 +843,11 @@ void setupDict() {
dict_cls->tp_init = dict_init;
dict_cls->tp_repr = dict_repr;
dict_cls->tp_as_mapping->mp_length = (lenfunc)dict_length;
dict_cls->tp_as_mapping->mp_subscript = (binaryfunc)dictGetitem<CAPI>;
dict_cls->tp_as_mapping->mp_ass_subscript = (objobjargproc)dict_ass_sub;
dict_cls->tp_as_sequence->sq_contains = (objobjproc)PyDict_Contains;
dict_keys_cls->giveAttr(
"__iter__", new BoxedFunction(boxRTFunction((void*)dictViewKeysIter, typeFromClass(dict_iterator_cls), 1)));
......
......@@ -31,6 +31,8 @@
namespace pyston {
static int list_ass_slice(PyListObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject* v);
extern "C" int PyList_Append(PyObject* op, PyObject* newitem) noexcept {
RELEASE_ASSERT(PyList_Check(op), "");
try {
......@@ -198,7 +200,7 @@ static Box* list_slice(Box* o, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept {
return (PyObject*)np;
}
extern "C" Box* listGetitemUnboxed(BoxedList* self, int64_t n) {
static inline Box* listGetitemUnboxed(BoxedList* self, int64_t n) {
assert(isSubclass(self->cls, list_cls));
if (n < 0)
n = self->size + n;
......@@ -252,6 +254,17 @@ extern "C" Box* listGetslice(BoxedList* self, Box* boxedStart, Box* boxedStop) {
return _listSlice(self, start, stop, 1, stop - start);
}
// Analoguous to CPython's, used for sq_ slots.
static PyObject* list_item(PyListObject* a, Py_ssize_t i) noexcept {
try {
BoxedList* self = (BoxedList*)a;
return listGetitemUnboxed(self, i);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
template <ExceptionStyle S> Box* listGetitem(BoxedList* self, Box* slice) {
if (S == CAPI) {
try {
......@@ -297,6 +310,22 @@ extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
return listSetitemUnboxed(self, slice->n, v);
}
// Analoguous to CPython's, used for sq_ slots.
static int list_ass_item(PyListObject* a, Py_ssize_t i, PyObject* v) {
PyObject* old_value;
if (i < 0 || i >= Py_SIZE(a)) {
PyErr_SetString(PyExc_IndexError, "list assignment index out of range");
return -1;
}
if (v == NULL)
return list_ass_slice(a, i, i + 1, v);
Py_INCREF(v);
old_value = a->ob_item[i];
a->ob_item[i] = v;
Py_DECREF(old_value);
return 0;
}
extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noexcept {
PyObject* olditem;
PyObject** p;
......@@ -449,7 +478,7 @@ int list_ass_ext_slice(BoxedList* self, PyObject* item, PyObject* value) {
}
}
Box* listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i64 step, Box* v) {
static inline void listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i64 step, Box* v) {
RELEASE_ASSERT(step == 1, "step sizes must be 1 in this code path");
boundSliceWithLength(&start, &stop, start, stop, self->size);
......@@ -488,8 +517,6 @@ Box* listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i64 step, Box*
}
self->size += delts;
return None;
}
extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
......@@ -511,7 +538,14 @@ extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
return None;
}
return listSetitemSliceInt64(self, start, stop, step, v);
listSetitemSliceInt64(self, start, stop, step, v);
return None;
}
// Analoguous to CPython's, used for sq_ slots.
static int list_ass_slice(PyListObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject* v) {
listSetitemSliceInt64((BoxedList*)a, ilow, ihigh, 1, v);
return 0;
}
extern "C" Box* listSetslice(BoxedList* self, Box* boxedStart, Box* boxedStop, Box** args) {
......@@ -522,7 +556,8 @@ extern "C" Box* listSetslice(BoxedList* self, Box* boxedStart, Box* boxedStop, B
sliceIndex(boxedStart, &start);
sliceIndex(boxedStop, &stop);
return listSetitemSliceInt64(self, start, stop, 1, value);
listSetitemSliceInt64(self, start, stop, 1, value);
return None;
}
extern "C" Box* listSetitem(BoxedList* self, Box* slice, Box* v) {
......@@ -822,23 +857,33 @@ extern "C" Box* PyList_GetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh)
return listGetitemSlice<CAPI>(self, new BoxedSlice(boxInt(ilow), boxInt(ihigh), boxInt(1)));
}
Box* listContains(BoxedList* self, Box* elt) {
static inline int list_contains_shared(BoxedList* self, Box* elt) {
assert(isSubclass(self->cls, list_cls));
int size = self->size;
for (int i = 0; i < size; i++) {
Box* e = self->elts->elts[i];
bool identity_eq = e == elt;
if (identity_eq)
return True;
return true;
int r = PyObject_RichCompareBool(e, elt, Py_EQ);
if (r == -1)
throwCAPIException();
if (r)
return True;
return true;
}
return False;
return false;
}
static int list_contains(PyListObject* a, PyObject* el) {
return list_contains_shared((BoxedList*)a, el);
}
Box* listContains(BoxedList* self, Box* elt) {
return boxBool(list_contains_shared(self, elt));
}
Box* listCount(BoxedList* self, Box* elt) {
......@@ -1195,9 +1240,13 @@ void setupList() {
list_cls->giveAttr("__hash__", None);
list_cls->freeze();
list_cls->tp_as_sequence->sq_slice = list_slice;
list_cls->tp_as_sequence->sq_length = list_length;
list_cls->tp_iter = listIter;
list_cls->tp_as_sequence->sq_length = list_length;
list_cls->tp_as_sequence->sq_item = (ssizeargfunc)list_item;
list_cls->tp_as_sequence->sq_slice = list_slice;
list_cls->tp_as_sequence->sq_ass_item = (ssizeobjargproc)list_ass_item;
list_cls->tp_as_sequence->sq_ass_slice = (ssizessizeobjargproc)list_ass_slice;
list_cls->tp_as_sequence->sq_contains = (objobjproc)list_contains;
CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL);
......
......@@ -1660,6 +1660,7 @@ static Box* str_slice(Box* o, Py_ssize_t i, Py_ssize_t j) {
return PyString_FromStringAndSize(a->data() + i, j - i);
}
// Analoguous to CPython's, used for sq_ slots.
static Py_ssize_t str_length(Box* a) {
return Py_SIZE(a);
}
......@@ -2062,14 +2063,14 @@ Box* strSwapcase(BoxedString* self) {
return rtn;
}
Box* strContains(BoxedString* self, Box* elt) {
static inline int string_contains_shared(BoxedString* self, Box* elt) {
assert(PyString_Check(self));
if (PyUnicode_Check(elt)) {
int r = PyUnicode_Contains(self, elt);
if (r < 0)
throwCAPIException();
return boxBool(r);
return r;
}
if (!PyString_Check(elt))
......@@ -2083,9 +2084,16 @@ Box* strContains(BoxedString* self, Box* elt) {
found_idx = self->s().find(sub->s()[0]);
else
found_idx = self->s().find(sub->s());
if (found_idx == std::string::npos)
return False;
return True;
return (found_idx != std::string::npos);
}
// Analoguous to CPython's, used for sq_ slots.
static int string_contains(PyObject* str_obj, PyObject* sub_obj) {
return string_contains_shared((BoxedString*)str_obj, sub_obj);
}
Box* strContains(BoxedString* self, Box* elt) {
return boxBool(string_contains_shared(self, elt));
}
// compares (a+a_pos, len) with (str)
......@@ -2284,6 +2292,17 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
return result;
}
static PyObject* string_item(PyStringObject* self, register Py_ssize_t i) {
BoxedString* boxedString = (BoxedString*)self;
if (i < 0 || i >= boxedString->size()) {
raiseExcHelper(IndexError, "string index out of range");
}
char c = boxedString->s()[i];
return characters[c & UCHAR_MAX];
}
template <ExceptionStyle S> Box* strGetitem(BoxedString* self, Box* slice) {
if (S == CAPI) {
try {
......@@ -2857,10 +2876,12 @@ void setupStr() {
add_operators(str_cls);
str_cls->freeze();
str_cls->tp_as_sequence->sq_slice = str_slice;
str_cls->tp_as_sequence->sq_length = str_length;
str_cls->tp_iter = (decltype(str_cls->tp_iter))strIter;
str_cls->tp_hash = (hashfunc)str_hash;
str_cls->tp_as_sequence->sq_length = str_length;
str_cls->tp_as_sequence->sq_item = (ssizeargfunc)string_item;
str_cls->tp_as_sequence->sq_slice = str_slice;
str_cls->tp_as_sequence->sq_contains = (objobjproc)string_contains;
basestring_cls->giveAttr("__doc__",
boxString("Type basestring cannot be instantiated; it is the base for str and unicode."));
......
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