Commit 79b2e9cc authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix some slot handling issues

Well, fix one of them and work around another.  They both come from having
an extension class subclass from a builtin class, since in CPython they can
expect the tp_* slots to be set, but in Pyston those are just wrappers around
the Python functions and then things can get in infinite recursion.
parent e16e0775
...@@ -395,7 +395,9 @@ static PyObject* wrap_init(PyObject* self, PyObject* args, void* wrapped, PyObje ...@@ -395,7 +395,9 @@ static PyObject* wrap_init(PyObject* self, PyObject* args, void* wrapped, PyObje
static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** attrobj) noexcept { static PyObject* lookup_maybe(PyObject* self, const char* attrstr, PyObject** attrobj) noexcept {
PyObject* res; PyObject* res;
// TODO: CPython uses the attrobj as a cache // TODO: CPython uses the attrobj as a cache. If we want to use it, we'd have to make sure that
// they get registered as GC roots since they are usually placed into static variables.
Box* obj = typeLookup(self->cls, attrstr, NULL); Box* obj = typeLookup(self->cls, attrstr, NULL);
if (obj) if (obj)
return processDescriptor(obj, self, self->cls); return processDescriptor(obj, self, self->cls);
...@@ -1842,9 +1844,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { ...@@ -1842,9 +1844,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
// tp_basicsize, tp_itemsize // tp_basicsize, tp_itemsize
// tp_doc // tp_doc
if (!cls->tp_new && base != object_cls)
cls->tp_new = base->tp_new;
try { try {
add_operators(cls); add_operators(cls);
} catch (ExcInfo e) { } catch (ExcInfo e) {
......
...@@ -550,6 +550,27 @@ extern "C" void dictViewGCHandler(GCVisitor* v, Box* b) { ...@@ -550,6 +550,27 @@ extern "C" void dictViewGCHandler(GCVisitor* v, Box* b) {
v->visit(view->d); v->visit(view->d);
} }
static int dict_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept {
assert(isSubclass(self->cls, dict_cls));
try {
dictInit(static_cast<BoxedDict*>(self), static_cast<BoxedTuple*>(args), static_cast<BoxedDict*>(kwds));
} catch (ExcInfo e) {
setCAPIException(e);
return -1;
}
return 0;
}
static Box* dict_repr(PyObject* self) noexcept {
assert(isSubclass(self->cls, dict_cls));
try {
return dictRepr(static_cast<BoxedDict*>(self));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
void setupDict() { void setupDict() {
dict_iterator_cls = new BoxedHeapClass(object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false, dict_iterator_cls = new BoxedHeapClass(object_cls, &dictIteratorGCHandler, 0, sizeof(BoxedDict), false,
"dictionary-itemiterator"); "dictionary-itemiterator");
...@@ -617,6 +638,20 @@ void setupDict() { ...@@ -617,6 +638,20 @@ void setupDict() {
dict_iterator_cls->freeze(); dict_iterator_cls->freeze();
// Manually set some tp_* slots *after* calling freeze() -> fixup_slot_dispatchers().
// fixup_slot_dispatchers will insert a wrapper like slot_tp_init into tp_init, which calls the python-level
// __init__ function. This is all well and good, until a C extension tries to subclass from dict and then
// creates a new tp_init function which calls Py_DictType.tp_init(). That tp_init is slot_tp_init, which calls
// self.__init__, which is the *subclasses* init function not dict's.
//
// This seems to happen pretty rarely, and only with dict, so for now let's just work around it by manually
// setting the couple functions that get used.
//
// I'm not sure if CPython has a better mechanism for this, since I assume they allow having extension classes
// subclass Python classes.
dict_cls->tp_init = dict_init;
dict_cls->tp_repr = dict_repr;
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)));
dict_keys_cls->freeze(); dict_keys_cls->freeze();
......
...@@ -14,3 +14,6 @@ for i in d: ...@@ -14,3 +14,6 @@ for i in d:
while d: while d:
print d.popleft() print d.popleft()
d = _collections.defaultdict()
print str(d), repr(d)
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