Commit d6aa23f2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Basic functionality working, with warnings

parent 50abb6db
...@@ -52,6 +52,41 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) { ...@@ -52,6 +52,41 @@ static PyObject* wrap_unaryfunc(PyObject* self, PyObject* args, void* wrapped) {
return (*func)(self); return (*func)(self);
} }
static Py_ssize_t getindex(PyObject* self, PyObject* arg) noexcept {
Py_ssize_t i;
i = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
if (i == -1 && PyErr_Occurred())
return -1;
if (i < 0) {
PySequenceMethods* sq = Py_TYPE(self)->tp_as_sequence;
if (sq && sq->sq_length) {
Py_ssize_t n = (*sq->sq_length)(self);
if (n < 0)
return -1;
i += n;
}
}
return i;
}
static PyObject* wrap_sq_item(PyObject* self, PyObject* args, void* wrapped) noexcept {
ssizeargfunc func = (ssizeargfunc)wrapped;
PyObject* arg;
Py_ssize_t i;
if (PyTuple_GET_SIZE(args) == 1) {
arg = PyTuple_GET_ITEM(args, 0);
i = getindex(self, arg);
if (i == -1 && PyErr_Occurred())
return NULL;
return (*func)(self, i);
}
check_num_args(args, 1);
assert(PyErr_Occurred());
return NULL;
}
PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept { PyObject* slot_tp_new(PyTypeObject* self, PyObject* args, PyObject* kwds) noexcept {
try { try {
// TODO: runtime ICs? // TODO: runtime ICs?
...@@ -84,6 +119,14 @@ PyObject* slot_tp_repr(PyObject* self) noexcept { ...@@ -84,6 +119,14 @@ PyObject* slot_tp_repr(PyObject* self) noexcept {
} }
} }
PyObject* slot_sq_item(PyObject* self, Py_ssize_t i) noexcept {
try {
return getitem(self, boxInt(i));
} catch (Box* e) {
abort();
}
}
typedef wrapper_def slotdef; typedef wrapper_def slotdef;
static void** slotptr(BoxedClass* type, int offset) { static void** slotptr(BoxedClass* type, int offset) {
...@@ -115,7 +158,14 @@ static void** slotptr(BoxedClass* type, int offset) { ...@@ -115,7 +158,14 @@ static void** slotptr(BoxedClass* type, int offset) {
static void update_one_slot(BoxedClass* self, const slotdef& p) { static void update_one_slot(BoxedClass* self, const slotdef& p) {
// TODO: CPython version is significantly more sophisticated // TODO: CPython version is significantly more sophisticated
void** ptr = slotptr(self, p.offset); void** ptr = slotptr(self, p.offset);
assert(ptr && "it is ok for this to be NULL (CPython handles that case) but I don't think it should happen?"); if (!ptr) {
if (typeLookup(self, p.name, NULL)) {
printf("Warning: should probably allocate the tp_as_sequence object\n");
// assert(0 && "it is ok for this to be NULL (CPython handles that case) but I don't think it should
// happen?");
}
return;
}
if (typeLookup(self, p.name, NULL)) if (typeLookup(self, p.name, NULL))
*ptr = p.function; *ptr = p.function;
...@@ -152,33 +202,31 @@ static slotdef slotdefs[] = { ...@@ -152,33 +202,31 @@ static slotdef slotdefs[] = {
PyWrapperFlag_KEYWORDS), PyWrapperFlag_KEYWORDS),
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
#if 0 // SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"),
SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"),
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
The logic in abstract.c always falls back to nb_add/nb_multiply in The logic in abstract.c always falls back to nb_add/nb_multiply in
this case. Defining both the nb_* and the sq_* slots to call the this case. Defining both the nb_* and the sq_* slots to call the
user-defined methods has unexpected side-effects, as shown by user-defined methods has unexpected side-effects, as shown by
test_descr.notimplemented() */ test_descr.notimplemented() */
SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, "x.__add__(y) <==> x+y"), // SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, "x.__add__(y) <==> x+y"),
SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, "x.__mul__(n) <==> x*n"), // SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, "x.__mul__(n) <==> x*n"),
SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, "x.__rmul__(n) <==> n*x"), // SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, "x.__rmul__(n) <==> n*x"),
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, "x.__getitem__(y) <==> x[y]"), SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, "x.__getitem__(y) <==> x[y]"),
SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc, "x.__getslice__(i, j) <==> x[i:j]\n\ //SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc, "x.__getslice__(i, j) <==> x[i:j]\n\
\n\ //\n\
Use of negative indices is not supported."), //Use of negative indices is not supported."),
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, "x.__setitem__(i, y) <==> x[i]=y"), // SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, "x.__setitem__(i, y) <==> x[i]=y"),
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, "x.__delitem__(y) <==> del x[y]"), // SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, "x.__delitem__(y) <==> del x[y]"),
SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice, wrap_ssizessizeobjargproc, // SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice, wrap_ssizessizeobjargproc,
"x.__setslice__(i, j, y) <==> x[i:j]=y\n\ //"x.__setslice__(i, j, y) <==> x[i:j]=y\n\
\n\ //\n\
Use of negative indices is not supported."), //Use of negative indices is not supported."),
SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice, "x.__delslice__(i, j) <==> del x[i:j]\n\ //SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice, "x.__delslice__(i, j) <==> del x[i:j]\n\
\n\ //\n\
Use of negative indices is not supported."), //Use of negative indices is not supported."),
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, "x.__contains__(y) <==> y in x"), // SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, "x.__contains__(y) <==> y in x"),
SQSLOT("__iadd__", sq_inplace_concat, NULL, wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"), // SQSLOT("__iadd__", sq_inplace_concat, NULL, wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
SQSLOT("__imul__", sq_inplace_repeat, NULL, wrap_indexargfunc, "x.__imul__(y) <==> x*=y"), // SQSLOT("__imul__", sq_inplace_repeat, NULL, wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
#endif
}; };
static void init_slotdefs() { static void init_slotdefs() {
...@@ -266,7 +314,7 @@ static void add_operators(BoxedClass* cls) { ...@@ -266,7 +314,7 @@ static void add_operators(BoxedClass* cls) {
continue; continue;
// TODO PyObject_HashNotImplemented // TODO PyObject_HashNotImplemented
cls->giveAttr(p.name, new BoxedWrapperDescriptor(&p, cls)); cls->giveAttr(p.name, new BoxedWrapperDescriptor(&p, cls, *ptr));
} }
if (cls->tp_new) if (cls->tp_new)
...@@ -286,7 +334,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) { ...@@ -286,7 +334,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
RELEASE_ASSERT(cls->tp_setattr == NULL, ""); RELEASE_ASSERT(cls->tp_setattr == NULL, "");
RELEASE_ASSERT(cls->tp_compare == NULL, ""); RELEASE_ASSERT(cls->tp_compare == NULL, "");
RELEASE_ASSERT(cls->tp_as_number == NULL, ""); RELEASE_ASSERT(cls->tp_as_number == NULL, "");
RELEASE_ASSERT(cls->tp_as_sequence == NULL, "");
RELEASE_ASSERT(cls->tp_as_mapping == NULL, ""); RELEASE_ASSERT(cls->tp_as_mapping == NULL, "");
RELEASE_ASSERT(cls->tp_hash == NULL, ""); RELEASE_ASSERT(cls->tp_hash == NULL, "");
RELEASE_ASSERT(cls->tp_str == NULL, ""); RELEASE_ASSERT(cls->tp_str == NULL, "");
...@@ -315,6 +362,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) { ...@@ -315,6 +362,10 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
RELEASE_ASSERT(cls->tp_del == NULL, ""); RELEASE_ASSERT(cls->tp_del == NULL, "");
RELEASE_ASSERT(cls->tp_version_tag == 0, ""); RELEASE_ASSERT(cls->tp_version_tag == 0, "");
if (cls->tp_as_sequence) {
printf("Warning: found tp_as_sequence, but not all sequence slotdefs defined\n");
}
// I think it is safe to ignore these for for now: // I think it is safe to ignore these for for now:
// RELEASE_ASSERT(cls->tp_weaklistoffset == 0, ""); // RELEASE_ASSERT(cls->tp_weaklistoffset == 0, "");
// RELEASE_ASSERT(cls->tp_traverse == NULL, ""); // RELEASE_ASSERT(cls->tp_traverse == NULL, "");
......
...@@ -83,8 +83,9 @@ class BoxedWrapperDescriptor : public Box { ...@@ -83,8 +83,9 @@ class BoxedWrapperDescriptor : public Box {
public: public:
const wrapper_def* wrapper; const wrapper_def* wrapper;
BoxedClass* type; BoxedClass* type;
BoxedWrapperDescriptor(const wrapper_def* wrapper, BoxedClass* type) void* wrapped;
: Box(wrapperdescr_cls), wrapper(wrapper), type(type) {} BoxedWrapperDescriptor(const wrapper_def* wrapper, BoxedClass* type, void* wrapped)
: Box(wrapperdescr_cls), wrapper(wrapper), type(type), wrapped(wrapped) {}
static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner); static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner);
}; };
...@@ -104,14 +105,12 @@ public: ...@@ -104,14 +105,12 @@ public:
int flags = self->descr->wrapper->flags; int flags = self->descr->wrapper->flags;
wrapperfunc wrapper = self->descr->wrapper->wrapper; wrapperfunc wrapper = self->descr->wrapper->wrapper;
assert(self->descr->wrapper->offset > 0); assert(self->descr->wrapper->offset > 0);
char* ptr = (char*)self->descr->type + self->descr->wrapper->offset;
void* wrapped = *reinterpret_cast<void**>(ptr);
if (flags & PyWrapperFlag_KEYWORDS) { if (flags & PyWrapperFlag_KEYWORDS) {
wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
return (*wk)(self->obj, args, wrapped, kwds); return (*wk)(self->obj, args, self->descr->wrapped, kwds);
} else { } else {
return (*wrapper)(self->obj, args, wrapped); return (*wrapper)(self->obj, args, self->descr->wrapped);
} }
abort(); abort();
} }
......
...@@ -699,7 +699,12 @@ extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) { ...@@ -699,7 +699,12 @@ extern "C" PyObject* PyNumber_ToBase(PyObject* n, int base) {
} }
extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) { extern "C" Py_ssize_t PyNumber_AsSsize_t(PyObject* o, PyObject* exc) {
Py_FatalError("unimplemented"); RELEASE_ASSERT(o->cls != long_cls, "unhandled");
RELEASE_ASSERT(o->cls == int_cls, "??");
int64_t n = static_cast<BoxedInt*>(o)->n;
static_assert(sizeof(n) == sizeof(Py_ssize_t), "");
return n;
} }
extern "C" Py_ssize_t PyUnicode_GET_SIZE(PyObject*) { extern "C" Py_ssize_t PyUnicode_GET_SIZE(PyObject*) {
......
...@@ -16,5 +16,5 @@ slots_test.call_funcs(C()) ...@@ -16,5 +16,5 @@ slots_test.call_funcs(C())
# Test to make sure that updating an existing class also updates the tp_* slots: # Test to make sure that updating an existing class also updates the tp_* slots:
def repr2(self): def repr2(self):
return "repr2()" return "repr2()"
C.repr2 = repr2 C.__repr__ = repr2
slots_test.call_funcs(C()) slots_test.call_funcs(C())
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