Commit 8b3f6190 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Consolidate slot info into a slotdefs array

Previously had hardcoded three different iterations.
parent c4233571
......@@ -86,58 +86,68 @@ PyObject* Py_CallPythonRepr(PyObject* self) {
}
}
bool update_slot(BoxedClass* self, const std::string& attr) {
if (attr == "__new__") {
self->tp_new = &Py_CallPythonNew;
// TODO update subclasses
return true;
}
typedef wrapper_def slotdef;
if (attr == "__call__") {
self->tp_call = &Py_CallPythonCall;
// TODO update subclasses
static void** slotptr(BoxedClass* self, int offset) {
// TODO handle indices into the indirected portions (tp_as_sequence, etc)
char* ptr = reinterpret_cast<char*>(self);
return reinterpret_cast<void**>(ptr + offset);
}
return true;
}
static void update_one_slot(BoxedClass* self, const slotdef& p) {
// TODO: CPython version is significantly more sophisticated
void** ptr = slotptr(self, p.offset);
assert(ptr);
if (attr == "__repr__") {
self->tp_repr = &Py_CallPythonRepr;
// TODO update subclasses
if (typeLookup(self, p.name, NULL))
*ptr = p.function;
else
*ptr = NULL;
}
return true;
static slotdef slotdefs[] = {
{ "__repr__", offsetof(PyTypeObject, tp_repr), (void*)&Py_CallPythonRepr, wrap_unaryfunc, 0 },
{ "__call__", offsetof(PyTypeObject, tp_call), (void*)&Py_CallPythonCall, (wrapperfunc)wrap_call,
PyWrapperFlag_KEYWORDS },
{ "__new__", offsetof(PyTypeObject, tp_new), (void*)&Py_CallPythonNew, NULL, 0 },
};
static void init_slotdefs() {
static bool initialized = false;
if (initialized)
return;
for (int i = 0; i < sizeof(slotdefs) / sizeof(slotdefs[0]); i++) {
if (i > 0) {
ASSERT(slotdefs[i].offset >= slotdefs[i - 1].offset, "%d %s", i, slotdefs[i - 1].name);
// CPython interns the name here
}
}
return false;
initialized = true;
}
void fixup_slot_dispatchers(BoxedClass* self) {
// This will probably share a lot in common with Py_TypeReady:
if (!self->tp_new) {
self->tp_new = &Py_CallPythonNew;
} else if (self->tp_new != Py_CallPythonNew) {
ASSERT(0, "need to set __new__?");
bool update_slot(BoxedClass* self, const std::string& attr) {
bool updated = false;
for (const slotdef& p : slotdefs) {
if (p.name == attr) {
// TODO update subclasses;
update_one_slot(self, p);
updated = true;
}
}
return updated;
}
if (!self->tp_call) {
self->tp_call = &Py_CallPythonCall;
} else if (self->tp_call != Py_CallPythonCall) {
ASSERT(0, "need to set __call__?");
}
void fixup_slot_dispatchers(BoxedClass* self) {
init_slotdefs();
if (!self->tp_repr) {
self->tp_repr = &PyObject_Repr;
} else if (self->tp_repr != Py_CallPythonRepr) {
ASSERT(0, "need to set __repr__?");
for (const slotdef& p : slotdefs) {
update_one_slot(self, p);
}
}
wrapper_def call_wrapper = { "__call__", offsetof(PyTypeObject, tp_call), (void*)&Py_CallPythonCall,
(wrapperfunc)wrap_call, PyWrapperFlag_KEYWORDS };
wrapper_def repr_wrapper
= { "__repr__", offsetof(PyTypeObject, tp_repr), (void*)&Py_CallPythonRepr, wrap_unaryfunc, 0 };
PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) {
static PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) {
RELEASE_ASSERT(isSubclass(self->cls, type_cls), "");
// ASSERT(self->tp_new != Py_CallPythonNew, "going to get in an infinite loop");
......@@ -155,20 +165,34 @@ PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) {
return self->tp_new(subtype, new_args, kwds);
}
static void add_tp_new_wrapper(BoxedClass* type) {
if (type->getattr("__new__"))
return;
static void add_operators(PyTypeObject* cls) {
if (cls->tp_new) {
cls->giveAttr("__new__",
new BoxedCApiFunction(METH_VARARGS | METH_KEYWORDS, cls, "__new__", (PyCFunction)tp_new_wrapper));
}
type->giveAttr("__new__",
new BoxedCApiFunction(METH_VARARGS | METH_KEYWORDS, type, "__new__", (PyCFunction)tp_new_wrapper));
}
if (cls->tp_call) {
cls->giveAttr("__call__", new BoxedWrapperDescriptor(&call_wrapper, cls));
}
static void add_operators(BoxedClass* cls) {
init_slotdefs();
for (const slotdef& p : slotdefs) {
if (!p.wrapper)
continue;
void** ptr = slotptr(cls, p.offset);
if (cls->tp_repr) {
cls->giveAttr("__repr__", new BoxedWrapperDescriptor(&repr_wrapper, cls));
if (!ptr || !*ptr)
continue;
if (cls->getattr(p.name))
continue;
// TODO PyObject_HashNotImplemented
cls->giveAttr(p.name, new BoxedWrapperDescriptor(&p, cls));
}
if (cls->tp_new)
add_tp_new_wrapper(cls);
}
extern "C" int PyType_IsSubtype(PyTypeObject* a, PyTypeObject* b) {
......@@ -243,7 +267,11 @@ extern "C" int PyType_Ready(PyTypeObject* cls) {
cls->tp_alloc = reinterpret_cast<decltype(cls->tp_alloc)>(PyType_GenericAlloc);
}
add_operators(cls);
try {
add_operators(cls);
} catch (Box* b) {
abort();
}
for (PyMethodDef* method = cls->tp_methods; method && method->ml_name; ++method) {
cls->giveAttr(method->ml_name, new BoxedMethodDescriptor(method, cls));
......
......@@ -19,7 +19,9 @@
namespace pyston {
// Returns if a slot was updated
bool update_slot(BoxedClass* self, const std::string& attr);
void fixup_slot_dispatchers(BoxedClass* self);
}
......
......@@ -27,7 +27,9 @@ struct wrapper_def {
int offset;
void* function; // "generic" handler that gets put in the tp_* slot which proxies to the python version
wrapperfunc wrapper; // "wrapper" that ends up getting called by the Python-visible WrapperDescr
// exists in CPython: const char* doc
int flags;
// exists in CPython: PyObject *name_strobj
};
extern BoxedClass* capifunc_cls, *wrapperdescr_cls, *wrapperobject_cls;
......
......@@ -18,6 +18,7 @@
#include "llvm/Support/FileSystem.h"
#include "capi/typeobject.h"
#include "codegen/ast_interpreter.h"
#include "codegen/irgen/hooks.h"
#include "codegen/parser.h"
......@@ -528,6 +529,8 @@ extern "C" PyObject* PyErr_NewException(char* name, PyObject* _base, PyObject* d
cls->giveAttr("__module__", boxStrConstantSize(name, dot_pos - name));
cls->giveAttr("__name__", boxStrConstantSize(dot_pos + 1, n - (dot_pos - name) - 1));
// TODO Not sure if this should be called here
fixup_slot_dispatchers(cls);
return cls;
} catch (Box* e) {
abort();
......
......@@ -3289,10 +3289,10 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
// Note: make sure to do this after assigning the attrs, since it will overwrite any defined __name__
made->setattr("__name__", name, NULL);
// TODO this function (typeNew) should probably call PyType_Ready
// TODO should this function (typeNew) call PyType_Ready?
made->tp_new = base->tp_new;
made->tp_alloc = reinterpret_cast<decltype(cls->tp_alloc)>(PyType_GenericAlloc);
fixup_slot_dispatchers(made);
return made;
}
......
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