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 { ...@@ -3278,6 +3278,19 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
assert(cls->tp_name); 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) { if (cls->tp_call) {
cls->tpp_call.capi_val = tppProxyToTpCall<CAPI>; cls->tpp_call.capi_val = tppProxyToTpCall<CAPI>;
cls->tpp_call.cxx_val = tppProxyToTpCall<CXX>; cls->tpp_call.cxx_val = tppProxyToTpCall<CXX>;
......
...@@ -174,6 +174,11 @@ Box* dictViewItems(BoxedDict* self) { ...@@ -174,6 +174,11 @@ Box* dictViewItems(BoxedDict* self) {
return rtn; 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) { Box* dictLen(BoxedDict* self) {
if (!isSubclass(self->cls, dict_cls)) if (!isSubclass(self->cls, dict_cls))
raiseExcHelper(TypeError, "descriptor '__len__' requires a 'dict' object but received a '%s'", 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 ...@@ -374,9 +379,7 @@ extern "C" PyObject* PyDict_GetItemString(PyObject* dict, const char* key) noexc
} }
Box* dictSetitem(BoxedDict* self, Box* k, Box* v) { Box* dictSetitem(BoxedDict* self, Box* k, Box* v) {
// printf("Starting setitem\n");
Box*& pos = self->d[k]; Box*& pos = self->d[k];
// printf("Got the pos\n");
if (pos != NULL) { if (pos != NULL) {
pos = v; pos = v;
...@@ -402,6 +405,22 @@ Box* dictDelitem(BoxedDict* self, Box* k) { ...@@ -402,6 +405,22 @@ Box* dictDelitem(BoxedDict* self, Box* k) {
return None; 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 { extern "C" int PyDict_DelItem(PyObject* op, PyObject* key) noexcept {
ASSERT(isSubclass(op->cls, dict_cls) || op->cls == attrwrapper_cls, "%s", getTypeName(op)); ASSERT(isSubclass(op->cls, dict_cls) || op->cls == attrwrapper_cls, "%s", getTypeName(op));
try { try {
...@@ -824,7 +843,11 @@ void setupDict() { ...@@ -824,7 +843,11 @@ 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_length = (lenfunc)dict_length;
dict_cls->tp_as_mapping->mp_subscript = (binaryfunc)dictGetitem<CAPI>; 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( 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)));
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
namespace pyston { 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 { extern "C" int PyList_Append(PyObject* op, PyObject* newitem) noexcept {
RELEASE_ASSERT(PyList_Check(op), ""); RELEASE_ASSERT(PyList_Check(op), "");
try { try {
...@@ -198,7 +200,7 @@ static Box* list_slice(Box* o, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept { ...@@ -198,7 +200,7 @@ static Box* list_slice(Box* o, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept {
return (PyObject*)np; 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)); assert(isSubclass(self->cls, list_cls));
if (n < 0) if (n < 0)
n = self->size + n; n = self->size + n;
...@@ -252,6 +254,17 @@ extern "C" Box* listGetslice(BoxedList* self, Box* boxedStart, Box* boxedStop) { ...@@ -252,6 +254,17 @@ extern "C" Box* listGetslice(BoxedList* self, Box* boxedStart, Box* boxedStop) {
return _listSlice(self, start, stop, 1, stop - start); 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) { template <ExceptionStyle S> Box* listGetitem(BoxedList* self, Box* slice) {
if (S == CAPI) { if (S == CAPI) {
try { try {
...@@ -297,6 +310,22 @@ extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) { ...@@ -297,6 +310,22 @@ extern "C" Box* listSetitemInt(BoxedList* self, BoxedInt* slice, Box* v) {
return listSetitemUnboxed(self, slice->n, 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 { extern "C" int PyList_SetItem(PyObject* op, Py_ssize_t i, PyObject* newitem) noexcept {
PyObject* olditem; PyObject* olditem;
PyObject** p; PyObject** p;
...@@ -449,7 +478,7 @@ int list_ass_ext_slice(BoxedList* self, PyObject* item, PyObject* value) { ...@@ -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"); RELEASE_ASSERT(step == 1, "step sizes must be 1 in this code path");
boundSliceWithLength(&start, &stop, start, stop, self->size); boundSliceWithLength(&start, &stop, start, stop, self->size);
...@@ -488,8 +517,6 @@ Box* listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i64 step, Box* ...@@ -488,8 +517,6 @@ Box* listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i64 step, Box*
} }
self->size += delts; self->size += delts;
return None;
} }
extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) { extern "C" Box* listSetitemSlice(BoxedList* self, BoxedSlice* slice, Box* v) {
...@@ -511,7 +538,14 @@ 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 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) { 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 ...@@ -522,7 +556,8 @@ extern "C" Box* listSetslice(BoxedList* self, Box* boxedStart, Box* boxedStop, B
sliceIndex(boxedStart, &start); sliceIndex(boxedStart, &start);
sliceIndex(boxedStop, &stop); 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) { 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) ...@@ -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))); 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; int size = self->size;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Box* e = self->elts->elts[i]; Box* e = self->elts->elts[i];
bool identity_eq = e == elt; bool identity_eq = e == elt;
if (identity_eq) if (identity_eq)
return True; return true;
int r = PyObject_RichCompareBool(e, elt, Py_EQ); int r = PyObject_RichCompareBool(e, elt, Py_EQ);
if (r == -1) if (r == -1)
throwCAPIException(); throwCAPIException();
if (r) 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) { Box* listCount(BoxedList* self, Box* elt) {
...@@ -1195,9 +1240,13 @@ void setupList() { ...@@ -1195,9 +1240,13 @@ void setupList() {
list_cls->giveAttr("__hash__", None); list_cls->giveAttr("__hash__", None);
list_cls->freeze(); 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_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); CLFunction* hasnext = boxRTFunction((void*)listiterHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL); addRTFunction(hasnext, (void*)listiterHasnext, BOXED_BOOL);
......
...@@ -1660,6 +1660,7 @@ static Box* str_slice(Box* o, Py_ssize_t i, Py_ssize_t j) { ...@@ -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); return PyString_FromStringAndSize(a->data() + i, j - i);
} }
// Analoguous to CPython's, used for sq_ slots.
static Py_ssize_t str_length(Box* a) { static Py_ssize_t str_length(Box* a) {
return Py_SIZE(a); return Py_SIZE(a);
} }
...@@ -2062,14 +2063,14 @@ Box* strSwapcase(BoxedString* self) { ...@@ -2062,14 +2063,14 @@ Box* strSwapcase(BoxedString* self) {
return rtn; return rtn;
} }
Box* strContains(BoxedString* self, Box* elt) { static inline int string_contains_shared(BoxedString* self, Box* elt) {
assert(PyString_Check(self)); assert(PyString_Check(self));
if (PyUnicode_Check(elt)) { if (PyUnicode_Check(elt)) {
int r = PyUnicode_Contains(self, elt); int r = PyUnicode_Contains(self, elt);
if (r < 0) if (r < 0)
throwCAPIException(); throwCAPIException();
return boxBool(r); return r;
} }
if (!PyString_Check(elt)) if (!PyString_Check(elt))
...@@ -2083,9 +2084,16 @@ Box* strContains(BoxedString* self, Box* elt) { ...@@ -2083,9 +2084,16 @@ Box* strContains(BoxedString* self, Box* elt) {
found_idx = self->s().find(sub->s()[0]); found_idx = self->s().find(sub->s()[0]);
else else
found_idx = self->s().find(sub->s()); found_idx = self->s().find(sub->s());
if (found_idx == std::string::npos) return (found_idx != std::string::npos);
return False; }
return True;
// 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) // compares (a+a_pos, len) with (str)
...@@ -2284,6 +2292,17 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) { ...@@ -2284,6 +2292,17 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
return result; 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) { template <ExceptionStyle S> Box* strGetitem(BoxedString* self, Box* slice) {
if (S == CAPI) { if (S == CAPI) {
try { try {
...@@ -2857,10 +2876,12 @@ void setupStr() { ...@@ -2857,10 +2876,12 @@ void setupStr() {
add_operators(str_cls); add_operators(str_cls);
str_cls->freeze(); 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_iter = (decltype(str_cls->tp_iter))strIter;
str_cls->tp_hash = (hashfunc)str_hash; 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__", basestring_cls->giveAttr("__doc__",
boxString("Type basestring cannot be instantiated; it is the base for str and unicode.")); 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