From d793a3a4db343a5c1bc0a6856350f700f659c10d Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 01:19:36 +0000 Subject: [PATCH 01/11] Workaround for the "terminator in middle of basic block" issue The problem is that we emit an llvm "unreachable" instruction, and then continue to emit other code, which fails the verifier. endBlock(DEAD) is supposed to be the right way to handle that, but there is some more work that would need to be done there to get that working properly. So just do the easy thing for now -- create a new BB so that it's ok to emit more code. --- src/codegen/irgen/irgenerator.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/codegen/irgen/irgenerator.cpp b/src/codegen/irgen/irgenerator.cpp index deb2e43c7..0963f9615 100644 --- a/src/codegen/irgen/irgenerator.cpp +++ b/src/codegen/irgen/irgenerator.cpp @@ -923,9 +923,16 @@ class IRGeneratorImpl : public IRGenerator { // trigger an exception, but the irgenerator will know that definitely-defined // local symbols will not throw. emitter.getBuilder()->CreateUnreachable(); + + // Hacky: create a new BB for any more code that we might generate + llvm::BasicBlock* continue_bb + = llvm::BasicBlock::Create(g.context, "cant_reach", irstate->getLLVMFunction()); + emitter.setCurrentBasicBlock(continue_bb); + exc_type = exc_value = exc_tb = undefVariable(); - // TODO: should we not emit the rest of the block? I (kmod) think I tried that and - // ran into some sort of issue, but I don't remember what it was. + // TODO: we should just call endBlock instead. It looks like the implementation + // of that has some issues though, and it might end up generating code as well. ANd + // then I'm not sure that the higher-level irgen.cpp would handle that well. // endBlock(DEAD); } From a994ec05add76ad3dea5a73ff131bd7f63beda8d Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 03:05:35 +0000 Subject: [PATCH 02/11] Fix a rewriter bug We were doing a "call bumpUse() early" optimization to free up registers when we can, but as a side-effect it looked to the refcounter like the reference was done being used. --- src/asm_writing/rewriter.cpp | 23 +++++++++++++++-------- src/asm_writing/rewriter.h | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/asm_writing/rewriter.cpp b/src/asm_writing/rewriter.cpp index d9843bc10..c08bd26f9 100644 --- a/src/asm_writing/rewriter.cpp +++ b/src/asm_writing/rewriter.cpp @@ -432,14 +432,15 @@ void Rewriter::_getAttr(RewriterVar* result, RewriterVar* ptr, int offset, Locat // mov ($0x133), %rdi assembler::Register ptr_reg = ptr->getInReg(Location::any(), /* allow_constant_in_reg */ true); - // It's okay to bump the use now, since it's fine to allocate the result - // in the same register as ptr - ptr->bumpUse(); + ptr->bumpUseEarlyIfPossible(); assembler::Register newvar_reg = result->initializeInReg(dest); assembler->mov_generic(assembler::Indirect(ptr_reg, offset), newvar_reg, type); result->releaseIfNoUses(); + + ptr->bumpUseLateIfNecessary(); + assertConsistent(); } @@ -457,11 +458,12 @@ void Rewriter::_getAttrDouble(RewriterVar* result, RewriterVar* ptr, int offset, assembler::Register ptr_reg = ptr->getInReg(); - ptr->bumpUse(); + ptr->bumpUseEarlyIfPossible(); assembler::XMMRegister newvar_reg = result->initializeInXMMReg(dest); assembler->movsd(assembler::Indirect(ptr_reg, offset), newvar_reg); + ptr->bumpUseLateIfNecessary(); result->releaseIfNoUses(); assertConsistent(); } @@ -480,7 +482,7 @@ void Rewriter::_getAttrFloat(RewriterVar* result, RewriterVar* ptr, int offset, assembler::Register ptr_reg = ptr->getInReg(); - ptr->bumpUse(); + ptr->bumpUseEarlyIfPossible(); assembler::XMMRegister newvar_reg = result->initializeInXMMReg(dest); assembler->movss(assembler::Indirect(ptr_reg, offset), newvar_reg); @@ -488,6 +490,7 @@ void Rewriter::_getAttrFloat(RewriterVar* result, RewriterVar* ptr, int offset, // cast to double assembler->cvtss2sd(newvar_reg, newvar_reg); + ptr->bumpUseLateIfNecessary(); result->releaseIfNoUses(); assertConsistent(); } @@ -633,8 +636,8 @@ void Rewriter::_cmp(RewriterVar* result, RewriterVar* v1, AST_TYPE::AST_TYPE cmp assembler::Register v2_reg = v2->getInReg(); assert(v1_reg != v2_reg); // TODO how do we ensure this? - v1->bumpUse(); - v2->bumpUse(); + v1->bumpUseEarlyIfPossible(); + v2->bumpUseEarlyIfPossible(); assembler::Register newvar_reg = allocReg(dest); result->initializeInReg(newvar_reg); @@ -650,6 +653,9 @@ void Rewriter::_cmp(RewriterVar* result, RewriterVar* v1, AST_TYPE::AST_TYPE cmp RELEASE_ASSERT(0, "%d", cmp_type); } + v1->bumpUseLateIfNecessary(); + v2->bumpUseLateIfNecessary(); + result->releaseIfNoUses(); assertConsistent(); } @@ -668,7 +674,7 @@ void Rewriter::_toBool(RewriterVar* result, RewriterVar* var, Location dest) { assembler::Register this_reg = var->getInReg(); - var->bumpUse(); + var->bumpUseEarlyIfPossible(); assembler::Register result_reg = allocReg(dest); result->initializeInReg(result_reg); @@ -676,6 +682,7 @@ void Rewriter::_toBool(RewriterVar* result, RewriterVar* var, Location dest) { assembler->test(this_reg, this_reg); assembler->setnz(result_reg); + var->bumpUseLateIfNecessary(); result->releaseIfNoUses(); assertConsistent(); } diff --git a/src/asm_writing/rewriter.h b/src/asm_writing/rewriter.h index d4811c3a9..385c05ec7 100644 --- a/src/asm_writing/rewriter.h +++ b/src/asm_writing/rewriter.h @@ -227,6 +227,24 @@ class RewriterVar { llvm::SmallVector uses; int next_use; void bumpUse(); + + // Helper functions for a common optimization. + // We want to be able to call bumpUse() as soon as the register is able to be used. + // But if we have an owned ref in that variable, we need to hold on to it until + // the end of the operation, even though its register is theoretically available to use. + // So before we would just call bumpUse() early. Now we can do + // bumpUseEarlyIfPossible(); + // /* some code */ + // bumpUseLateIfNecessary(); + void bumpUseEarlyIfPossible() { + if (reftype != RefType::OWNED) + bumpUse(); + } + void bumpUseLateIfNecessary() { + if (reftype == RefType::OWNED) + bumpUse(); + } + // Call this on the result at the end of the action in which it's created // TODO we should have a better way of dealing with variables that have 0 uses void releaseIfNoUses(); From 8e8c9a89db3863b54099396204da8b7ef30cd3d4 Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 01:27:42 +0000 Subject: [PATCH 03/11] Copy in CPython's descrobject.c Not using it in this commit, just wanted to get the unmodified version in so it's easier to see the changes. --- from_cpython/Objects/descrobject.c | 1440 ++++++++++++++++++++++++++++ 1 file changed, 1440 insertions(+) create mode 100644 from_cpython/Objects/descrobject.c diff --git a/from_cpython/Objects/descrobject.c b/from_cpython/Objects/descrobject.c new file mode 100644 index 000000000..3e9b03451 --- /dev/null +++ b/from_cpython/Objects/descrobject.c @@ -0,0 +1,1440 @@ +/* Descriptors -- a new, flexible way to describe attributes */ + +#include "Python.h" +#include "structmember.h" /* Why is this not included in Python.h? */ + +static void +descr_dealloc(PyDescrObject *descr) +{ + _PyObject_GC_UNTRACK(descr); + Py_XDECREF(descr->d_type); + Py_XDECREF(descr->d_name); + PyObject_GC_Del(descr); +} + +static char * +descr_name(PyDescrObject *descr) +{ + if (descr->d_name != NULL && PyString_Check(descr->d_name)) + return PyString_AS_STRING(descr->d_name); + else + return "?"; +} + +static PyObject * +descr_repr(PyDescrObject *descr, char *format) +{ + return PyString_FromFormat(format, descr_name(descr), + descr->d_type->tp_name); +} + +static PyObject * +method_repr(PyMethodDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + ""); +} + +static PyObject * +member_repr(PyMemberDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + ""); +} + +static PyObject * +getset_repr(PyGetSetDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + ""); +} + +static PyObject * +wrapperdescr_repr(PyWrapperDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + ""); +} + +static int +descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres) +{ + if (obj == NULL) { + Py_INCREF(descr); + *pres = (PyObject *)descr; + return 1; + } + if (!PyObject_TypeCheck(obj, descr->d_type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for '%s' objects " + "doesn't apply to '%s' object", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + obj->ob_type->tp_name); + *pres = NULL; + return 1; + } + return 0; +} + +static PyObject * +classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) +{ + /* Ensure a valid type. Class methods ignore obj. */ + if (type == NULL) { + if (obj != NULL) + type = (PyObject *)obj->ob_type; + else { + /* Wot - no type?! */ + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for type '%s' " + "needs either an object or a type", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + } + if (!PyType_Check(type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for type '%s' " + "needs a type, not a '%s' as arg 2", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + type->ob_type->tp_name); + return NULL; + } + if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for type '%s' " + "doesn't apply to type '%s'", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + ((PyTypeObject *)type)->tp_name); + return NULL; + } + return PyCFunction_New(descr->d_method, type); +} + +static PyObject * +method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + return PyCFunction_New(descr->d_method, obj); +} + +static PyObject * +member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + return PyMember_GetOne((char *)obj, descr->d_member); +} + +static PyObject * +getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + if (descr->d_getset->get != NULL) + return descr->d_getset->get(obj, descr->d_getset->closure); + PyErr_Format(PyExc_AttributeError, + "attribute '%.300s' of '%.100s' objects is not readable", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; +} + +static PyObject * +wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + return PyWrapper_New((PyObject *)descr, obj); +} + +static int +descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value, + int *pres) +{ + assert(obj != NULL); + if (!PyObject_TypeCheck(obj, descr->d_type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.200s' for '%.100s' objects " + "doesn't apply to '%.100s' object", + descr_name(descr), + descr->d_type->tp_name, + obj->ob_type->tp_name); + *pres = -1; + return 1; + } + return 0; +} + +static int +member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value) +{ + int res; + + if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) + return res; + return PyMember_SetOne((char *)obj, descr->d_member, value); +} + +static int +getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) +{ + int res; + + if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) + return res; + if (descr->d_getset->set != NULL) + return descr->d_getset->set(obj, value, + descr->d_getset->closure); + PyErr_Format(PyExc_AttributeError, + "attribute '%.300s' of '%.100s' objects is not writable", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return -1; +} + +static PyObject * +methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) +{ + Py_ssize_t argc; + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + assert(PyTuple_Check(args)); + argc = PyTuple_GET_SIZE(args); + if (argc < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.300s' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + self = PyTuple_GET_ITEM(args, 0); + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.200s' " + "requires a '%.100s' object " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + self->ob_type->tp_name); + return NULL; + } + + func = PyCFunction_New(descr->d_method, self); + if (func == NULL) + return NULL; + args = PyTuple_GetSlice(args, 1, argc); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObjectWithKeywords(func, args, kwds); + Py_DECREF(args); + Py_DECREF(func); + return result; +} + +static PyObject * +classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, + PyObject *kwds) +{ + Py_ssize_t argc; + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + assert(PyTuple_Check(args)); + argc = PyTuple_GET_SIZE(args); + if (argc < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + self = PyTuple_GET_ITEM(args, 0); + if (!PyType_Check(self)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' requires a type " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), + self->ob_type->tp_name); + return NULL; + } + if (!PyType_IsSubtype((PyTypeObject *)self, descr->d_type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' " + "requires a subtype of '%.100s' " + "but received '%.100s", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + self->ob_type->tp_name); + return NULL; + } + + func = PyCFunction_New(descr->d_method, self); + if (func == NULL) + return NULL; + args = PyTuple_GetSlice(args, 1, argc); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObjectWithKeywords(func, args, kwds); + Py_DECREF(func); + Py_DECREF(args); + return result; +} + +static PyObject * +wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) +{ + Py_ssize_t argc; + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + assert(PyTuple_Check(args)); + argc = PyTuple_GET_SIZE(args); + if (argc < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.300s' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + self = PyTuple_GET_ITEM(args, 0); + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.200s' " + "requires a '%.100s' object " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + self->ob_type->tp_name); + return NULL; + } + + func = PyWrapper_New((PyObject *)descr, self); + if (func == NULL) + return NULL; + args = PyTuple_GetSlice(args, 1, argc); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObjectWithKeywords(func, args, kwds); + Py_DECREF(args); + Py_DECREF(func); + return result; +} + +static PyObject * +method_get_doc(PyMethodDescrObject *descr, void *closure) +{ + if (descr->d_method->ml_doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_method->ml_doc); +} + +static PyMemberDef descr_members[] = { + {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, + {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY}, + {0} +}; + +static PyGetSetDef method_getset[] = { + {"__doc__", (getter)method_get_doc}, + {0} +}; + +static PyObject * +member_get_doc(PyMemberDescrObject *descr, void *closure) +{ + if (descr->d_member->doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_member->doc); +} + +static PyGetSetDef member_getset[] = { + {"__doc__", (getter)member_get_doc}, + {0} +}; + +static PyObject * +getset_get_doc(PyGetSetDescrObject *descr, void *closure) +{ + if (descr->d_getset->doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_getset->doc); +} + +static PyGetSetDef getset_getset[] = { + {"__doc__", (getter)getset_get_doc}, + {0} +}; + +static PyObject * +wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) +{ + if (descr->d_base->doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_base->doc); +} + +static PyGetSetDef wrapperdescr_getset[] = { + {"__doc__", (getter)wrapperdescr_get_doc}, + {0} +}; + +static int +descr_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyDescrObject *descr = (PyDescrObject *)self; + Py_VISIT(descr->d_type); + return 0; +} + +static PyTypeObject PyMethodDescr_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "method_descriptor", + sizeof(PyMethodDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)method_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)methoddescr_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + method_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)method_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +/* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */ +static PyTypeObject PyClassMethodDescr_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "classmethod_descriptor", + sizeof(PyMethodDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)method_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)classmethoddescr_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + method_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)classmethod_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +PyTypeObject PyMemberDescr_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "member_descriptor", + sizeof(PyMemberDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)member_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + member_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)member_get, /* tp_descr_get */ + (descrsetfunc)member_set, /* tp_descr_set */ +}; + +PyTypeObject PyGetSetDescr_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "getset_descriptor", + sizeof(PyGetSetDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)getset_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + getset_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)getset_get, /* tp_descr_get */ + (descrsetfunc)getset_set, /* tp_descr_set */ +}; + +PyTypeObject PyWrapperDescr_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "wrapper_descriptor", + sizeof(PyWrapperDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)wrapperdescr_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)wrapperdescr_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + wrapperdescr_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)wrapperdescr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +static PyDescrObject * +descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) +{ + PyDescrObject *descr; + + descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); + if (descr != NULL) { + Py_XINCREF(type); + descr->d_type = type; + descr->d_name = PyString_InternFromString(name); + if (descr->d_name == NULL) { + Py_DECREF(descr); + descr = NULL; + } + } + return descr; +} + +PyObject * +PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) +{ + PyMethodDescrObject *descr; + + descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type, + type, method->ml_name); + if (descr != NULL) + descr->d_method = method; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) +{ + PyMethodDescrObject *descr; + + descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type, + type, method->ml_name); + if (descr != NULL) + descr->d_method = method; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) +{ + PyMemberDescrObject *descr; + + descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type, + type, member->name); + if (descr != NULL) + descr->d_member = member; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset) +{ + PyGetSetDescrObject *descr; + + descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type, + type, getset->name); + if (descr != NULL) + descr->d_getset = getset; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) +{ + PyWrapperDescrObject *descr; + + descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type, + type, base->name); + if (descr != NULL) { + descr->d_base = base; + descr->d_wrapped = wrapped; + } + return (PyObject *)descr; +} + + +/* --- Readonly proxy for dictionaries (actually any mapping) --- */ + +/* This has no reason to be in this file except that adding new files is a + bit of a pain */ + +typedef struct { + PyObject_HEAD + PyObject *dict; +} proxyobject; + +static Py_ssize_t +proxy_len(proxyobject *pp) +{ + return PyObject_Size(pp->dict); +} + +static PyObject * +proxy_getitem(proxyobject *pp, PyObject *key) +{ + return PyObject_GetItem(pp->dict, key); +} + +static PyMappingMethods proxy_as_mapping = { + (lenfunc)proxy_len, /* mp_length */ + (binaryfunc)proxy_getitem, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + +static int +proxy_contains(proxyobject *pp, PyObject *key) +{ + return PyDict_Contains(pp->dict, key); +} + +static PySequenceMethods proxy_as_sequence = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)proxy_contains, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyObject * +proxy_has_key(proxyobject *pp, PyObject *key) +{ + int res = PyDict_Contains(pp->dict, key); + if (res < 0) + return NULL; + return PyBool_FromLong(res); +} + +static PyObject * +proxy_get(proxyobject *pp, PyObject *args) +{ + PyObject *key, *def = Py_None; + + if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) + return NULL; + return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); +} + +static PyObject * +proxy_keys(proxyobject *pp) +{ + return PyMapping_Keys(pp->dict); +} + +static PyObject * +proxy_values(proxyobject *pp) +{ + return PyMapping_Values(pp->dict); +} + +static PyObject * +proxy_items(proxyobject *pp) +{ + return PyMapping_Items(pp->dict); +} + +static PyObject * +proxy_iterkeys(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "iterkeys", NULL); +} + +static PyObject * +proxy_itervalues(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "itervalues", NULL); +} + +static PyObject * +proxy_iteritems(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "iteritems", NULL); +} +static PyObject * +proxy_copy(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "copy", NULL); +} + +static PyMethodDef proxy_methods[] = { + {"has_key", (PyCFunction)proxy_has_key, METH_O, + PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")}, + {"get", (PyCFunction)proxy_get, METH_VARARGS, + PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d." + " d defaults to None.")}, + {"keys", (PyCFunction)proxy_keys, METH_NOARGS, + PyDoc_STR("D.keys() -> list of D's keys")}, + {"values", (PyCFunction)proxy_values, METH_NOARGS, + PyDoc_STR("D.values() -> list of D's values")}, + {"items", (PyCFunction)proxy_items, METH_NOARGS, + PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")}, + {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS, + PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")}, + {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS, + PyDoc_STR("D.itervalues() -> an iterator over the values of D")}, + {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS, + PyDoc_STR("D.iteritems() ->" + " an iterator over the (key, value) items of D")}, + {"copy", (PyCFunction)proxy_copy, METH_NOARGS, + PyDoc_STR("D.copy() -> a shallow copy of D")}, + {0} +}; + +static void +proxy_dealloc(proxyobject *pp) +{ + _PyObject_GC_UNTRACK(pp); + Py_DECREF(pp->dict); + PyObject_GC_Del(pp); +} + +static PyObject * +proxy_getiter(proxyobject *pp) +{ + return PyObject_GetIter(pp->dict); +} + +static PyObject * +proxy_str(proxyobject *pp) +{ + return PyObject_Str(pp->dict); +} + +static PyObject * +proxy_repr(proxyobject *pp) +{ + PyObject *dictrepr; + PyObject *result; + + dictrepr = PyObject_Repr(pp->dict); + if (dictrepr == NULL) + return NULL; + result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr)); + Py_DECREF(dictrepr); + return result; +} + +static int +proxy_traverse(PyObject *self, visitproc visit, void *arg) +{ + proxyobject *pp = (proxyobject *)self; + Py_VISIT(pp->dict); + return 0; +} + +static int +proxy_compare(proxyobject *v, PyObject *w) +{ + return PyObject_Compare(v->dict, w); +} + +static PyObject * +proxy_richcompare(proxyobject *v, PyObject *w, int op) +{ + return PyObject_RichCompare(v->dict, w, op); +} + +PyTypeObject PyDictProxy_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "dictproxy", /* tp_name */ + sizeof(proxyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)proxy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)proxy_compare, /* tp_compare */ + (reprfunc)proxy_repr, /* tp_repr */ + 0, /* tp_as_number */ + &proxy_as_sequence, /* tp_as_sequence */ + &proxy_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)proxy_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + proxy_traverse, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)proxy_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)proxy_getiter, /* tp_iter */ + 0, /* tp_iternext */ + proxy_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +PyObject * +PyDictProxy_New(PyObject *dict) +{ + proxyobject *pp; + + pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type); + if (pp != NULL) { + Py_INCREF(dict); + pp->dict = dict; + _PyObject_GC_TRACK(pp); + } + return (PyObject *)pp; +} + + +/* --- Wrapper object for "slot" methods --- */ + +/* This has no reason to be in this file except that adding new files is a + bit of a pain */ + +typedef struct { + PyObject_HEAD + PyWrapperDescrObject *descr; + PyObject *self; +} wrapperobject; + +static void +wrapper_dealloc(wrapperobject *wp) +{ + PyObject_GC_UnTrack(wp); + Py_TRASHCAN_SAFE_BEGIN(wp) + Py_XDECREF(wp->descr); + Py_XDECREF(wp->self); + PyObject_GC_Del(wp); + Py_TRASHCAN_SAFE_END(wp) +} + +static int +wrapper_compare(wrapperobject *a, wrapperobject *b) +{ + if (a->descr == b->descr) + return PyObject_Compare(a->self, b->self); + else + return (a->descr < b->descr) ? -1 : 1; +} + +static long +wrapper_hash(wrapperobject *wp) +{ + int x, y; + x = _Py_HashPointer(wp->descr); + if (x == -1) + return -1; + y = PyObject_Hash(wp->self); + if (y == -1) + return -1; + x = x ^ y; + if (x == -1) + x = -2; + return x; +} + +static PyObject * +wrapper_repr(wrapperobject *wp) +{ + return PyString_FromFormat("", + wp->descr->d_base->name, + wp->self->ob_type->tp_name, + wp->self); +} + +static PyMemberDef wrapper_members[] = { + {"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY}, + {0} +}; + +static PyObject * +wrapper_objclass(wrapperobject *wp) +{ + PyObject *c = (PyObject *)wp->descr->d_type; + + Py_INCREF(c); + return c; +} + +static PyObject * +wrapper_name(wrapperobject *wp) +{ + char *s = wp->descr->d_base->name; + + return PyString_FromString(s); +} + +static PyObject * +wrapper_doc(wrapperobject *wp) +{ + char *s = wp->descr->d_base->doc; + + if (s == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + else { + return PyString_FromString(s); + } +} + +static PyGetSetDef wrapper_getsets[] = { + {"__objclass__", (getter)wrapper_objclass}, + {"__name__", (getter)wrapper_name}, + {"__doc__", (getter)wrapper_doc}, + {0} +}; + +static PyObject * +wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) +{ + wrapperfunc wrapper = wp->descr->d_base->wrapper; + PyObject *self = wp->self; + + if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { + wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; + return (*wk)(self, args, wp->descr->d_wrapped, kwds); + } + + if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { + PyErr_Format(PyExc_TypeError, + "wrapper %s doesn't take keyword arguments", + wp->descr->d_base->name); + return NULL; + } + return (*wrapper)(self, args, wp->descr->d_wrapped); +} + +static int +wrapper_traverse(PyObject *self, visitproc visit, void *arg) +{ + wrapperobject *wp = (wrapperobject *)self; + Py_VISIT(wp->descr); + Py_VISIT(wp->self); + return 0; +} + +static PyTypeObject wrappertype = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "method-wrapper", /* tp_name */ + sizeof(wrapperobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)wrapper_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)wrapper_compare, /* tp_compare */ + (reprfunc)wrapper_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)wrapper_hash, /* tp_hash */ + (ternaryfunc)wrapper_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + wrapper_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + wrapper_members, /* tp_members */ + wrapper_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +PyObject * +PyWrapper_New(PyObject *d, PyObject *self) +{ + wrapperobject *wp; + PyWrapperDescrObject *descr; + + assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); + descr = (PyWrapperDescrObject *)d; + assert(_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)(descr->d_type))); + + wp = PyObject_GC_New(wrapperobject, &wrappertype); + if (wp != NULL) { + Py_INCREF(descr); + wp->descr = descr; + Py_INCREF(self); + wp->self = self; + _PyObject_GC_TRACK(wp); + } + return (PyObject *)wp; +} + + +/* A built-in 'property' type */ + +/* + class property(object): + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + if doc is None and fget is not None and hasattr(fget, "__doc__"): + doc = fget.__doc__ + self.__get = fget + self.__set = fset + self.__del = fdel + self.__doc__ = doc + + def __get__(self, inst, type=None): + if inst is None: + return self + if self.__get is None: + raise AttributeError, "unreadable attribute" + return self.__get(inst) + + def __set__(self, inst, value): + if self.__set is None: + raise AttributeError, "can't set attribute" + return self.__set(inst, value) + + def __delete__(self, inst): + if self.__del is None: + raise AttributeError, "can't delete attribute" + return self.__del(inst) + +*/ + +typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; + int getter_doc; +} propertyobject; + +static PyObject * property_copy(PyObject *, PyObject *, PyObject *, + PyObject *); + +static PyMemberDef property_members[] = { + {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, + {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, + {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, + {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, + {0} +}; + + +PyDoc_STRVAR(getter_doc, + "Descriptor to change the getter on a property."); + +static PyObject * +property_getter(PyObject *self, PyObject *getter) +{ + return property_copy(self, getter, NULL, NULL); +} + + +PyDoc_STRVAR(setter_doc, + "Descriptor to change the setter on a property."); + +static PyObject * +property_setter(PyObject *self, PyObject *setter) +{ + return property_copy(self, NULL, setter, NULL); +} + + +PyDoc_STRVAR(deleter_doc, + "Descriptor to change the deleter on a property."); + +static PyObject * +property_deleter(PyObject *self, PyObject *deleter) +{ + return property_copy(self, NULL, NULL, deleter); +} + + +static PyMethodDef property_methods[] = { + {"getter", property_getter, METH_O, getter_doc}, + {"setter", property_setter, METH_O, setter_doc}, + {"deleter", property_deleter, METH_O, deleter_doc}, + {0} +}; + + +static void +property_dealloc(PyObject *self) +{ + propertyobject *gs = (propertyobject *)self; + + _PyObject_GC_UNTRACK(self); + Py_XDECREF(gs->prop_get); + Py_XDECREF(gs->prop_set); + Py_XDECREF(gs->prop_del); + Py_XDECREF(gs->prop_doc); + self->ob_type->tp_free(self); +} + +static PyObject * +property_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + propertyobject *gs = (propertyobject *)self; + + if (obj == NULL || obj == Py_None) { + Py_INCREF(self); + return self; + } + if (gs->prop_get == NULL) { + PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); + return NULL; + } + return PyObject_CallFunction(gs->prop_get, "(O)", obj); +} + +static int +property_descr_set(PyObject *self, PyObject *obj, PyObject *value) +{ + propertyobject *gs = (propertyobject *)self; + PyObject *func, *res; + + if (value == NULL) + func = gs->prop_del; + else + func = gs->prop_set; + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, + value == NULL ? + "can't delete attribute" : + "can't set attribute"); + return -1; + } + if (value == NULL) + res = PyObject_CallFunction(func, "(O)", obj); + else + res = PyObject_CallFunction(func, "(OO)", obj, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static PyObject * +property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del) +{ + propertyobject *pold = (propertyobject *)old; + PyObject *new, *type, *doc; + + type = PyObject_Type(old); + if (type == NULL) + return NULL; + + if (get == NULL || get == Py_None) { + Py_XDECREF(get); + get = pold->prop_get ? pold->prop_get : Py_None; + } + if (set == NULL || set == Py_None) { + Py_XDECREF(set); + set = pold->prop_set ? pold->prop_set : Py_None; + } + if (del == NULL || del == Py_None) { + Py_XDECREF(del); + del = pold->prop_del ? pold->prop_del : Py_None; + } + if (pold->getter_doc && get != Py_None) { + /* make _init use __doc__ from getter */ + doc = Py_None; + } + else { + doc = pold->prop_doc ? pold->prop_doc : Py_None; + } + + new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); + Py_DECREF(type); + if (new == NULL) + return NULL; + return new; +} + +static int +property_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; + static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; + propertyobject *prop = (propertyobject *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", + kwlist, &get, &set, &del, &doc)) + return -1; + + if (get == Py_None) + get = NULL; + if (set == Py_None) + set = NULL; + if (del == Py_None) + del = NULL; + + Py_XINCREF(get); + Py_XINCREF(set); + Py_XINCREF(del); + Py_XINCREF(doc); + + prop->prop_get = get; + prop->prop_set = set; + prop->prop_del = del; + prop->prop_doc = doc; + prop->getter_doc = 0; + + /* if no docstring given and the getter has one, use that one */ + if ((doc == NULL || doc == Py_None) && get != NULL) { + PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); + if (get_doc) { + if (Py_TYPE(self) == &PyProperty_Type) { + Py_XDECREF(prop->prop_doc); + prop->prop_doc = get_doc; + } + else { + /* If this is a property subclass, put __doc__ + in dict of the subclass instance instead, + otherwise it gets shadowed by __doc__ in the + class's dict. */ + int err = PyObject_SetAttrString(self, "__doc__", get_doc); + Py_DECREF(get_doc); + if (err < 0) + return -1; + } + prop->getter_doc = 1; + } + else if (PyErr_ExceptionMatches(PyExc_Exception)) { + PyErr_Clear(); + } + else { + return -1; + } + } + + return 0; +} + +PyDoc_STRVAR(property_doc, +"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" +"\n" +"fget is a function to be used for getting an attribute value, and likewise\n" +"fset is a function for setting, and fdel a function for del'ing, an\n" +"attribute. Typical use is to define a managed attribute x:\n\n" +"class C(object):\n" +" def getx(self): return self._x\n" +" def setx(self, value): self._x = value\n" +" def delx(self): del self._x\n" +" x = property(getx, setx, delx, \"I'm the 'x' property.\")\n" +"\n" +"Decorators make defining new properties or modifying existing ones easy:\n\n" +"class C(object):\n" +" @property\n" +" def x(self):\n" +" \"I am the 'x' property.\"\n" +" return self._x\n" +" @x.setter\n" +" def x(self, value):\n" +" self._x = value\n" +" @x.deleter\n" +" def x(self):\n" +" del self._x\n" +); + +static int +property_traverse(PyObject *self, visitproc visit, void *arg) +{ + propertyobject *pp = (propertyobject *)self; + Py_VISIT(pp->prop_get); + Py_VISIT(pp->prop_set); + Py_VISIT(pp->prop_del); + Py_VISIT(pp->prop_doc); + return 0; +} + +PyTypeObject PyProperty_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "property", /* tp_name */ + sizeof(propertyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + property_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + property_doc, /* tp_doc */ + property_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + property_methods, /* tp_methods */ + property_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + property_descr_get, /* tp_descr_get */ + property_descr_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + property_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; From 4c3c6933ad836aec50299dc87f8323883f621ddf Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 01:43:39 +0000 Subject: [PATCH 04/11] Switch to using CPython's getset, member, wrapperdescr, and wrapper types via their descrobject.c --- from_cpython/CMakeLists.txt | 2 +- from_cpython/Include/descrobject.h | 31 ++- from_cpython/Include/structmember.h | 2 +- from_cpython/Objects/descrobject.c | 66 ++++-- from_cpython/Objects/dictproxy.c | 244 ---------------------- from_cpython/Objects/structseq.c | 4 +- src/capi/typeobject.cpp | 151 +++++++++----- src/capi/typeobject.h | 3 + src/capi/types.h | 4 +- src/codegen/irgen/hooks.cpp | 2 +- src/core/types.h | 7 +- src/runtime/builtin_modules/sys.cpp | 4 +- src/runtime/capi.cpp | 3 +- src/runtime/code.cpp | 16 +- src/runtime/code.h | 16 +- src/runtime/complex.cpp | 13 +- src/runtime/descr.cpp | 246 +++++----------------- src/runtime/float.cpp | 19 +- src/runtime/frame.cpp | 18 +- src/runtime/generator.cpp | 4 +- src/runtime/int.cpp | 13 +- src/runtime/long.cpp | 15 +- src/runtime/objmodel.cpp | 158 +++++++-------- src/runtime/str.cpp | 5 +- src/runtime/super.cpp | 9 +- src/runtime/types.cpp | 303 +++++++++------------------- src/runtime/types.h | 123 +---------- test/tests/wrapperdesc.py | 1 + 28 files changed, 462 insertions(+), 1020 deletions(-) delete mode 100644 from_cpython/Objects/dictproxy.c diff --git a/from_cpython/CMakeLists.txt b/from_cpython/CMakeLists.txt index c524f32f2..aaa500dae 100644 --- a/from_cpython/CMakeLists.txt +++ b/from_cpython/CMakeLists.txt @@ -86,8 +86,8 @@ file(GLOB_RECURSE STDOBJECT_SRCS Objects capsule.c cobject.c complexobject.c + descrobject.c dictobject.c - dictproxy.c errors.c exceptions.c floatobject.c diff --git a/from_cpython/Include/descrobject.h b/from_cpython/Include/descrobject.h index 2fcb99fcd..929cf4786 100644 --- a/from_cpython/Include/descrobject.h +++ b/from_cpython/Include/descrobject.h @@ -24,14 +24,16 @@ typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds); +// Pyston addition: faster CC typedef PyObject *(*wrapperfunc_1arg)(PyObject *self, void *wrapped); +typedef PyObject *(*wrapperfunc_2arg)(PyObject *self, PyObject* arg, void *wrapped); struct wrapperbase { - char *name; + const char *name; int offset; void *function; wrapperfunc wrapper; - char *doc; + const char *doc; int flags; PyObject *name_strobj; }; @@ -45,8 +47,6 @@ struct wrapperbase { /* Various kinds of descriptor objects */ -// Pyston change: these are not our object layouts -#if 0 #define PyDescr_COMMON \ PyObject_HEAD \ PyTypeObject *d_type; \ @@ -56,10 +56,12 @@ typedef struct { PyDescr_COMMON; } PyDescrObject; +#if 0 typedef struct { PyDescr_COMMON; PyMethodDef *d_method; } PyMethodDescrObject; +#endif typedef struct { PyDescr_COMMON; @@ -76,21 +78,11 @@ typedef struct { struct wrapperbase *d_base; void *d_wrapped; /* This can be any function pointer */ } PyWrapperDescrObject; -#endif -// (Pyston TODO: add opaque definitions of those names) -// Pyston change: these are not static objects any more -#if 0 PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type; PyAPI_DATA(PyTypeObject) PyDictProxy_Type; PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type; PyAPI_DATA(PyTypeObject) PyMemberDescr_Type; -#else -PyAPI_DATA(PyTypeObject) PyDictProxy_Type; -#endif -// (Pyston TODO: add #defines to our names) -PyAPI_DATA(PyTypeObject*) wrapperdescr_cls; -#define PyWrapperDescr_Type (*wrapperdescr_cls) PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *) PYSTON_NOEXCEPT; PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *) PYSTON_NOEXCEPT; @@ -106,8 +98,15 @@ PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *) PYSTON_NOEXCEPT; PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *) PYSTON_NOEXCEPT; -// Pyston change: this is no longer a static object -//PyAPI_DATA(PyTypeObject) PyProperty_Type; +PyAPI_DATA(PyTypeObject) PyProperty_Type; + +// Pyston change: exposed these +typedef struct { + PyObject_HEAD + PyWrapperDescrObject *descr; + PyObject *self; +} wrapperobject; +PyAPI_DATA(PyTypeObject) wrappertype; #ifdef __cplusplus } diff --git a/from_cpython/Include/structmember.h b/from_cpython/Include/structmember.h index f9d9b4933..087829640 100644 --- a/from_cpython/Include/structmember.h +++ b/from_cpython/Include/structmember.h @@ -37,7 +37,7 @@ struct memberlist { typedef struct PyMemberDef { /* Current version, use this */ - char *name; + const char *name; int type; Py_ssize_t offset; int flags; diff --git a/from_cpython/Objects/descrobject.c b/from_cpython/Objects/descrobject.c index 3e9b03451..15d4d00ee 100644 --- a/from_cpython/Objects/descrobject.c +++ b/from_cpython/Objects/descrobject.c @@ -1,3 +1,5 @@ +// This file is originally from CPython 2.7, with modifications for Pyston + /* Descriptors -- a new, flexible way to describe attributes */ #include "Python.h" @@ -28,12 +30,14 @@ descr_repr(PyDescrObject *descr, char *format) descr->d_type->tp_name); } +#if 0 static PyObject * method_repr(PyMethodDescrObject *descr) { return descr_repr((PyDescrObject *)descr, ""); } +#endif static PyObject * member_repr(PyMemberDescrObject *descr) @@ -77,6 +81,8 @@ descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres) return 0; } +// Pyston change: not using this for now +#if 0 static PyObject * classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) { @@ -124,6 +130,7 @@ method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) return res; return PyCFunction_New(descr->d_method, obj); } +#endif static PyObject * member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) @@ -206,6 +213,7 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) return -1; } +#if 0 static PyObject * methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) { @@ -301,6 +309,7 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, Py_DECREF(args); return result; } +#endif static PyObject * wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) @@ -346,6 +355,7 @@ wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) return result; } +#if 0 static PyObject * method_get_doc(PyMethodDescrObject *descr, void *closure) { @@ -355,6 +365,7 @@ method_get_doc(PyMethodDescrObject *descr, void *closure) } return PyString_FromString(descr->d_method->ml_doc); } +#endif static PyMemberDef descr_members[] = { {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, @@ -362,10 +373,12 @@ static PyMemberDef descr_members[] = { {0} }; +#if 0 static PyGetSetDef method_getset[] = { {"__doc__", (getter)method_get_doc}, {0} }; +#endif static PyObject * member_get_doc(PyMemberDescrObject *descr, void *closure) @@ -420,8 +433,9 @@ descr_traverse(PyObject *self, visitproc visit, void *arg) return 0; } +#if 0 static PyTypeObject PyMethodDescr_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "method_descriptor", sizeof(PyMethodDescrObject), 0, @@ -459,7 +473,7 @@ static PyTypeObject PyMethodDescr_Type = { /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */ static PyTypeObject PyClassMethodDescr_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "classmethod_descriptor", sizeof(PyMethodDescrObject), 0, @@ -494,9 +508,10 @@ static PyTypeObject PyClassMethodDescr_Type = { (descrgetfunc)classmethod_get, /* tp_descr_get */ 0, /* tp_descr_set */ }; +#endif PyTypeObject PyMemberDescr_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "member_descriptor", sizeof(PyMemberDescrObject), 0, @@ -533,7 +548,7 @@ PyTypeObject PyMemberDescr_Type = { }; PyTypeObject PyGetSetDescr_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "getset_descriptor", sizeof(PyGetSetDescrObject), 0, @@ -570,7 +585,7 @@ PyTypeObject PyGetSetDescr_Type = { }; PyTypeObject PyWrapperDescr_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "wrapper_descriptor", sizeof(PyWrapperDescrObject), 0, @@ -624,6 +639,7 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) return descr; } +#if 0 PyObject * PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) { @@ -647,6 +663,7 @@ PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) descr->d_method = method; return (PyObject *)descr; } +#endif PyObject * PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) @@ -873,7 +890,7 @@ proxy_richcompare(proxyobject *v, PyObject *w, int op) } PyTypeObject PyDictProxy_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "dictproxy", /* tp_name */ sizeof(proxyobject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -930,12 +947,6 @@ PyDictProxy_New(PyObject *dict) /* This has no reason to be in this file except that adding new files is a bit of a pain */ -typedef struct { - PyObject_HEAD - PyWrapperDescrObject *descr; - PyObject *self; -} wrapperobject; - static void wrapper_dealloc(wrapperobject *wp) { @@ -998,7 +1009,7 @@ wrapper_objclass(wrapperobject *wp) static PyObject * wrapper_name(wrapperobject *wp) { - char *s = wp->descr->d_base->name; + /* Pyston change: made const */ const char *s = wp->descr->d_base->name; return PyString_FromString(s); } @@ -1006,7 +1017,7 @@ wrapper_name(wrapperobject *wp) static PyObject * wrapper_doc(wrapperobject *wp) { - char *s = wp->descr->d_base->doc; + /* Pyston change: made const */ const char *s = wp->descr->d_base->doc; if (s == NULL) { Py_INCREF(Py_None); @@ -1024,6 +1035,8 @@ static PyGetSetDef wrapper_getsets[] = { {0} }; +// Pyston note -- this function will usually not get hit, since we override tpp_call (which takes +// precedence over tp_call) static PyObject * wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) { @@ -1041,6 +1054,22 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) wp->descr->d_base->name); return NULL; } + + // Pyston addition: + if (wp->descr->d_base->flags & PyWrapperFlag_1ARG) { + assert(PyTuple_GET_SIZE(args) == 0); + return (*(wrapperfunc_1arg)wrapper)(self, wp->descr->d_wrapped); + } + + if (wp->descr->d_base->flags & PyWrapperFlag_2ARG) { + if (PyTuple_GET_SIZE(args) != 1) { + PyErr_Format(PyExc_TypeError, "Expected 1 argument, got %ld", PyTuple_GET_SIZE(args)); + return NULL; + } + return (*(wrapperfunc_2arg)wrapper)(self, PyTuple_GET_ITEM(args, 0), wp->descr->d_wrapped); + } + assert(!wp->descr->d_base->flags); + return (*wrapper)(self, args, wp->descr->d_wrapped); } @@ -1053,8 +1082,8 @@ wrapper_traverse(PyObject *self, visitproc visit, void *arg) return 0; } -static PyTypeObject wrappertype = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) +/* static */ PyTypeObject wrappertype = { + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "method-wrapper", /* tp_name */ sizeof(wrapperobject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1114,6 +1143,8 @@ PyWrapper_New(PyObject *d, PyObject *self) } +// Pyston change: not using this for now +#if 0 /* A built-in 'property' type */ /* @@ -1396,7 +1427,7 @@ property_traverse(PyObject *self, visitproc visit, void *arg) } PyTypeObject PyProperty_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) + PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "property", /* tp_name */ sizeof(propertyobject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -1438,3 +1469,4 @@ PyTypeObject PyProperty_Type = { PyType_GenericNew, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; +#endif // end pyston change diff --git a/from_cpython/Objects/dictproxy.c b/from_cpython/Objects/dictproxy.c deleted file mode 100644 index 312413a36..000000000 --- a/from_cpython/Objects/dictproxy.c +++ /dev/null @@ -1,244 +0,0 @@ -// This file is originally from CPython 2.7, with modifications for Pyston -// The code is normally part of descrobject.c - -#include "Python.h" - -/* --- Readonly proxy for dictionaries (actually any mapping) --- */ - -/* This has no reason to be in this file except that adding new files is a - bit of a pain */ - -typedef struct { - PyObject_HEAD - PyObject *dict; -} proxyobject; - -static Py_ssize_t -proxy_len(proxyobject *pp) -{ - return PyObject_Size(pp->dict); -} - -static PyObject * -proxy_getitem(proxyobject *pp, PyObject *key) -{ - return PyObject_GetItem(pp->dict, key); -} - -static PyMappingMethods proxy_as_mapping = { - (lenfunc)proxy_len, /* mp_length */ - (binaryfunc)proxy_getitem, /* mp_subscript */ - 0, /* mp_ass_subscript */ -}; - -static int -proxy_contains(proxyobject *pp, PyObject *key) -{ - return PyDict_Contains(pp->dict, key); -} - -static PySequenceMethods proxy_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - (objobjproc)proxy_contains, /* sq_contains */ - 0, /* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - -static PyObject * -proxy_has_key(proxyobject *pp, PyObject *key) -{ - int res = PyDict_Contains(pp->dict, key); - if (res < 0) - return NULL; - return PyBool_FromLong(res); -} - -static PyObject * -proxy_get(proxyobject *pp, PyObject *args) -{ - PyObject *key, *def = Py_None; - - if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) - return NULL; - return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); -} - -static PyObject * -proxy_keys(proxyobject *pp) -{ - return PyMapping_Keys(pp->dict); -} - -static PyObject * -proxy_values(proxyobject *pp) -{ - return PyMapping_Values(pp->dict); -} - -static PyObject * -proxy_items(proxyobject *pp) -{ - return PyMapping_Items(pp->dict); -} - -static PyObject * -proxy_iterkeys(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "iterkeys", NULL); -} - -static PyObject * -proxy_itervalues(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "itervalues", NULL); -} - -static PyObject * -proxy_iteritems(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "iteritems", NULL); -} -static PyObject * -proxy_copy(proxyobject *pp) -{ - return PyObject_CallMethod(pp->dict, "copy", NULL); -} - -static PyMethodDef proxy_methods[] = { - {"has_key", (PyCFunction)proxy_has_key, METH_O, - PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")}, - {"get", (PyCFunction)proxy_get, METH_VARARGS, - PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d." - " d defaults to None.")}, - {"keys", (PyCFunction)proxy_keys, METH_NOARGS, - PyDoc_STR("D.keys() -> list of D's keys")}, - {"values", (PyCFunction)proxy_values, METH_NOARGS, - PyDoc_STR("D.values() -> list of D's values")}, - {"items", (PyCFunction)proxy_items, METH_NOARGS, - PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")}, - {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS, - PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")}, - {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS, - PyDoc_STR("D.itervalues() -> an iterator over the values of D")}, - {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS, - PyDoc_STR("D.iteritems() ->" - " an iterator over the (key, value) items of D")}, - {"copy", (PyCFunction)proxy_copy, METH_NOARGS, - PyDoc_STR("D.copy() -> a shallow copy of D")}, - {0} -}; - -static void -proxy_dealloc(proxyobject *pp) -{ - _PyObject_GC_UNTRACK(pp); - Py_DECREF(pp->dict); - PyObject_GC_Del(pp); -} - -static PyObject * -proxy_getiter(proxyobject *pp) -{ - return PyObject_GetIter(pp->dict); -} - -static PyObject * -proxy_str(proxyobject *pp) -{ - return PyObject_Str(pp->dict); -} - -static PyObject * -proxy_repr(proxyobject *pp) -{ - PyObject *dictrepr; - PyObject *result; - - dictrepr = PyObject_Repr(pp->dict); - if (dictrepr == NULL) - return NULL; - result = PyString_FromFormat("dict_proxy(%s)", PyString_AS_STRING(dictrepr)); - Py_DECREF(dictrepr); - return result; -} - -static int -proxy_traverse(PyObject *self, visitproc visit, void *arg) -{ - proxyobject *pp = (proxyobject *)self; - Py_VISIT(pp->dict); - return 0; -} - -static int -proxy_compare(proxyobject *v, PyObject *w) -{ - return PyObject_Compare(v->dict, w); -} - -static PyObject * -proxy_richcompare(proxyobject *v, PyObject *w, int op) -{ - return PyObject_RichCompare(v->dict, w, op); -} - -PyTypeObject PyDictProxy_Type = { - // Pyston change: - // PyVarObject_HEAD_INIT(&PyType_Type, 0) - PyVarObject_HEAD_INIT(NULL, 0) - "dictproxy", /* tp_name */ - sizeof(proxyobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)proxy_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - (cmpfunc)proxy_compare, /* tp_compare */ - (reprfunc)proxy_repr, /* tp_repr */ - 0, /* tp_as_number */ - &proxy_as_sequence, /* tp_as_sequence */ - &proxy_as_mapping, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)proxy_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - proxy_traverse, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)proxy_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)proxy_getiter, /* tp_iter */ - 0, /* tp_iternext */ - proxy_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ -}; - -PyObject * -PyDictProxy_New(PyObject *dict) -{ - proxyobject *pp; - - pp = PyObject_GC_New(proxyobject, &PyDictProxy_Type); - if (pp != NULL) { - Py_INCREF(dict); - pp->dict = dict; - _PyObject_GC_TRACK(pp); - } - return (PyObject *)pp; -} - diff --git a/from_cpython/Objects/structseq.c b/from_cpython/Objects/structseq.c index 149bad7dc..37cb5ae41 100644 --- a/from_cpython/Objects/structseq.c +++ b/from_cpython/Objects/structseq.c @@ -262,7 +262,7 @@ structseq_repr(PyStructSequence *obj) for (i=0; i < VISIBLE_SIZE(obj); i++) { PyObject *val, *repr; - char *cname, *crepr; + /* Pyston change: made const */ const char *cname, *crepr; cname = typ->tp_members[i].name; @@ -399,7 +399,7 @@ structseq_reduce(PyStructSequence* self) } for (; i < n_fields; i++) { - char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; + /* Pyston change: made const */ const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; PyDict_SetItemString(dict, n, self->ob_item[i]); } diff --git a/src/capi/typeobject.cpp b/src/capi/typeobject.cpp index 6d124c994..76ebf7484 100644 --- a/src/capi/typeobject.cpp +++ b/src/capi/typeobject.cpp @@ -142,6 +142,31 @@ static PyObject* wrap_descr_get(PyObject* self, PyObject* args, void* wrapped) n return (*func)(self, obj, type); } +static PyObject* wrap_descr_set(PyObject* self, PyObject* args, void* wrapped) { + descrsetfunc func = (descrsetfunc)wrapped; + PyObject* obj, *value; + int ret; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &obj, &value)) + return NULL; + ret = (*func)(self, obj, value); + if (ret < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* wrap_descr_delete(PyObject* self, PyObject* obj, void* wrapped) { + descrsetfunc func = (descrsetfunc)wrapped; + int ret; + + ret = (*func)(self, obj, NULL); + if (ret < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* wrap_coercefunc(PyObject* self, PyObject* other, void* wrapped) noexcept { STAT_TIMER(t0, "us_timer_wrap_coercefunc", WRAP_AVOIDABILITY(self)); coercion func = (coercion)wrapped; @@ -943,8 +968,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* assert(getattribute); if (getattribute == NULL - || (Py_TYPE(getattribute) == wrapperdescr_cls - && ((BoxedWrapperDescriptor*)getattribute)->wrapped == (void*)PyObject_GenericGetAttr)) { + || (Py_TYPE(getattribute) == &PyWrapperDescr_Type + && ((PyWrapperDescrObject*)getattribute)->d_wrapped == (void*)PyObject_GenericGetAttr)) { assert(PyString_CHECK_INTERNED(name)); if (rewrite_args) { @@ -1177,6 +1202,20 @@ static void slot_tp_del(PyObject* self) noexcept { #endif } +static int slot_tp_descr_set(PyObject* self, PyObject* target, PyObject* value) { + PyObject* res; + static PyObject* del_str, *set_str; + + if (value == NULL) + res = call_method(self, "__delete__", &del_str, "(O)", target); + else + res = call_method(self, "__set__", &set_str, "(OO)", target, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + /* Pyston change: static */ int slot_tp_init(PyObject* self, PyObject* args, PyObject* kwds) noexcept { STAT_TIMER(t0, "us_timer_slot_tpinit", SLOT_AVOIDABILITY(self)); @@ -1573,7 +1612,7 @@ SLOT1BIN(slot_nb_true_divide, nb_true_divide, "__truediv__", "__rtruediv__") SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject*, "O") SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject*, "O") -typedef wrapper_def slotdef; +typedef wrapperbase slotdef; static void** slotptr(BoxedClass* type, int offset) noexcept { // We use the index into PyHeapTypeObject as the canonical way to represent offsets, even though we are not @@ -1650,12 +1689,12 @@ static void** slotptr(BoxedClass* type, int offset) noexcept { ETSLOT_2ARG(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, "x." NAME "(y) <==> " DOC) static slotdef slotdefs[] = { - TPSLOT("__str__", tp_print, NULL, NULL, ""), - TPSLOT("__repr__", tp_print, NULL, NULL, ""), - TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), - TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""), - TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), - TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), + TPSLOT("__str__", tp_print, NULL, NULL, NULL), + TPSLOT("__repr__", tp_print, NULL, NULL, NULL), + TPSLOT("__getattribute__", tp_getattr, NULL, NULL, NULL), + TPSLOT("__getattr__", tp_getattr, NULL, NULL, NULL), + TPSLOT("__setattr__", tp_setattr, NULL, NULL, NULL), + TPSLOT("__delattr__", tp_setattr, NULL, NULL, NULL), TPSLOT_2ARG("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc, "x.__cmp__(y) <==> cmp(x,y)"), TPSLOT_1ARG("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, "x.__repr__() <==> repr(x)"), @@ -1666,7 +1705,7 @@ static slotdef slotdefs[] = { TPSLOT_2ARG("__getattribute__", tp_getattro, slot_tp_getattr_hook, wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"), - TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), + TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, NULL), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, "x.__setattr__('name', value) <==> x.name = value"), TPSLOT_2ARG("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, "x.__delattr__('name') <==> del x.name"), @@ -1681,16 +1720,18 @@ static slotdef slotdefs[] = { TPSLOT_1ARG("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, "x.__iter__() <==> iter(x)"), TPSLOT_1ARG("next", tp_iternext, slot_tp_iternext, wrap_next, "x.next() -> the next value, or raise StopIteration"), TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, "descr.__get__(obj[, type]) -> value"), + TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, "descr.__set__(obj, value)"), + TPSLOT_2ARG("__delete__", tp_descr_set, slot_tp_descr_set, wrap_descr_delete, "descr.__delete__(obj)"), FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, "x.__init__(...) initializes x; " "see help(type(x)) for signature", PyWrapperFlag_KEYWORDS), - TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), - TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""), - FLSLOT("__class__", has___class__, NULL, NULL, "", PyWrapperFlag_BOOL), - FLSLOT("__instancecheck__", has_instancecheck, NULL, NULL, "", PyWrapperFlag_BOOL), - FLSLOT("__subclasscheck__", has_subclasscheck, NULL, NULL, "", PyWrapperFlag_BOOL), - FLSLOT("__getattribute__", has_getattribute, NULL, NULL, "", PyWrapperFlag_BOOL), + TPSLOT("__new__", tp_new, slot_tp_new, NULL, NULL), + TPSLOT("__del__", tp_del, slot_tp_del, NULL, NULL), + FLSLOT("__class__", has___class__, NULL, NULL, NULL, PyWrapperFlag_BOOL), + FLSLOT("__instancecheck__", has_instancecheck, NULL, NULL, NULL, PyWrapperFlag_BOOL), + FLSLOT("__subclasscheck__", has_subclasscheck, NULL, NULL, NULL, PyWrapperFlag_BOOL), + FLSLOT("__getattribute__", has_getattribute, NULL, NULL, NULL, PyWrapperFlag_BOOL), TPPSLOT_1ARG("__hasnext__", tpp_hasnext, slotTppHasnext, wrapInquirypred, "hasnext"), BINSLOT("__add__", nb_add, slot_nb_add, "+"), // [force clang-format to line break] @@ -1778,7 +1819,7 @@ static slotdef slotdefs[] = { SQSLOT_2ARG("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, "x.__contains__(y) <==> y in x"), SQSLOT_2ARG("__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"), - { "", 0, NULL, NULL, "", 0, NULL } + { NULL, 0, NULL, NULL, NULL, 0, NULL } }; static void init_slotdefs() noexcept { @@ -1787,24 +1828,23 @@ static void init_slotdefs() noexcept { return; for (int i = 0; i < sizeof(slotdefs) / sizeof(slotdefs[0]); i++) { - slotdefs[i].name_strobj = getStaticString(slotdefs[i].name.data()); + if (!slotdefs[i].name) + break; + slotdefs[i].name_strobj = getStaticString(slotdefs[i].name); if (i > 0) { - if (!slotdefs[i].name.size()) - continue; - #ifndef NDEBUG if (slotdefs[i - 1].offset > slotdefs[i].offset) { - printf("slotdef for %s in the wrong place\n", slotdefs[i - 1].name.data()); + printf("slotdef for %s in the wrong place\n", slotdefs[i - 1].name); for (int j = i; j < sizeof(slotdefs) / sizeof(slotdefs[0]); j++) { if (slotdefs[i - 1].offset <= slotdefs[j].offset) { - printf("Should go before %s\n", slotdefs[j].name.data()); + printf("Should go before %s\n", slotdefs[j].name); break; } } } #endif - ASSERT(slotdefs[i].offset >= slotdefs[i - 1].offset, "%d %s", i, slotdefs[i - 1].name.data()); + ASSERT(slotdefs[i].offset >= slotdefs[i - 1].offset, "%d %s", i, slotdefs[i - 1].name); } } @@ -1819,11 +1859,11 @@ static void init_slotdefs() noexcept { /* Return a slot pointer for a given name, but ONLY if the attribute has exactly one slot function. The name must be an interned string. */ -static void** resolve_slotdups(PyTypeObject* type, const std::string& name) noexcept { +static void** resolve_slotdups(PyTypeObject* type, PyObject* name) noexcept { /* XXX Maybe this could be optimized more -- but is it worth it? */ /* pname and ptrs act as a little cache */ - static std::string pname; + static PyObject* pname; static slotdef* ptrs[MAX_EQUIV]; slotdef* p, **pp; void** res, **ptr; @@ -1832,15 +1872,15 @@ static void** resolve_slotdups(PyTypeObject* type, const std::string& name) noex /* Collect all slotdefs that match name into ptrs. */ pname = name; pp = ptrs; - for (p = slotdefs; p->name.size() != 0; p++) { - if (p->name == name) + for (p = slotdefs; p->name_strobj; p++) { + if (p->name_strobj == name) *pp++ = p; } *pp = NULL; } /* Look in all matching slots of the type; if exactly one of these has - a filled-in slot, return its value. Otherwise return NULL. */ + * a filled-in slot, return its value. Otherwise return NULL. */ res = NULL; for (pp = ptrs; *pp; pp++) { ptr = slotptr(type, (*pp)->offset); @@ -1854,10 +1894,10 @@ static void** resolve_slotdups(PyTypeObject* type, const std::string& name) noex } static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexcept { - assert(p->name.size() != 0); + assert(p->name); PyObject* descr; - BoxedWrapperDescriptor* d; + PyWrapperDescrObject* d; void* generic = NULL, * specific = NULL; int use_generic = 0; int offset = p->offset; @@ -1871,7 +1911,8 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce } do { - descr = typeLookup(type, p->name_strobj); + assert(p->name_strobj->cls == str_cls); + descr = typeLookup(type, static_cast(p->name_strobj)); if (p->flags & PyWrapperFlag_BOOL) { // We are supposed to iterate over each slotdef; for now just assert that @@ -1886,8 +1927,8 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce static BoxedString* getattribute_str = getStaticString("__getattribute__"); if (p->name_strobj == getattribute_str) { - if (descr && descr->cls == wrapperdescr_cls - && ((BoxedWrapperDescriptor*)descr)->wrapped == PyObject_GenericGetAttr) + if (descr && descr->cls == &PyWrapperDescr_Type + && ((PyWrapperDescrObject*)descr)->d_wrapped == PyObject_GenericGetAttr) descr = NULL; } @@ -1901,16 +1942,15 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce } continue; } - if (Py_TYPE(descr) == wrapperdescr_cls - && ((BoxedWrapperDescriptor*)descr)->wrapper->name == std::string(p->name)) { - void** tptr = resolve_slotdups(type, p->name); + if (Py_TYPE(descr) == &PyWrapperDescr_Type + && ((PyWrapperDescrObject*)descr)->d_base->name_strobj == p->name_strobj) { + void** tptr = resolve_slotdups(type, p->name_strobj); if (tptr == NULL || tptr == ptr) generic = p->function; - d = (BoxedWrapperDescriptor*)descr; - if (d->wrapper->wrapper == p->wrapper && PyType_IsSubtype(type, d->type) - && ((d->wrapper->flags & PyWrapperFlag_PYSTON) == (p->flags & PyWrapperFlag_PYSTON))) { - if (specific == NULL || specific == d->wrapped) - specific = d->wrapped; + d = (PyWrapperDescrObject*)descr; + if (d->d_base->wrapper == p->wrapper && PyType_IsSubtype(type, d->d_type)) { + if (specific == NULL || specific == d->d_wrapped) + specific = d->d_wrapped; else use_generic = 1; } @@ -1987,7 +2027,7 @@ bool update_slot(BoxedClass* type, llvm::StringRef attr) noexcept { init_slotdefs(); pp = ptrs; - for (p = slotdefs; p->name.size() != 0; p++) { + for (p = slotdefs; p->name; p++) { /* XXX assume name is interned! */ if (p->name == attr) *pp++ = p; @@ -2014,7 +2054,7 @@ void fixup_slot_dispatchers(BoxedClass* self) noexcept { init_slotdefs(); const slotdef* p = slotdefs; - while (p->name.size() != 0) + while (p->name) p = update_one_slot(self, p); } @@ -2022,7 +2062,7 @@ void fixup_pyston_slot_dispatchers(BoxedClass* self) noexcept { init_slotdefs(); const slotdef* p = slotdefs; - while (p->name.size() != 0) { + while (p->name) { // Skip slotdefs that are either in the CPython slots (things before tp_version_tag), or // things that are pointers into the tp_as_foo structs (which are represented as offsets // past the end of BoxedClass, ie into BoxedHeapClass) @@ -2129,7 +2169,7 @@ static void add_tp_new_wrapper(BoxedClass* type) noexcept { void add_operators(BoxedClass* cls) noexcept { init_slotdefs(); - for (const slotdef& p : slotdefs) { + for (slotdef& p : slotdefs) { if (!p.wrapper) continue; @@ -2137,14 +2177,16 @@ void add_operators(BoxedClass* cls) noexcept { if (!ptr || !*ptr) continue; - if (cls->getattr(p.name_strobj)) + assert(p.name_strobj->cls == str_cls); + if (cls->getattr(static_cast(p.name_strobj))) continue; if (*ptr == PyObject_HashNotImplemented) { - cls->setattr(p.name_strobj, None, NULL); + cls->setattr(static_cast(p.name_strobj), None, NULL); } else { - auto descr = new BoxedWrapperDescriptor(&p, cls, *ptr); - cls->setattr(p.name_strobj, descr, NULL); + auto descr = PyDescr_NewWrapper(cls, &p, *ptr); + assert(descr); + cls->setattr(static_cast(p.name_strobj), descr, NULL); Py_DECREF(descr); } } @@ -3118,7 +3160,7 @@ static void update_all_slots(PyTypeObject* type) noexcept { slotdef* p; init_slotdefs(); - for (p = slotdefs; p->name.size() > 0; p++) { + for (p = slotdefs; p->name; p++) { /* update_slot returns int but can't actually fail */ update_slot(type, p->name); } @@ -3447,6 +3489,11 @@ static Box* tppProxyToTpCall(Box* self, CallRewriteArgs* rewrite_args, ArgPassSp }); } +Box* proxyToTppCall(Box* self, Box* args, Box* kw) noexcept { + assert(self->cls->tpp_call.get() != NULL && self->cls->tpp_call.get() != tppProxyToTpCall); + return self->cls->tpp_call.call(self, NULL, ArgPassSpec(0, 0, true, true), args, kw, NULL, NULL, NULL); +} + extern "C" void PyType_RequestHcAttrs(PyTypeObject* cls, int offset) noexcept { assert(cls->attrs_offset == 0); assert(cls->tp_dictoffset == 0); @@ -3526,7 +3573,7 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { assert(cls->tp_name); - if (cls->tp_call) { + if (cls->tp_call && cls->tp_call != proxyToTppCall) { cls->tpp_call.capi_val = tppProxyToTpCall; cls->tpp_call.cxx_val = tppProxyToTpCall; } diff --git a/src/capi/typeobject.h b/src/capi/typeobject.h index c34c24049..1a75f26ab 100644 --- a/src/capi/typeobject.h +++ b/src/capi/typeobject.h @@ -59,6 +59,9 @@ class GetattrRewriteArgs; template Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool for_call, BORROWED(Box**) bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI); + +// Set a class's tp_call to this to have calls to tp_call (and __call__) proxy to tpp_call +Box* proxyToTppCall(Box* self, Box* args, Box* kw) noexcept; } #endif diff --git a/src/capi/types.h b/src/capi/types.h index fcf948de8..8596422a3 100644 --- a/src/capi/types.h +++ b/src/capi/types.h @@ -54,7 +54,7 @@ class BoxedCApiFunction : public Box { static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, const std::vector* keyword_names) noexcept(S == CAPI); - static Box* getname(Box* b, void*) { + static Box* getname(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == capifunc_cls, ""); const char* s = static_cast(b)->method_def->ml_name; if (s) @@ -62,7 +62,7 @@ class BoxedCApiFunction : public Box { return incref(None); } - static Box* doc(Box* b, void*) { + static Box* doc(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == capifunc_cls, ""); const char* s = static_cast(b)->method_def->ml_doc; if (s) diff --git a/src/codegen/irgen/hooks.cpp b/src/codegen/irgen/hooks.cpp index e91425495..740d4f18a 100644 --- a/src/codegen/irgen/hooks.cpp +++ b/src/codegen/irgen/hooks.cpp @@ -112,7 +112,7 @@ BORROWED(BoxedString*) SourceInfo::getFn() { return fn; } -BORROWED(BoxedString*) SourceInfo::getName() { +BORROWED(BoxedString*) SourceInfo::getName() noexcept { assert(ast); static BoxedString* lambda_name = getStaticString(""); diff --git a/src/core/types.h b/src/core/types.h index e4897bfc5..e6d613c05 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -416,7 +416,8 @@ class SourceInfo { // body and we have to create one. Ideally, we'd be able to avoid the space duplication for non-lambdas. const std::vector body; - BORROWED(BoxedString*) getName(); + // does not throw CXX or CAPI exceptions: + BORROWED(BoxedString*) getName() noexcept; BORROWED(BoxedString*) getFn(); InternedString mangleName(InternedString id); @@ -867,8 +868,8 @@ class Box { void clearAttrsForDealloc(); - void giveAttrDescriptor(const char* attr, Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*)); - void giveCapiAttrDescriptor(const char* attr, Box* (*get)(Box*, void*), int (*set)(Box*, Box*, void*)); + void giveAttrDescriptor(const char* attr, Box* (*get)(Box*, void*), int (*set)(Box*, Box*, void*)); + void giveAttrMember(const char* attr, int type, ssize_t offset, bool readonly = true); // getattr() does the equivalent of PyDict_GetItem(obj->dict, attr): it looks up the attribute's value on the // object's attribute storage. it doesn't look at other objects or do any descriptor logic. diff --git a/src/runtime/builtin_modules/sys.cpp b/src/runtime/builtin_modules/sys.cpp index 3982d1e34..a09b5c1ae 100644 --- a/src/runtime/builtin_modules/sys.cpp +++ b/src/runtime/builtin_modules/sys.cpp @@ -816,9 +816,7 @@ void setupSys() { sys_flags_cls->giveAttr( "__new__", new BoxedFunction(FunctionMetadata::create((void*)BoxedSysFlags::__new__, UNKNOWN, 1, true, true))); sys_flags_cls->tp_dealloc = (destructor)BoxedSysFlags::dealloc; -#define ADD(name) \ - sys_flags_cls->giveAttr(STRINGIFY(name), \ - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSysFlags, name))) +#define ADD(name) sys_flags_cls->giveAttrMember(STRINGIFY(name), T_OBJECT, offsetof(BoxedSysFlags, name)); ADD(division_warning); ADD(bytes_warning); ADD(no_user_site); diff --git a/src/runtime/capi.cpp b/src/runtime/capi.cpp index 4b20f36bf..40dedf7f0 100644 --- a/src/runtime/capi.cpp +++ b/src/runtime/capi.cpp @@ -1915,8 +1915,7 @@ void setupCAPI() { capifunc_cls->tpp_call.cxx_val = BoxedCApiFunction::tppCall; capifunc_cls->giveAttrDescriptor("__name__", BoxedCApiFunction::getname, NULL); capifunc_cls->giveAttrDescriptor("__doc__", BoxedCApiFunction::doc, NULL); - capifunc_cls->giveAttr( - "__module__", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedCApiFunction, module))); + capifunc_cls->giveAttrMember("__module__", T_OBJECT, offsetof(BoxedCApiFunction, module)); capifunc_cls->freeze(); } diff --git a/src/runtime/code.cpp b/src/runtime/code.cpp index 7608a6b74..2d30e97c5 100644 --- a/src/runtime/code.cpp +++ b/src/runtime/code.cpp @@ -26,7 +26,7 @@ extern "C" { BoxedClass* code_cls; } -BORROWED(Box*) BoxedCode::name(Box* b, void*) { +BORROWED(Box*) BoxedCode::name(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast(b); if (code->_name) @@ -34,11 +34,11 @@ BORROWED(Box*) BoxedCode::name(Box* b, void*) { return code->f->source->getName(); } -Box* BoxedCode::co_name(Box* b, void* arg) { +Box* BoxedCode::co_name(Box* b, void* arg) noexcept { return incref(name(b, arg)); } -BORROWED(Box*) BoxedCode::filename(Box* b, void*) { +BORROWED(Box*) BoxedCode::filename(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast(b); if (code->_filename) @@ -46,11 +46,11 @@ BORROWED(Box*) BoxedCode::filename(Box* b, void*) { return code->f->source->getFn(); } -Box* BoxedCode::co_filename(Box* b, void* arg) { +Box* BoxedCode::co_filename(Box* b, void* arg) noexcept { return incref(filename(b, arg)); } -Box* BoxedCode::firstlineno(Box* b, void*) { +Box* BoxedCode::firstlineno(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast(b); FunctionMetadata* md = code->f; @@ -64,12 +64,12 @@ Box* BoxedCode::firstlineno(Box* b, void*) { return boxInt(md->source->ast->lineno); } -Box* BoxedCode::argcount(Box* b, void*) { +Box* BoxedCode::argcount(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); return boxInt(static_cast(b)->f->num_args); } -Box* BoxedCode::varnames(Box* b, void*) { +Box* BoxedCode::varnames(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast(b); @@ -90,7 +90,7 @@ Box* BoxedCode::varnames(Box* b, void*) { return rtn; } -Box* BoxedCode::flags(Box* b, void*) { +Box* BoxedCode::flags(Box* b, void*) noexcept { RELEASE_ASSERT(b->cls == code_cls, ""); BoxedCode* code = static_cast(b); diff --git a/src/runtime/code.h b/src/runtime/code.h index 3a58fb458..d9584f6ba 100644 --- a/src/runtime/code.h +++ b/src/runtime/code.h @@ -39,14 +39,14 @@ class BoxedCode : public Box { // These need to be static functions rather than methods because function // pointers could point to them. - static BORROWED(Box*) name(Box* b, void*); - static BORROWED(Box*) filename(Box* b, void*); - static Box* co_name(Box* b, void*); - static Box* co_filename(Box* b, void*); - static Box* firstlineno(Box* b, void*); - static Box* argcount(Box* b, void*); - static Box* varnames(Box* b, void*); - static Box* flags(Box* b, void*); + static BORROWED(Box*) name(Box* b, void*) noexcept; + static BORROWED(Box*) filename(Box* b, void*) noexcept; + static Box* co_name(Box* b, void*) noexcept; + static Box* co_filename(Box* b, void*) noexcept; + static Box* firstlineno(Box* b, void*) noexcept; + static Box* argcount(Box* b, void*) noexcept; + static Box* varnames(Box* b, void*) noexcept; + static Box* flags(Box* b, void*) noexcept; static int traverse(Box* self, visitproc visit, void* arg) noexcept; static void dealloc(Box* b) noexcept; diff --git a/src/runtime/complex.cpp b/src/runtime/complex.cpp index babca277c..7aa973001 100644 --- a/src/runtime/complex.cpp +++ b/src/runtime/complex.cpp @@ -741,7 +741,8 @@ PyObject* complex_neg(PyComplexObject* v) { } static PyMethodDef complex_methods[] = { - { "__format__", (PyCFunction)complex__format__, METH_VARARGS, NULL }, + { "__format__", (PyCFunction)complex__format__, METH_VARARGS, NULL }, // + { NULL, NULL, 0, NULL }, }; void setupComplex() { @@ -810,19 +811,15 @@ void setupComplex() { complex_cls->giveAttr("__float__", new BoxedFunction(FunctionMetadata::create((void*)complexFloat, UNKNOWN, 1))); complex_cls->giveAttr("__long__", new BoxedFunction(FunctionMetadata::create((void*)complexLong, UNKNOWN, 1))); complex_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)complexRepr, STR, 1))); - complex_cls->giveAttr("real", - new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, real))); - complex_cls->giveAttr("imag", - new BoxedMemberDescriptor(BoxedMemberDescriptor::DOUBLE, offsetof(BoxedComplex, imag))); + complex_cls->giveAttrMember("real", T_DOUBLE, offsetof(BoxedComplex, real), true); + complex_cls->giveAttrMember("imag", T_DOUBLE, offsetof(BoxedComplex, imag), true); complex_cls->giveAttr("__doc__", boxString("complex(real[, imag]) -> complex number\n" "\n" "Create a complex number from a real part and an optional imaginary part.\n" "This is equivalent to (real + imag*1j) where imag defaults to 0.")); - for (auto& md : complex_methods) { - complex_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, complex_cls)); - } + add_methods(complex_cls, complex_methods); add_operators(complex_cls); diff --git a/src/runtime/descr.cpp b/src/runtime/descr.cpp index bb6208f8a..a325dce08 100644 --- a/src/runtime/descr.cpp +++ b/src/runtime/descr.cpp @@ -20,26 +20,6 @@ namespace pyston { -extern "C" { -BoxedClass* wrapperdescr_cls, *wrapperobject_cls; -} - -static Box* memberGet(BoxedMemberDescriptor* self, Box* inst, Box* owner) { - RELEASE_ASSERT(self->cls == member_descriptor_cls, ""); - - if (inst == None) - return incref(self); - - if (self->type == BoxedMemberDescriptor::OBJECT) { - Box* rtn = *(Box**)(((char*)inst) + self->offset); - if (!rtn) - rtn = None; - return incref(rtn); - } - - Py_FatalError("unimplemented"); -} - static void propertyDocCopy(BoxedProperty* prop, Box* fget) { assert(prop); assert(fget); @@ -470,38 +450,6 @@ int BoxedMethodDescriptor::traverse(Box* _self, visitproc visit, void* arg) noex return 0; } -void BoxedWrapperDescriptor::dealloc(Box* _self) noexcept { - BoxedWrapperDescriptor* self = static_cast(_self); - - PyObject_GC_UnTrack(self); - Py_XDECREF(self->type); - self->cls->tp_free(self); -} - -int BoxedWrapperDescriptor::traverse(Box* _self, visitproc visit, void* arg) noexcept { - BoxedWrapperDescriptor* self = static_cast(_self); - - Py_VISIT(self->type); - return 0; -} - -void BoxedWrapperObject::dealloc(Box* _self) noexcept { - BoxedWrapperObject* self = static_cast(_self); - - PyObject_GC_UnTrack(self); - Py_XDECREF(self->obj); - Py_XDECREF(self->descr); - self->cls->tp_free(self); -} - -int BoxedWrapperObject::traverse(Box* _self, visitproc visit, void* arg) noexcept { - BoxedWrapperObject* self = static_cast(_self); - - Py_VISIT(self->obj); - Py_VISIT(self->descr); - return 0; -} - void BoxedProperty::dealloc(Box* _self) noexcept { BoxedProperty* self = static_cast(_self); @@ -567,45 +515,12 @@ int BoxedClassmethod::clear(Box* _self) noexcept { return 0; } -Box* BoxedWrapperDescriptor::descr_get(Box* _self, Box* inst, Box* owner) noexcept { - STAT_TIMER(t0, "us_timer_boxedwrapperdescriptor_descr_get", 20); - - RELEASE_ASSERT(_self->cls == wrapperdescr_cls, ""); - BoxedWrapperDescriptor* self = static_cast(_self); - - if (inst == NULL) - return incref(self); - - if (!isSubclass(inst->cls, self->type)) { - PyErr_Format(TypeError, "Descriptor '' for '%s' objects doesn't apply to '%s' object", - getFullNameOfClass(self->type).c_str(), getFullTypeName(inst).c_str()); - return NULL; - } - - return new BoxedWrapperObject(self, inst); -} - -Box* BoxedWrapperDescriptor::__call__(BoxedWrapperDescriptor* descr, PyObject* self, BoxedTuple* args, Box** _args) { - RELEASE_ASSERT(descr->cls == wrapperdescr_cls, ""); - - BoxedDict* kw = static_cast(_args[0]); - - if (!isSubclass(self->cls, descr->type)) - raiseExcHelper(TypeError, "descriptor '' requires a '%s' object but received a '%s'", - getFullNameOfClass(descr->type).c_str(), getFullTypeName(self).c_str()); - - auto wrapper = new BoxedWrapperObject(descr, self); - AUTO_DECREF(wrapper); - return BoxedWrapperObject::__call__(wrapper, args, kw); -} - template -Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, - Box* arg2, Box* arg3, Box** args, - const std::vector* keyword_names) noexcept(S == CAPI) { +Box* wrapperDescrTppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, + Box* arg3, Box** args, const std::vector* keyword_names) noexcept(S == CAPI) { if (S == CAPI) { try { - return tppCall(_self, NULL, argspec, arg1, arg2, arg3, args, keyword_names); + return wrapperDescrTppCall(_self, NULL, argspec, arg1, arg2, arg3, args, keyword_names); } catch (ExcInfo e) { setCAPIException(e); return NULL; @@ -614,12 +529,11 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, STAT_TIMER(t0, "us_timer_boxedwrapperdecsriptor_call", (_self->cls->is_user_defined ? 10 : 20)); - assert(_self->cls == wrapperdescr_cls); - BoxedWrapperDescriptor* self = static_cast(_self); + assert(_self->cls == &PyWrapperDescr_Type); + PyWrapperDescrObject* self = reinterpret_cast(_self); - int flags = self->wrapper->flags; - wrapperfunc wrapper = self->wrapper->wrapper; - assert(self->wrapper->offset > 0); + int flags = self->d_base->flags; + wrapperfunc wrapper = self->d_base->wrapper; ParamReceiveSpec paramspec(1, 0, true, false); if (flags == PyWrapperFlag_KEYWORDS) { @@ -643,50 +557,50 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, Box* rtn; if (flags == PyWrapperFlag_KEYWORDS) { wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; - rtn = (*wk)(arg1, arg2, self->wrapped, arg3); + rtn = (*wk)(arg1, arg2, self->d_wrapped, arg3); if (rewrite_args) { auto rewriter = rewrite_args->rewriter; rewrite_args->out_rtn = rewriter->call(true, (void*)wk, rewrite_args->arg1, rewrite_args->arg2, - rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2)), + rewriter->loadConst((intptr_t)self->d_wrapped, Location::forArg(2)), rewrite_args->arg3)->setType(RefType::OWNED); rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); rewrite_args->out_success = true; } } else if (flags == PyWrapperFlag_PYSTON || flags == 0) { - rtn = (*wrapper)(arg1, arg2, self->wrapped); + rtn = (*wrapper)(arg1, arg2, self->d_wrapped); if (rewrite_args) { auto rewriter = rewrite_args->rewriter; rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2, - rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2))) + rewriter->loadConst((intptr_t)self->d_wrapped, Location::forArg(2))) ->setType(RefType::OWNED); rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); rewrite_args->out_success = true; } } else if (flags == PyWrapperFlag_1ARG) { wrapperfunc_1arg wrapper_1arg = (wrapperfunc_1arg)wrapper; - rtn = (*wrapper_1arg)(arg1, self->wrapped); + rtn = (*wrapper_1arg)(arg1, self->d_wrapped); if (rewrite_args) { auto rewriter = rewrite_args->rewriter; rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, - rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(1))) + rewriter->loadConst((intptr_t)self->d_wrapped, Location::forArg(1))) ->setType(RefType::OWNED); rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); rewrite_args->out_success = true; } } else if (flags == PyWrapperFlag_2ARG) { - rtn = (*wrapper)(arg1, arg2, self->wrapped); + rtn = (*wrapper)(arg1, arg2, self->d_wrapped); if (rewrite_args) { auto rewriter = rewrite_args->rewriter; rewrite_args->out_rtn = rewriter->call(true, (void*)wrapper, rewrite_args->arg1, rewrite_args->arg2, - rewriter->loadConst((intptr_t)self->wrapped, Location::forArg(2))) + rewriter->loadConst((intptr_t)self->d_wrapped, Location::forArg(2))) ->setType(RefType::OWNED); rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); rewrite_args->out_success = true; @@ -701,93 +615,37 @@ Box* BoxedWrapperDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, }; return callCXXFromStyle([&]() { - return rearrangeArgumentsAndCall(paramspec, NULL, self->wrapper->name.data(), NULL, rewrite_args, argspec, arg1, - arg2, arg3, args, keyword_names, continuation); + return rearrangeArgumentsAndCall(paramspec, NULL, self->d_base->name, NULL, rewrite_args, argspec, arg1, arg2, + arg3, args, keyword_names, continuation); }); } -static Box* wrapperdescrGetDoc(Box* b, void*) { - assert(b->cls == wrapperdescr_cls); - StringRef s = static_cast(b)->wrapper->doc; - assert(s.size()); - return boxString(s); -} - -static Box* wrapperdescrGetName(Box* b, void*) { - assert(b->cls == wrapperdescr_cls); - StringRef s = static_cast(b)->wrapper->name; - assert(s.size()); - return boxString(s); -} - -static Box* wrapperDescrRepr(Box* _o) { - assert(_o->cls == wrapperdescr_cls); - BoxedWrapperDescriptor* wd = static_cast(_o); - const char* name = "?"; - if (wd->wrapper != NULL) - name = wd->wrapper->name.data(); - return PyString_FromFormat("", name, getNameOfClass(wd->type)); -} - -static Box* wrapperobjectGetDoc(Box* b, void*) { - assert(b->cls == wrapperobject_cls); - auto s = static_cast(b)->descr->wrapper->doc; - assert(s.size()); - return boxString(s); -} - -static Box* wrapperObjectRepr(Box* _o) { - assert(_o->cls == wrapperobject_cls); - BoxedWrapperObject* wp = static_cast(_o); - return PyString_FromFormat("", wp->descr->wrapper->name.str().c_str(), - getTypeName(wp->obj), wp->obj); -} - -// TODO this should be auto-generated as a slot wrapper: -Box* BoxedWrapperObject::__call__(BoxedWrapperObject* self, Box* args, Box* kwargs) { - return BoxedWrapperObject::tppCall(self, NULL, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL, NULL); -} - template -Box* BoxedWrapperObject::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, - Box* arg3, Box** args, - const std::vector* keyword_names) noexcept(S == CAPI) { +Box* wrapperObjectTppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, + Box* arg3, Box** args, const std::vector* keyword_names) noexcept(S == CAPI) { STAT_TIMER(t0, "us_timer_boxedwrapperobject_call", (_self->cls->is_user_defined ? 10 : 20)); - assert(_self->cls == wrapperobject_cls); - BoxedWrapperObject* self = static_cast(_self); + assert(_self->cls == &wrappertype); + wrapperobject* self = reinterpret_cast(_self); - assert(self->descr->wrapper->offset > 0); RewriterVar* r_obj = NULL; Box** new_args = NULL; if (argspec.totalPassed() >= 3) new_args = (Box**)alloca(sizeof(Box*) * (argspec.totalPassed() + 1 - 3)); if (rewrite_args) { - if (!rewrite_args->func_guarded) - rewrite_args->obj->addAttrGuard(offsetof(BoxedWrapperObject, descr), (intptr_t)self->descr); - r_obj = rewrite_args->obj->getAttr(offsetof(BoxedWrapperObject, obj), Location::forArg(0)); + r_obj = rewrite_args->obj->getAttr(offsetof(wrapperobject, self), Location::forArg(0)); } ArgPassSpec new_argspec - = bindObjIntoArgs(self->obj, r_obj, rewrite_args, argspec, arg1, arg2, arg3, args, new_args); - return BoxedWrapperDescriptor::tppCall(self->descr, rewrite_args, new_argspec, arg1, arg2, arg3, new_args, - keyword_names); + = bindObjIntoArgs(self->self, r_obj, rewrite_args, argspec, arg1, arg2, arg3, args, new_args); + return wrapperDescrTppCall((Box*)self->descr, rewrite_args, new_argspec, arg1, arg2, arg3, new_args, + keyword_names); } extern "C" PyObject* PyStaticMethod_New(PyObject* callable) noexcept { return new BoxedStaticmethod(callable); } -extern "C" PyObject* PyDescr_NewMember(PyTypeObject* x, struct PyMemberDef* y) noexcept { - return new BoxedMemberDescriptor(y); -} - -extern "C" PyObject* PyDescr_NewGetSet(PyTypeObject* x, struct PyGetSetDef* y) noexcept { - // TODO do something with __doc__ - return new (capi_getset_cls) - BoxedGetsetDescriptor(autoDecref(internStringMortal(y->name)), y->get, y->set, y->closure); -} - extern "C" PyObject* PyDescr_NewClassMethod(PyTypeObject* type, PyMethodDef* method) noexcept { // Pyston change: we don't have a separate capi classmethod descriptor type, we just use the normal // one but with the METH_CLASS flag set. @@ -803,10 +661,6 @@ extern "C" PyObject* PyDescr_NewMethod(PyTypeObject* type, PyMethodDef* method) } void setupDescr() { - member_descriptor_cls->giveAttr("__get__", - new BoxedFunction(FunctionMetadata::create((void*)memberGet, UNKNOWN, 3))); - member_descriptor_cls->freeze(); - property_cls->instances_are_nonzero = true; property_cls->giveAttr("__init__", new BoxedFunction(FunctionMetadata::create( @@ -819,14 +673,10 @@ void setupDescr() { property_cls->giveAttr("getter", new BoxedFunction(FunctionMetadata::create((void*)propertyGetter, UNKNOWN, 2))); property_cls->giveAttr("setter", new BoxedFunction(FunctionMetadata::create((void*)propertySetter, UNKNOWN, 2))); property_cls->giveAttr("deleter", new BoxedFunction(FunctionMetadata::create((void*)propertyDeleter, UNKNOWN, 2))); - property_cls->giveAttr("fget", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_get))); - property_cls->giveAttr("fset", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_set))); - property_cls->giveAttr("fdel", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_del))); - property_cls->giveAttr("__doc__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedProperty, prop_doc))); + property_cls->giveAttrMember("fget", T_OBJECT, offsetof(BoxedProperty, prop_get)); + property_cls->giveAttrMember("fset", T_OBJECT, offsetof(BoxedProperty, prop_set)); + property_cls->giveAttrMember("fdel", T_OBJECT, offsetof(BoxedProperty, prop_del)); + property_cls->giveAttrMember("__doc__", T_OBJECT, offsetof(BoxedProperty, prop_doc)); property_cls->freeze(); staticmethod_cls->giveAttr( @@ -858,26 +708,22 @@ void setupDescr() { method_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)methodRepr, UNKNOWN, 1))); method_cls->freeze(); - wrapperdescr_cls->giveAttr("__call__", new BoxedFunction(FunctionMetadata::create( - (void*)BoxedWrapperDescriptor::__call__, UNKNOWN, 2, true, true))); - wrapperdescr_cls->giveAttrDescriptor("__doc__", wrapperdescrGetDoc, NULL); - wrapperdescr_cls->giveAttrDescriptor("__name__", wrapperdescrGetName, NULL); - wrapperdescr_cls->tp_descr_get = BoxedWrapperDescriptor::descr_get; - wrapperdescr_cls->tpp_call.capi_val = BoxedWrapperDescriptor::tppCall; - wrapperdescr_cls->tpp_call.cxx_val = BoxedWrapperDescriptor::tppCall; - add_operators(wrapperdescr_cls); - wrapperdescr_cls->giveAttr("__repr__", - new BoxedFunction(FunctionMetadata::create((void*)wrapperDescrRepr, UNKNOWN, 1))); - wrapperdescr_cls->freeze(); - assert(wrapperdescr_cls->tp_descr_get == BoxedWrapperDescriptor::descr_get); - - wrapperobject_cls->giveAttr("__call__", new BoxedFunction(FunctionMetadata::create( - (void*)BoxedWrapperObject::__call__, UNKNOWN, 1, true, true))); - wrapperobject_cls->tpp_call.capi_val = BoxedWrapperObject::tppCall; - wrapperobject_cls->tpp_call.cxx_val = BoxedWrapperObject::tppCall; - wrapperobject_cls->giveAttrDescriptor("__doc__", wrapperobjectGetDoc, NULL); - wrapperobject_cls->giveAttr("__repr__", - new BoxedFunction(FunctionMetadata::create((void*)wrapperObjectRepr, UNKNOWN, 1))); - wrapperobject_cls->freeze(); + PyType_Ready(&PyGetSetDescr_Type); + PyType_Ready(&PyMemberDescr_Type); + + PyType_Ready(&wrappertype); + PyType_Ready(&PyWrapperDescr_Type); + +#if 0 + wrappertype.tpp_call.capi_val = wrapperObjectTppCall; + wrappertype.tpp_call.cxx_val = wrapperObjectTppCall; + wrappertype.tp_call = proxyToTppCall; + PyType_Ready(&wrappertype); + + PyWrapperDescr_Type.tpp_call.capi_val = wrapperDescrTppCall; + PyWrapperDescr_Type.tpp_call.cxx_val = wrapperDescrTppCall; + PyWrapperDescr_Type.tp_call = proxyToTppCall; + PyType_Ready(&PyWrapperDescr_Type); +#endif } } diff --git a/src/runtime/float.cpp b/src/runtime/float.cpp index 5d0c6c33d..0e18b0936 100644 --- a/src/runtime/float.cpp +++ b/src/runtime/float.cpp @@ -1117,10 +1117,11 @@ static void _addFuncPow(const char* name, ConcreteCompilerType* rtn_type, void* float_cls->giveAttr(name, new BoxedFunction(md, { None })); } -static Box* floatConjugate(Box* b, void*) { - if (!PyFloat_Check(b)) - raiseExcHelper(TypeError, "descriptor 'conjugate' requires a 'float' object but received a '%s'", - getTypeName(b)); +static Box* float_conjugate(Box* b, void*) noexcept { + if (!PyFloat_Check(b)) { + PyErr_Format(TypeError, "descriptor 'conjugate' requires a 'float' object but received a '%s'", getTypeName(b)); + return NULL; + } if (b->cls == float_cls) { return incref(b); } else { @@ -1129,7 +1130,7 @@ static Box* floatConjugate(Box* b, void*) { } } -static Box* float0(Box*, void*) { +static Box* float0(Box*, void*) noexcept { return boxFloat(0.0); } @@ -1733,10 +1734,10 @@ void setupFloat() { float_cls->giveAttr("__long__", new BoxedFunction(FunctionMetadata::create((void*)floatLong, UNKNOWN, 1))); float_cls->giveAttr("__hash__", new BoxedFunction(FunctionMetadata::create((void*)floatHash, BOXED_INT, 1))); - float_cls->giveAttrDescriptor("real", floatConjugate, NULL); + float_cls->giveAttrDescriptor("real", float_conjugate, NULL); float_cls->giveAttrDescriptor("imag", float0, NULL); - float_cls->giveAttr("conjugate", - new BoxedFunction(FunctionMetadata::create((void*)floatConjugate, BOXED_FLOAT, 1))); + float_cls->giveAttr("conjugate", new BoxedFunction(FunctionMetadata::create((void*)float_conjugate, BOXED_FLOAT, 1, + ParamNames::empty(), CAPI))); float_cls->giveAttr("__doc__", boxString("float(x) -> floating point number\n" "\n" @@ -1746,7 +1747,7 @@ void setupFloat() { "__getformat__", floatGetFormatDoc)); for (auto& md : float_methods) { - float_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, float_cls)); + float_cls->giveAttr(md.ml_name, PyDescr_NewMethod(float_cls, &md)); } add_operators(float_cls); diff --git a/src/runtime/frame.cpp b/src/runtime/frame.cpp index d6d2efb1d..4e1ace232 100644 --- a/src/runtime/frame.cpp +++ b/src/runtime/frame.cpp @@ -79,7 +79,7 @@ class BoxedFrame : public Box { // * = unsupported in Pyston // ** = getter supported, but setter unsupported - static BORROWED(Box*) code(Box* obj, void*) { + static BORROWED(Box*) code(Box* obj, void*) noexcept { auto f = static_cast(obj); if (!f->_code) @@ -88,9 +88,9 @@ class BoxedFrame : public Box { return f->_code; } - static Box* f_code(Box* obj, void* arg) { return incref(code(obj, arg)); } + static Box* f_code(Box* obj, void* arg) noexcept { return incref(code(obj, arg)); } - static BORROWED(Box*) locals(Box* obj, void*) { + static BORROWED(Box*) locals(Box* obj, void*) noexcept { auto f = static_cast(obj); if (f->hasExited()) @@ -99,9 +99,9 @@ class BoxedFrame : public Box { return f->frame_info->updateBoxedLocals(); } - static Box* f_locals(Box* obj, void* arg) { return incref(locals(obj, arg)); } + static Box* f_locals(Box* obj, void* arg) noexcept { return incref(locals(obj, arg)); } - static BORROWED(Box*) globals(Box* obj, void*) { + static BORROWED(Box*) globals(Box* obj, void*) noexcept { auto f = static_cast(obj); if (!f->_globals) { @@ -116,9 +116,9 @@ class BoxedFrame : public Box { return f->_globals; } - static Box* f_globals(Box* obj, void* arg) { return incref(globals(obj, arg)); } + static Box* f_globals(Box* obj, void* arg) noexcept { return incref(globals(obj, arg)); } - static BORROWED(Box*) back(Box* obj, void*) { + static BORROWED(Box*) back(Box* obj, void*) noexcept { auto f = static_cast(obj); if (!f->_back) { @@ -131,9 +131,9 @@ class BoxedFrame : public Box { return f->_back; } - static Box* f_back(Box* obj, void* arg) { return incref(back(obj, arg)); } + static Box* f_back(Box* obj, void* arg) noexcept { return incref(back(obj, arg)); } - static Box* lineno(Box* obj, void*) { + static Box* lineno(Box* obj, void*) noexcept { auto f = static_cast(obj); if (f->hasExited()) diff --git a/src/runtime/generator.cpp b/src/runtime/generator.cpp index 08660d44c..380a94a04 100644 --- a/src/runtime/generator.cpp +++ b/src/runtime/generator.cpp @@ -500,7 +500,7 @@ extern "C" BoxedGenerator::BoxedGenerator(BoxedFunctionBase* function, Box* arg1 context = makeContext(stack_begin, (void (*)(intptr_t))generatorEntry); } -Box* generatorName(Box* _self, void* context) { +Box* generator_name(Box* _self, void* context) noexcept { assert(isSubclass(_self->cls, generator_cls)); BoxedGenerator* self = static_cast(_self); @@ -715,7 +715,7 @@ void setupGenerator() { = new BoxedFunction(FunctionMetadata::create((void*)generatorThrow, UNKNOWN, 4, false, false), { NULL, NULL }); generator_cls->giveAttr("throw", gthrow); - generator_cls->giveAttrDescriptor("__name__", generatorName, NULL); + generator_cls->giveAttrDescriptor("__name__", generator_name, NULL); generator_cls->freeze(); generator_cls->tp_iter = PyObject_SelfIter; diff --git a/src/runtime/int.cpp b/src/runtime/int.cpp index edb275f36..cb672d2d1 100644 --- a/src/runtime/int.cpp +++ b/src/runtime/int.cpp @@ -1395,7 +1395,7 @@ static void _addFuncIntUnknown(const char* name, ConcreteCompilerType* rtn_type, int_cls->giveAttr(name, new BoxedFunction(md)); } -static Box* intIntGetset(Box* b, void*) { +static Box* int_int_getset(Box* b, void*) noexcept { if (b->cls == int_cls) { return incref(b); } else { @@ -1404,11 +1404,11 @@ static Box* intIntGetset(Box* b, void*) { } } -static Box* int0(Box*, void*) { +static Box* int0(Box*, void*) noexcept { return boxInt(0); } -static Box* int1(Box*, void*) { +static Box* int1(Box*, void*) noexcept { return boxInt(1); } @@ -1608,10 +1608,11 @@ void setupInt() { int_cls->giveAttr("bit_length", new BoxedFunction(FunctionMetadata::create((void*)intBitLength, BOXED_INT, 1))); - int_cls->giveAttrDescriptor("real", intIntGetset, NULL); + // int_int_getset doesn't throw at all, so we can cheat and use it as both a CAPI and CXX style function. + int_cls->giveAttrDescriptor("real", int_int_getset, NULL); int_cls->giveAttrDescriptor("imag", int0, NULL); - int_cls->giveAttr("conjugate", new BoxedFunction(FunctionMetadata::create((void*)intIntGetset, BOXED_INT, 1))); - int_cls->giveAttrDescriptor("numerator", intIntGetset, NULL); + int_cls->giveAttr("conjugate", new BoxedFunction(FunctionMetadata::create((void*)int_int_getset, BOXED_INT, 1))); + int_cls->giveAttrDescriptor("numerator", int_int_getset, NULL); int_cls->giveAttrDescriptor("denominator", int1, NULL); add_operators(int_cls); diff --git a/src/runtime/long.cpp b/src/runtime/long.cpp index 154602f5a..384df4c30 100644 --- a/src/runtime/long.cpp +++ b/src/runtime/long.cpp @@ -787,7 +787,7 @@ Box* longInt(Box* v) { return boxInt(n); } -Box* longToLong(Box* self) { +Box* longToLong(Box* self) noexcept { if (self->cls == long_cls) { return incref(self); } else { @@ -1678,15 +1678,15 @@ static PyObject* long_pow(PyObject* v, PyObject* w, PyObject* x) noexcept { } } -static Box* longDesc(Box* b, void*) { +static Box* long_desc(Box* b, void*) noexcept { return longToLong(b); } -static Box* long0(Box* b, void*) { +static Box* long0(Box* b, void*) noexcept { return boxLong(0); } -static Box* long1(Box* b, void*) { +static Box* long1(Box* b, void*) noexcept { return boxLong(1); } @@ -1763,10 +1763,11 @@ void setupLong() { long_cls->giveAttr("__index__", new BoxedFunction(FunctionMetadata::create((void*)longIndex, LONG, 1))); long_cls->giveAttr("bit_length", new BoxedFunction(FunctionMetadata::create((void*)longBitLength, LONG, 1))); - long_cls->giveAttrDescriptor("real", longDesc, NULL); + long_cls->giveAttrDescriptor("real", long_desc, NULL); long_cls->giveAttrDescriptor("imag", long0, NULL); - long_cls->giveAttr("conjugate", new BoxedFunction(FunctionMetadata::create((void*)longDesc, UNKNOWN, 1))); - long_cls->giveAttrDescriptor("numerator", longDesc, NULL); + // long_desc is both CAPI and CXX style since it doesn't throw + long_cls->giveAttr("conjugate", new BoxedFunction(FunctionMetadata::create((void*)long_desc, UNKNOWN, 1))); + long_cls->giveAttrDescriptor("numerator", long_desc, NULL); long_cls->giveAttrDescriptor("denominator", long1, NULL); long_cls->giveAttr("__getnewargs__", new BoxedFunction(FunctionMetadata::create((void*)long_getnewargs, UNKNOWN, 1, diff --git a/src/runtime/objmodel.cpp b/src/runtime/objmodel.cpp index 8cc21a6ff..3920b92de 100644 --- a/src/runtime/objmodel.cpp +++ b/src/runtime/objmodel.cpp @@ -1803,7 +1803,7 @@ template Box* typeLookup(BoxedClass*, BoxedString*, GetattrRewri bool isNondataDescriptorInstanceSpecialCase(Box* descr) { return descr->cls == function_cls || descr->cls == instancemethod_cls || descr->cls == staticmethod_cls - || descr->cls == classmethod_cls || descr->cls == wrapperdescr_cls; + || descr->cls == classmethod_cls || descr->cls == &PyWrapperDescr_Type; } template @@ -1910,7 +1910,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box } return incref(sm->sm_callable); - } else if (descr->cls == wrapperdescr_cls) { + } else if (descr->cls == &PyWrapperDescr_Type) { if (for_call) { if (rewrite_args) { rewrite_args->setReturn(r_descr, ReturnConvention::HAS_RETURN); @@ -1919,17 +1919,16 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box *bind_obj_out = obj; return incref(descr); } else { - BoxedWrapperDescriptor* self = static_cast(descr); Box* inst = obj; Box* owner = obj->cls; - Box* r = BoxedWrapperDescriptor::descr_get(self, inst, owner); + Box* r = PyWrapperDescr_Type.tp_descr_get(descr, inst, owner); if (rewrite_args) { // TODO: inline this? RewriterVar* r_rtn = rewrite_args->rewriter->call( /* has_side_effects= */ false, - (void*)&BoxedWrapperDescriptor::descr_get, r_descr, rewrite_args->obj, + (void*)PyWrapperDescr_Type.tp_descr_get, r_descr, rewrite_args->obj, r_descr->getAttr(offsetof(Box, cls), Location::forArg(2))) ->setType(RefType::OWNED); @@ -1977,7 +1976,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls // These classes are descriptors, but only have special behavior when involved // in instance lookups - if (descr->cls == member_descriptor_cls || descr->cls == wrapperdescr_cls) { + if (descr->cls == &PyMemberDescr_Type || descr->cls == &PyWrapperDescr_Type) { if (rewrite_args) r_descr->addAttrGuard(offsetof(Box, cls), (uint64_t)descr->cls); @@ -2008,59 +2007,63 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS } // Special case: data descriptor: member descriptor - if (descr->cls == member_descriptor_cls) { + if (descr->cls == &PyMemberDescr_Type) { static StatCounter slowpath("slowpath_member_descriptor_get"); slowpath.log(); - BoxedMemberDescriptor* member_desc = static_cast(descr); + PyMemberDescrObject* member_desc = reinterpret_cast(descr); // TODO should also have logic to raise a type error if type of obj is wrong if (rewrite_args) { // TODO we could use offset as the index in the assembly lookup rather than hardcoding // the value in the assembly and guarding on it be the same. - // This could be optimized if addAttrGuard supported things < 64 bits - static_assert(sizeof(member_desc->offset) == 4, "assumed by assembly instruction below"); - r_descr->getAttr(offsetof(BoxedMemberDescriptor, offset), Location::any(), assembler::MovType::ZLQ) - ->addGuard(member_desc->offset); + auto r_memberdef = r_descr->getAttr(offsetof(PyMemberDescrObject, d_member)); + + static_assert(sizeof(member_desc->d_member->offset) == 8, "assumed by assembly instruction below"); + r_memberdef->addAttrGuard(offsetof(PyMemberDef, offset), member_desc->d_member->offset); - static_assert(sizeof(member_desc->type) == 4, "assumed by assembly instruction below"); - r_descr->getAttr(offsetof(BoxedMemberDescriptor, type), Location::any(), assembler::MovType::ZLQ) - ->addGuard(member_desc->type); + // This could be optimized if addAttrGuard supported things < 64 bits + static_assert(sizeof(member_desc->d_member->type) == 4, "assumed by assembly instruction below"); + r_memberdef->getAttr(offsetof(PyMemberDef, type), Location::any(), assembler::MovType::ZLQ) + ->addGuard(member_desc->d_member->type); } - switch (member_desc->type) { - case BoxedMemberDescriptor::OBJECT_EX: { + switch (member_desc->d_member->type) { + case T_OBJECT_EX: { if (rewrite_args) { - RewriterVar* r_rtn = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination) - ->setType(RefType::BORROWED); + RewriterVar* r_rtn + = rewrite_args->obj->getAttr(member_desc->d_member->offset, rewrite_args->destination) + ->setType(RefType::BORROWED); r_rtn->addGuardNotEq(0); rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); } - Box* rtn = *reinterpret_cast((char*)obj + member_desc->offset); + Box* rtn = *reinterpret_cast((char*)obj + member_desc->d_member->offset); if (rtn == NULL) { assert(attr_name->data()[attr_name->size()] == '\0'); raiseExcHelper(AttributeError, "%s", attr_name->data()); } return incref(rtn); } - case BoxedMemberDescriptor::OBJECT: { + case T_OBJECT: { if (rewrite_args) { - RewriterVar* r_interm = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination); + RewriterVar* r_interm + = rewrite_args->obj->getAttr(member_desc->d_member->offset, rewrite_args->destination); // TODO would be faster to not use a call RewriterVar* r_rtn = rewrite_args->rewriter->call(false, (void*)noneIfNull, r_interm)->setType(RefType::BORROWED); rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); } - Box* rtn = *reinterpret_cast((char*)obj + member_desc->offset); + Box* rtn = *reinterpret_cast((char*)obj + member_desc->d_member->offset); return incref(noneIfNull(rtn)); } - case BoxedMemberDescriptor::DOUBLE: { + case T_DOUBLE: { if (rewrite_args) { - RewriterVar* r_unboxed_val = rewrite_args->obj->getAttrDouble(member_desc->offset, assembler::XMM0); + RewriterVar* r_unboxed_val + = rewrite_args->obj->getAttrDouble(member_desc->d_member->offset, assembler::XMM0); RewriterVar::SmallVector normal_args; RewriterVar::SmallVector float_args; float_args.push_back(r_unboxed_val); @@ -2069,12 +2072,13 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); } - double rtn = *reinterpret_cast((char*)obj + member_desc->offset); + double rtn = *reinterpret_cast((char*)obj + member_desc->d_member->offset); return boxFloat(rtn); } - case BoxedMemberDescriptor::FLOAT: { + case T_FLOAT: { if (rewrite_args) { - RewriterVar* r_unboxed_val = rewrite_args->obj->getAttrFloat(member_desc->offset, assembler::XMM0); + RewriterVar* r_unboxed_val + = rewrite_args->obj->getAttrFloat(member_desc->d_member->offset, assembler::XMM0); RewriterVar::SmallVector normal_args; RewriterVar::SmallVector float_args; float_args.push_back(r_unboxed_val); @@ -2083,20 +2087,20 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); } - float rtn = *reinterpret_cast((char*)obj + member_desc->offset); + float rtn = *reinterpret_cast((char*)obj + member_desc->d_member->offset); return boxFloat((double)rtn); } #define CASE_INTEGER_TYPE(TYPE, type, boxFn, cast) \ - case BoxedMemberDescriptor::TYPE: { \ + case T_##TYPE: { \ if (rewrite_args) { \ - RewriterVar* r_unboxed_val = rewrite_args->obj->getAttrCast(member_desc->offset); \ + RewriterVar* r_unboxed_val = rewrite_args->obj->getAttrCast(member_desc->d_member->offset); \ RewriterVar* r_rtn \ = rewrite_args->rewriter->call(true, (void*)boxFn, r_unboxed_val)->setType(RefType::OWNED); \ /* XXX assuming that none of these throw a capi error! */ \ rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); \ } \ - type rtn = *reinterpret_cast((char*)obj + member_desc->offset); \ + type rtn = *reinterpret_cast((char*)obj + member_desc->d_member->offset); \ return boxFn((cast)rtn); \ } // Note that (a bit confusingly) boxInt takes int64_t, not an int @@ -2113,35 +2117,36 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS CASE_INTEGER_TYPE(LONGLONG, long long, PyLong_FromLongLong, long long) CASE_INTEGER_TYPE(ULONGLONG, unsigned long long, PyLong_FromUnsignedLongLong, unsigned long long) CASE_INTEGER_TYPE(PYSSIZET, Py_ssize_t, boxInt, Py_ssize_t) - case BoxedMemberDescriptor::STRING: { + case T_STRING: { if (rewrite_args) { - RewriterVar* r_interm = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination); + RewriterVar* r_interm + = rewrite_args->obj->getAttr(member_desc->d_member->offset, rewrite_args->destination); RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)boxStringOrNone, r_interm)->setType(RefType::OWNED); rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); } - char* rtn = *reinterpret_cast((char*)obj + member_desc->offset); + char* rtn = *reinterpret_cast((char*)obj + member_desc->d_member->offset); return boxStringOrNone(rtn); } - case BoxedMemberDescriptor::STRING_INPLACE: { + case T_STRING_INPLACE: { if (rewrite_args) { RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)boxStringFromCharPtr, rewrite_args->rewriter->add( - rewrite_args->obj, member_desc->offset, + rewrite_args->obj, member_desc->d_member->offset, rewrite_args->destination))->setType(RefType::OWNED); rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); } rewrite_args = NULL; REWRITE_ABORTED(""); - char* rtn = reinterpret_cast((char*)obj + member_desc->offset); + char* rtn = reinterpret_cast((char*)obj + member_desc->d_member->offset); return boxStringFromCharPtr(rtn); } default: - RELEASE_ASSERT(0, "%d", member_desc->type); + RELEASE_ASSERT(0, "%d", member_desc->d_member->type); } } @@ -2171,33 +2176,34 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS } // Special case: data descriptor: getset descriptor - else if (descr->cls == pyston_getset_cls || descr->cls == capi_getset_cls) { - BoxedGetsetDescriptor* getset_descr = static_cast(descr); + else if (descr->cls == &PyGetSetDescr_Type) { + PyGetSetDescrObject* getset_descr = reinterpret_cast(descr); // TODO some more checks should go here // getset descriptors (and some other types of builtin descriptors I think) should have // a field which gives the type that the descriptor should apply to. We need to check that obj // is of that type. - if (getset_descr->get == NULL) { + if (getset_descr->d_getset->get == NULL) { assert(attr_name->data()[attr_name->size()] == '\0'); raiseExcHelper(AttributeError, "attribute '%s' of '%s' object is not readable", attr_name->data(), - getTypeName(getset_descr)); + getTypeName((Box*)getset_descr)); } - Box* rtn = getset_descr->get(obj, getset_descr->closure); + Box* rtn = getset_descr->d_getset->get(obj, getset_descr->d_getset->closure); if (rewrite_args) { // hmm, maybe we should write assembly which can look up the function address and call any function - r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, get), (intptr_t)getset_descr->get); + auto r_getsetdef = r_descr->getAttr(offsetof(PyGetSetDescrObject, d_getset)); + r_getsetdef->addAttrGuard(offsetof(PyGetSetDef, get), (intptr_t)getset_descr->d_getset->get); - RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure)); - RewriterVar* r_rtn = rewrite_args->rewriter->call( - /* has_side_effects */ true, (void*)getset_descr->get, - rewrite_args->obj, r_closure)->setType(RefType::OWNED); + RewriterVar* r_closure = r_getsetdef->getAttr(offsetof(PyGetSetDef, closure)); + RewriterVar* r_rtn + = rewrite_args->rewriter->call( + /* has_side_effects */ true, (void*)getset_descr->d_getset->get, + rewrite_args->obj, r_closure)->setType(RefType::OWNED); - rewrite_args->setReturn(r_rtn, descr->cls == capi_getset_cls ? ReturnConvention::CAPI_RETURN - : ReturnConvention::MAYBE_EXC); + rewrite_args->setReturn(r_rtn, ReturnConvention::CAPI_RETURN); } return rtn; } @@ -2929,11 +2935,11 @@ bool dataDescriptorSetSpecialCases(Box* obj, STOLEN(Box*) val, Box* descr, Setat RewriterVar* r_descr, BoxedString* attr_name) { // Special case: getset descriptor - if (descr->cls == pyston_getset_cls || descr->cls == capi_getset_cls) { - BoxedGetsetDescriptor* getset_descr = static_cast(descr); + if (descr->cls == &PyGetSetDescr_Type) { + PyGetSetDescrObject* getset_descr = reinterpret_cast(descr); // TODO type checking goes here - if (getset_descr->set == NULL) { + if (getset_descr->d_getset->set == NULL) { assert(attr_name->data()[attr_name->size()] == '\0'); Py_DECREF(val); raiseExcHelper(AttributeError, "attribute '%s' of '%s' objects is not writable", attr_name->data(), @@ -2944,40 +2950,30 @@ bool dataDescriptorSetSpecialCases(Box* obj, STOLEN(Box*) val, Box* descr, Setat RewriterVar* r_obj = rewrite_args->obj; RewriterVar* r_val = rewrite_args->attrval; - r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, set), (intptr_t)getset_descr->set); - RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure)); + auto r_getset = r_descr->getAttr(offsetof(PyGetSetDescrObject, d_getset)); + r_getset->addAttrGuard(offsetof(PyGetSetDef, set), (intptr_t)getset_descr->d_getset->set); + RewriterVar* r_closure = r_getset->getAttr(offsetof(PyGetSetDef, closure)); RewriterVar::SmallVector args; args.push_back(r_obj); args.push_back(r_val); args.push_back(r_closure); RewriterVar* r_rtn = rewrite_args->rewriter->call( - /* has_side_effects */ true, (void*)getset_descr->set, args); + /* has_side_effects */ true, (void*)getset_descr->d_getset->set, args); - if (descr->cls == capi_getset_cls) - rewrite_args->rewriter->checkAndThrowCAPIException(r_rtn, -1, assembler::MovType::L); + rewrite_args->rewriter->checkAndThrowCAPIException(r_rtn, -1, assembler::MovType::L); rewrite_args->out_success = true; } AUTO_DECREF(val); - if (descr->cls == pyston_getset_cls) { - getset_descr->set_pyston(obj, val, getset_descr->closure); - } else { - int r = getset_descr->set_capi(obj, val, getset_descr->closure); - if (r) - throwCAPIException(); - } + int r = getset_descr->d_getset->set(obj, val, getset_descr->d_getset->closure); + if (r) + throwCAPIException(); return true; - } else if (descr->cls == member_descriptor_cls) { - BoxedMemberDescriptor* member_desc = static_cast(descr); - PyMemberDef member_def; - memset(&member_def, 0, sizeof(member_def)); - member_def.offset = member_desc->offset; - member_def.type = member_desc->type; - if (member_desc->readonly) - member_def.flags |= READONLY; - int ret = PyMember_SetOne((char*)obj, &member_def, val); + } else if (descr->cls == &PyMemberDescr_Type) { + PyMemberDescrObject* member_desc = reinterpret_cast(descr); + int ret = PyMember_SetOne((char*)obj, member_desc->d_member, val); Py_DECREF(val); if (ret < 0) throwCAPIException(); @@ -3373,9 +3369,8 @@ extern "C" bool nonzero(Box* obj) { || obj->cls == type_cls || isSubclass(obj->cls, Exception) || obj->cls == &PyFile_Type || obj->cls == &PyTraceBack_Type || obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == capifunc_cls || obj->cls == builtin_function_or_method_cls - || obj->cls == method_cls || obj->cls == frame_cls || obj->cls == generator_cls - || obj->cls == capi_getset_cls || obj->cls == pyston_getset_cls || obj->cls == wrapperdescr_cls - || obj->cls == wrapperobject_cls || obj->cls == code_cls, + || obj->cls == method_cls || obj->cls == &PyMethod_Type || obj->cls == frame_cls + || obj->cls == generator_cls || obj->cls == code_cls, "%s.__nonzero__", getTypeName(obj)); // TODO if (rewriter.get()) { @@ -5988,7 +5983,7 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit #ifndef NDEBUG if ((lhs->cls == int_cls || lhs->cls == float_cls || lhs->cls == long_cls) && (rhs->cls == int_cls || rhs->cls == float_cls || rhs->cls == long_cls)) { - printf("\n%s %s %s\n", lhs->cls->tp_name, op_name->c_str(), rhs->cls->tp_name); + fprintf(stderr, "\n%s %s %s\n", lhs->cls->tp_name, op_name->c_str(), rhs->cls->tp_name); Py_FatalError("missing comparison between these classes"); } #endif @@ -7019,13 +7014,12 @@ Box* _typeNew(BoxedClass* metatype, BoxedString* name, BoxedTuple* bases, BoxedD // Add the member descriptors size_t offset = base->tp_basicsize; for (size_t i = 0; i < final_slot_names.size(); i++) { - made->giveAttr(static_cast(slotsTuple->elts[i])->data(), - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT_EX, offset, false /* read only */)); - mp[i].name = static_cast(slotsTuple->elts[i])->data(); mp[i].type = T_OBJECT_EX; mp[i].offset = offset; + made->giveAttr(static_cast(slotsTuple->elts[i])->data(), PyDescr_NewMember(made, &mp[i])); + offset += sizeof(Box*); } } else { diff --git a/src/runtime/str.cpp b/src/runtime/str.cpp index f37307f09..aeeee5e79 100644 --- a/src/runtime/str.cpp +++ b/src/runtime/str.cpp @@ -2851,6 +2851,7 @@ static PyMethodDef string_methods[] = { { "__format__", (PyCFunction)string__format__, METH_VARARGS, NULL }, { "_formatter_parser", (PyCFunction)_formatter_parser, METH_NOARGS, NULL }, { "_formatter_field_name_split", (PyCFunction)_formatter_field_name_split, METH_NOARGS, NULL }, + { NULL, NULL, 0, NULL }, }; void setupStr() { @@ -2961,9 +2962,7 @@ void setupStr() { str_cls->giveAttr("__iter__", new BoxedFunction(FunctionMetadata::create((void*)strIter, typeFromClass(str_iterator_cls), 1))); - for (auto& md : string_methods) { - str_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, str_cls)); - } + add_methods(str_cls, string_methods); auto str_new = FunctionMetadata::create((void*)strNew, UNKNOWN, 2, false, false, ParamNames({ "", "object" }, "", ""), CXX); diff --git a/src/runtime/super.cpp b/src/runtime/super.cpp index 25ac40ebd..0ea84f14e 100644 --- a/src/runtime/super.cpp +++ b/src/runtime/super.cpp @@ -260,12 +260,9 @@ void setupSuper() { "__init__", new BoxedFunction(FunctionMetadata::create((void*)superInit, UNKNOWN, 3, false, false), { NULL })); super_cls->giveAttr("__get__", new BoxedFunction(FunctionMetadata::create((void*)superGet, UNKNOWN, 3))); - super_cls->giveAttr("__thisclass__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSuper, type))); - super_cls->giveAttr("__self__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSuper, obj))); - super_cls->giveAttr("__self_class__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSuper, obj_type))); + super_cls->giveAttrMember("__thisclass__", T_OBJECT, offsetof(BoxedSuper, type)); + super_cls->giveAttrMember("__self__", T_OBJECT, offsetof(BoxedSuper, obj)); + super_cls->giveAttrMember("__self_class__", T_OBJECT, offsetof(BoxedSuper, obj_type)); super_cls->freeze(); super_cls->tp_getattro = super_getattro; diff --git a/src/runtime/types.cpp b/src/runtime/types.cpp index 9c5ce094a..d83da3110 100644 --- a/src/runtime/types.cpp +++ b/src/runtime/types.cpp @@ -311,7 +311,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(FunctionMetadata* md, std::initi if (defaults.size()) { // HAX copy+modify the BoxedTuple constructor so that we can put NULLs into the tuple. // We are going to separately be careful to make sure that those NULLs don't escape - // to the user (see functionDefaults) + // to the user (see function_defaults) this->defaults = BoxedTuple::create(defaults.size()); int i = 0; for (auto e : defaults) { @@ -1366,29 +1366,31 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo return made; } -static Box* typeDict(Box* obj, void* context) { +static Box* type_dict(Box* obj, void* context) noexcept { if (obj->cls->instancesHaveHCAttrs()) return PyDictProxy_New(obj->getAttrWrapper()); abort(); } -static Box* typeSubDict(Box* obj, void* context) { +static Box* type_sub_dict(Box* obj, void* context) noexcept { // This should only be getting called for hc-backed classes: assert(obj->cls->instancesHaveHCAttrs()); return incref(obj->getAttrWrapper()); } -static void typeSubSetDict(BORROWED(Box*) obj, BORROWED(Box*) val, void* context) { +static int type_sub_set_dict(BORROWED(Box*) obj, BORROWED(Box*) val, void* context) noexcept { // This should only be getting called for hc-backed classes: assert(obj->cls->instancesHaveHCAttrs()); Py_INCREF(val); obj->setDictBacked(val); + + return 0; } extern "C" void PyType_SetDict(PyTypeObject* type, STOLEN(PyObject*) dict) noexcept { - typeSubSetDict(type, dict, NULL); + type_sub_set_dict(type, dict, NULL); Box* old_dict = type->tp_dict; type->tp_dict = dict; Py_DECREF(old_dict); @@ -1399,9 +1401,8 @@ Box* dict_descr = NULL; extern "C" { BoxedClass* object_cls, *type_cls, *none_cls, *bool_cls, *int_cls, *float_cls, * str_cls = NULL, *function_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, - *member_descriptor_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *property_cls, - *staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *pyston_getset_cls, *capi_getset_cls, - *builtin_function_or_method_cls, *attrwrapperiter_cls, *set_cls, *frozenset_cls; + *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *property_cls, *staticmethod_cls, *classmethod_cls, + *attrwrapper_cls, *builtin_function_or_method_cls, *attrwrapperiter_cls, *set_cls, *frozenset_cls; BoxedTuple* EmptyTuple; } @@ -1537,7 +1538,7 @@ static Box* functionCall(BoxedFunction* self, Box* args, Box* kwargs) { return runtimeCall(self, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL, NULL); } -static Box* funcName(Box* b, void*) { +static Box* func_name(Box* b, void*) noexcept { assert(b->cls == function_cls); BoxedFunction* func = static_cast(b); if (func->name == NULL) @@ -1545,20 +1546,22 @@ static Box* funcName(Box* b, void*) { return incref(func->name); } -static void funcSetName(Box* b, Box* v, void*) { +static int func_set_name(Box* b, Box* v, void*) noexcept { assert(b->cls == function_cls); BoxedFunction* func = static_cast(b); if (v == NULL || !PyString_Check(v)) { - raiseExcHelper(TypeError, "__name__ must be set to a string object"); + PyErr_Format(TypeError, "__name__ must be set to a string object"); + return -1; } auto old_name = func->name; func->name = incref(static_cast(v)); Py_XDECREF(old_name); + return 0; } -static Box* builtinFunctionOrMethodName(Box* b, void*) { +static Box* builtin_function_or_method_name(Box* b, void*) noexcept { // In CPython, these guys just store char*, and it gets wrapped here // But we already share the BoxedString* field with BoxedFunctions... // so it's more convenient to just use that, which is what we do here. @@ -1570,32 +1573,23 @@ static Box* builtinFunctionOrMethodName(Box* b, void*) { return incref(func->name); } -static Box* wrapperobjectName(Box* w, void*) { - assert(w->cls == wrapperobject_cls); - BoxedWrapperObject* wrapper_obj = static_cast(w); - return boxString(wrapper_obj->descr->wrapper->name); -} - -static Box* functionCode(Box* self, void*) { +static Box* function_code(Box* self, void*) noexcept { assert(self->cls == function_cls); BoxedFunction* func = static_cast(self); return incref(func->md->getCode()); } extern "C" PyObject* PyFunction_GetCode(PyObject* func) noexcept { - try { - return functionCode((Box*)func, NULL); - } catch (ExcInfo e) { - setCAPIException(e); - return NULL; - } + return function_code((Box*)func, NULL); } -static void functionSetCode(Box* self, Box* v, void*) { +static int function_set_code(Box* self, Box* v, void*) noexcept { assert(self->cls == function_cls); - if (v == NULL || !PyCode_Check(v)) - raiseExcHelper(TypeError, "__code__ must be set to a code object"); + if (v == NULL || !PyCode_Check(v)) { + PyErr_Format(TypeError, "__code__ must be set to a code object"); + return -1; + } BoxedFunction* func = static_cast(self); BoxedCode* code = static_cast(v); @@ -1607,9 +1601,11 @@ static void functionSetCode(Box* self, Box* v, void*) { func->md = code->f; func->dependent_ics.invalidateAll(); + + return 0; } -static Box* functionDefaults(Box* self, void*) { +static Box* function_defaults(Box* self, void*) noexcept { assert(self->cls == function_cls); BoxedFunction* func = static_cast(self); if (!func->defaults) @@ -1620,7 +1616,7 @@ static Box* functionDefaults(Box* self, void*) { return incref(func->defaults); } -static Box* functionGlobals(Box* self, void*) { +static Box* function_globals(Box* self, void*) noexcept { assert(self->cls == function_cls); BoxedFunction* func = static_cast(self); if (func->globals) { @@ -1631,10 +1627,10 @@ static Box* functionGlobals(Box* self, void*) { assert(func->md->source->scoping->areGlobalsFromModule()); static BoxedString* dict_str = getStaticString("__dict__"); - return getattr(func->md->source->parent_module, dict_str); + return getattrInternal(func->md->source->parent_module, dict_str); } -static void functionSetDefaults(Box* b, Box* v, void*) { +static int function_set_defaults(Box* b, Box* v, void*) noexcept { assert(b->cls == function_cls); BoxedFunction* func = static_cast(b); @@ -1654,7 +1650,8 @@ static void functionSetDefaults(Box* b, Box* v, void*) { if (v == None) v = NULL; else if (v && !PyTuple_Check(v)) { - raiseExcHelper(TypeError, "__defaults__ must be set to a tuple object"); + PyErr_Format(TypeError, "__defaults__ must be set to a tuple object"); + return -1; } BoxedTuple* t = static_cast(v); @@ -1663,6 +1660,7 @@ static void functionSetDefaults(Box* b, Box* v, void*) { func->defaults = xincref(t); // t can be NULL for 'del f.func_defaults' Py_XDECREF(old_defaults); func->dependent_ics.invalidateAll(); + return 0; } static Box* functionNonzero(BoxedFunction* self) { @@ -2005,7 +2003,7 @@ Box* typeRepr(BoxedClass* self) { return boxString(os.str()); } -static PyObject* typeModule(Box* _type, void* context) { +static PyObject* type_module(Box* _type, void* context) noexcept { PyTypeObject* type = static_cast(_type); PyObject* mod; @@ -2014,8 +2012,10 @@ static PyObject* typeModule(Box* _type, void* context) { if (type->tp_flags & Py_TPFLAGS_HEAPTYPE && type->is_user_defined) { static BoxedString* module_str = getStaticString("__module__"); mod = type->getattr(module_str); - if (!mod) - raiseExcHelper(AttributeError, "__module__"); + if (!mod) { + PyErr_Format(AttributeError, "__module__"); + return NULL; + } return incref(mod); } else { s = strrchr(type->tp_name, '.'); @@ -2025,20 +2025,23 @@ static PyObject* typeModule(Box* _type, void* context) { } } -static void typeSetModule(Box* _type, PyObject* value, void* context) { +static int type_set_module(Box* _type, PyObject* value, void* context) noexcept { PyTypeObject* type = static_cast(_type); if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - raiseExcHelper(TypeError, "can't set %s.__module__", type->tp_name); + PyErr_Format(TypeError, "can't set %s.__module__", type->tp_name); + return -1; } if (!value) { - raiseExcHelper(TypeError, "can't delete %s.__module__", type->tp_name); + PyErr_Format(TypeError, "can't delete %s.__module__", type->tp_name); + return -1; } PyType_Modified(type); static BoxedString* module_str = getStaticString("__module__"); type->setattr(module_str, value, NULL); + return 0; } @@ -2784,14 +2787,17 @@ Box* AttrWrapperIter::next_capi(Box* _self) noexcept { return incref(r); } -void Box::giveAttrDescriptor(const char* attr, Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*)) { +void Box::giveAttrDescriptor(const char* attr, Box* (*get)(Box*, void*), int (*set)(Box*, Box*, void*)) { BoxedString* bstr = internStringMortal(attr); - giveAttr(bstr, new (pyston_getset_cls) BoxedGetsetDescriptor(bstr, get, set, NULL)); + assert(this->cls == type_cls); + giveAttr(bstr, PyDescr_NewGetSet(static_cast(this), new PyGetSetDef{ attr, get, set, NULL, NULL })); } -void Box::giveCapiAttrDescriptor(const char* attr, Box* (*get)(Box*, void*), int (*set)(Box*, Box*, void*)) { +void Box::giveAttrMember(const char* attr, int type, ssize_t offset, bool readonly) { BoxedString* bstr = internStringMortal(attr); - giveAttr(bstr, new (capi_getset_cls) BoxedGetsetDescriptor(bstr, get, set, NULL)); + assert(this->cls == type_cls); + giveAttr(bstr, PyDescr_NewMember(static_cast(this), + new PyMemberDef{ attr, type, offset, readonly ? READONLY : 0, NULL })); } BORROWED(Box*) Box::getAttrWrapper() { @@ -2910,14 +2916,6 @@ static int type_set_abstractmethods(PyTypeObject* type, PyObject* value, void* c return res; } -static void typeSetAbstractMethods(Box* _type, PyObject* value, void* context) { - RELEASE_ASSERT(PyType_Check(_type), ""); - PyTypeObject* type = static_cast(_type); - - if (type_set_abstractmethods(type, value, context) == -1) - throwCAPIException(); -} - static PyObject* type_abstractmethods(PyTypeObject* type, void* context) noexcept { PyObject* mod = NULL; /* type itself has an __abstractmethods__ descriptor (this). Don't return @@ -2932,15 +2930,6 @@ static PyObject* type_abstractmethods(PyTypeObject* type, void* context) noexcep return mod; } -static Box* typeAbstractMethods(Box* _type, void* c) { - RELEASE_ASSERT(PyType_Check(_type), ""); - PyTypeObject* type = static_cast(_type); - Box* rtn = type_abstractmethods(type, c); - if (!rtn) - throwCAPIException(); - return rtn; -} - static PyObject* object_new(PyTypeObject* type, PyObject* args, PyObject* kwds) noexcept { int err = 0; if (excess_args(args, kwds)) { @@ -3003,19 +2992,16 @@ static PyObject* object_new(PyTypeObject* type, PyObject* args, PyObject* kwds) return type->tp_alloc(type, 0); } -static Box* typeName(Box* b, void*); +static Box* type_name(Box* b, void*) noexcept; Box* objectRepr(Box* self) { BoxedClass* type = self->cls; DecrefHandle mod(NULL); - try { - mod = typeModule(type, NULL); - if (!PyString_Check(mod)) - mod = NULL; - } catch (ExcInfo e) { - e.clear(); - } - DecrefHandle name(typeName(type, NULL)); + mod = type_module(type, NULL); + if (!PyString_Check(mod)) + mod = NULL; + + DecrefHandle name(type_name(type, NULL)); if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__")) return PyString_FromFormat("<%s.%s object at %p>", PyString_AS_STRING(mod), PyString_AS_STRING(name), self); return PyString_FromFormat("<%s object at %p>", type->tp_name, self); @@ -3391,7 +3377,7 @@ static PyMethodDef object_methods[] = { { "__format__", object_format, METH_VARARGS, PyDoc_STR("default object formatter") }, }; -static Box* typeName(Box* b, void*) { +static Box* type_name(Box* b, void*) noexcept { RELEASE_ASSERT(PyType_Check(b), ""); BoxedClass* type = static_cast(b); @@ -3408,7 +3394,7 @@ static Box* typeName(Box* b, void*) { } } -static void typeSetName(Box* b, Box* v, void*) { +static int type_set_name(Box* b, Box* v, void*) noexcept { assert(PyType_Check(b)); BoxedClass* type = static_cast(b); @@ -3419,18 +3405,22 @@ static void typeSetName(Box* b, Box* v, void*) { // TODO is this predicate right? bool is_heaptype = (type->tp_flags & Py_TPFLAGS_HEAPTYPE); if (!(is_heaptype && type->is_user_defined)) { - raiseExcHelper(TypeError, "can't set %s.__name__", type->tp_name); + PyErr_Format(TypeError, "can't set %s.__name__", type->tp_name); + return -1; } if (!v) { - raiseExcHelper(TypeError, "can't delete %s.__name__", type->tp_name); + PyErr_Format(TypeError, "can't delete %s.__name__", type->tp_name); + return -1; } if (!PyString_Check(v)) { - raiseExcHelper(TypeError, "can only assign string to %s.__name__, not '%s'", type->tp_name, getTypeName(v)); + PyErr_Format(TypeError, "can only assign string to %s.__name__, not '%s'", type->tp_name, getTypeName(v)); + return -1; } BoxedString* s = static_cast(v); if (strlen(s->data()) != s->size()) { - raiseExcHelper(ValueError, "__name__ must not contain null bytes"); + PyErr_Format(ValueError, "__name__ must not contain null bytes"); + return -1; } BoxedHeapClass* ht = static_cast(type); @@ -3438,9 +3428,11 @@ static void typeSetName(Box* b, Box* v, void*) { ht->ht_name = incref(s); ht->tp_name = s->data(); Py_DECREF(old_name); + + return 0; } -static Box* typeBases(Box* b, void*) { +static Box* type_bases(Box* b, void*) noexcept { RELEASE_ASSERT(PyType_Check(b), ""); BoxedClass* type = static_cast(b); @@ -3448,13 +3440,6 @@ static Box* typeBases(Box* b, void*) { return incref(type->tp_bases); } -static void typeSetBases(Box* b, Box* v, void* c) { - RELEASE_ASSERT(PyType_Check(b), ""); - BoxedClass* type = static_cast(b); - if (type_set_bases(type, v, c) == -1) - throwCAPIException(); -} - // cls should be obj->cls. // Added as parameter because it should typically be available inline void initUserAttrs(Box* obj, BoxedClass* cls) { @@ -3607,52 +3592,6 @@ void dealloc_null(Box* box) { assert(box->cls->tp_del == NULL); } -static Box* getsetGet(Box* self, Box* obj, Box* type) { - // TODO: should call the full descr_check instead - if (obj == NULL || obj == None) - return incref(self); - - BoxedGetsetDescriptor* getset_descr = static_cast(self); - - assert(getset_descr->get != NULL); - - if (isSubclass(self->cls, pyston_getset_cls)) { - return getset_descr->get(obj, getset_descr->closure); - } else { - RELEASE_ASSERT(isSubclass(self->cls, capi_getset_cls), ""); - Box* r = getset_descr->get(obj, getset_descr->closure); - if (!r) - throwCAPIException(); - return r; - } -} - -static Box* getsetSet(Box* self, Box* obj, Box* val) { - assert(obj != NULL && obj != None); - - BoxedGetsetDescriptor* getset_descr = static_cast(self); - - if (getset_descr->set == NULL) { - raiseExcHelper(AttributeError, "attribute '%s' of '%s' objects is not writable", getset_descr->name->data(), - obj->cls->tp_name); - } - - if (isSubclass(self->cls, pyston_getset_cls)) { - getset_descr->set_pyston(obj, val, getset_descr->closure); - return incref(None); - } else { - RELEASE_ASSERT(isSubclass(self->cls, capi_getset_cls), ""); - int r = getset_descr->set_capi(obj, val, getset_descr->closure); - if (r) - throwCAPIException(); - return incref(None); - } -} - -static Box* getsetDelete(Box* self, Box* obj) { - return getsetSet(self, obj, NULL); -} - void Box::clearAttrsForDealloc() { if (cls->instancesHaveHCAttrs()) { HCAttrs* attrs = getHCAttrsPtr(); @@ -3994,14 +3933,6 @@ int BoxedClosure::clear(Box* _o) noexcept { return 0; } -void BoxedGetsetDescriptor::dealloc(Box* _o) noexcept { - BoxedGetsetDescriptor* o = (BoxedGetsetDescriptor*)_o; - - Py_XDECREF(o->name); - - o->cls->tp_free(o); -} - #ifndef Py_REF_DEBUG #define PRINT_TOTAL_REFS() #else /* Py_REF_DEBUG */ @@ -4159,8 +4090,6 @@ void setupRuntime() { list_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedList), false, "list", true, BoxedList::dealloc, NULL, true, BoxedList::traverse, BoxedList::clear); list_cls->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS; - pyston_getset_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedGetsetDescriptor), false, "getset_descriptor", - false, BoxedGetsetDescriptor::dealloc, NULL, false); attrwrapper_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(AttrWrapper), false, "attrwrapper", false, AttrWrapper::dealloc, NULL, true, AttrWrapper::traverse, AttrWrapper::tp_clear); @@ -4185,20 +4114,12 @@ void setupRuntime() { module_cls = new (0) BoxedClass(object_cls, offsetof(BoxedModule, attrs), 0, sizeof(BoxedModule), false, "module", true, BoxedModule::dealloc, NULL, true, BoxedModule::traverse, BoxedModule::clear); - member_descriptor_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedMemberDescriptor), false, - "member_descriptor", false, NULL, NULL, false); capifunc_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedCApiFunction), false, "capifunc", true, BoxedCApiFunction::dealloc, NULL, true, BoxedCApiFunction::traverse, BoxedCApiFunction::clear); method_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedMethodDescriptor), false, "method_descriptor", false, BoxedMethodDescriptor::dealloc, NULL, true, BoxedMethodDescriptor::traverse, NOCLEAR); - wrapperobject_cls = new (0) - BoxedClass(object_cls, 0, 0, sizeof(BoxedWrapperObject), false, "method-wrapper", false, - BoxedWrapperObject::dealloc, NULL, true, BoxedWrapperObject::traverse, NOCLEAR); - wrapperdescr_cls = new (0) - BoxedClass(object_cls, 0, 0, sizeof(BoxedWrapperDescriptor), false, "wrapper_descriptor", false, - BoxedWrapperDescriptor::dealloc, NULL, true, BoxedWrapperDescriptor::traverse, NOCLEAR); EmptyString = new (0) BoxedString(""); constants.push_back(EmptyString); @@ -4219,7 +4140,6 @@ void setupRuntime() { object_cls->tp_mro = BoxedTuple::create({ object_cls }); list_cls->tp_mro = BoxedTuple::create({ list_cls, object_cls }); type_cls->tp_mro = BoxedTuple::create({ type_cls, object_cls }); - pyston_getset_cls->tp_mro = BoxedTuple::create({ pyston_getset_cls, object_cls }); attrwrapper_cls->tp_mro = BoxedTuple::create({ attrwrapper_cls, object_cls }); dict_cls->tp_mro = BoxedTuple::create({ dict_cls, object_cls }); int_cls->tp_mro = BoxedTuple::create({ int_cls, object_cls }); @@ -4229,12 +4149,9 @@ void setupRuntime() { float_cls->tp_mro = BoxedTuple::create({ float_cls, object_cls }); function_cls->tp_mro = BoxedTuple::create({ function_cls, object_cls }); builtin_function_or_method_cls->tp_mro = BoxedTuple::create({ builtin_function_or_method_cls, object_cls }); - member_descriptor_cls->tp_mro = BoxedTuple::create({ member_descriptor_cls, object_cls }); capifunc_cls->tp_mro = BoxedTuple::create({ capifunc_cls, object_cls }); module_cls->tp_mro = BoxedTuple::create({ module_cls, object_cls }); method_cls->tp_mro = BoxedTuple::create({ method_cls, object_cls }); - wrapperobject_cls->tp_mro = BoxedTuple::create({ wrapperobject_cls, object_cls }); - wrapperdescr_cls->tp_mro = BoxedTuple::create({ wrapperdescr_cls, object_cls }); object_cls->tp_hash = (hashfunc)_Py_HashPointer; @@ -4278,7 +4195,6 @@ void setupRuntime() { none_cls->finishInitialization(); tuple_cls->finishInitialization(); list_cls->finishInitialization(); - pyston_getset_cls->finishInitialization(); attrwrapper_cls->finishInitialization(); dict_cls->finishInitialization(); int_cls->finishInitialization(); @@ -4288,19 +4204,16 @@ void setupRuntime() { float_cls->finishInitialization(); function_cls->finishInitialization(); builtin_function_or_method_cls->finishInitialization(); - member_descriptor_cls->finishInitialization(); module_cls->finishInitialization(); capifunc_cls->finishInitialization(); method_cls->finishInitialization(); - wrapperobject_cls->finishInitialization(); - wrapperdescr_cls->finishInitialization(); str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; - dict_descr = new (pyston_getset_cls) - BoxedGetsetDescriptor(getStaticString("__dict__"), typeSubDict, typeSubSetDict, NULL); + dict_descr + = PyDescr_NewGetSet(object_cls, new PyGetSetDef{ "__dict__", type_sub_dict, type_sub_set_dict, NULL, NULL }); constants.push_back(dict_descr); - type_cls->giveAttrDescriptor("__dict__", typeDict, NULL); + type_cls->giveAttrDescriptor("__dict__", type_dict, NULL); instancemethod_cls = BoxedClass::create( @@ -4314,8 +4227,6 @@ void setupRuntime() { frozenset_cls = BoxedClass::create(type_cls, object_cls, 0, offsetof(BoxedSet, weakreflist), sizeof(BoxedSet), false, "frozenset", true, BoxedSet::dealloc, NULL, true, BoxedSet::traverse, BoxedSet::clear); - capi_getset_cls = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedGetsetDescriptor), false, "getset", - true, BoxedGetsetDescriptor::dealloc, NULL, false); closure_cls = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedClosure), false, "closure", true, BoxedClosure::dealloc, NULL, true, BoxedClosure::traverse, BoxedClosure::clear); property_cls = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(BoxedProperty), false, "property", true, @@ -4329,19 +4240,6 @@ void setupRuntime() { attrwrapperiter_cls = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(AttrWrapperIter), false, "attrwrapperiter", true, AttrWrapperIter::dealloc, NULL, false); - pyston_getset_cls->giveAttr("__get__", - new BoxedFunction(FunctionMetadata::create((void*)getsetGet, UNKNOWN, 3), { None })); - capi_getset_cls->giveAttr("__get__", - new BoxedFunction(FunctionMetadata::create((void*)getsetGet, UNKNOWN, 3), { None })); - pyston_getset_cls->giveAttr("__set__", new BoxedFunction(FunctionMetadata::create((void*)getsetSet, UNKNOWN, 3))); - capi_getset_cls->giveAttr("__set__", new BoxedFunction(FunctionMetadata::create((void*)getsetSet, UNKNOWN, 3))); - pyston_getset_cls->giveAttr("__delete__", - new BoxedFunction(FunctionMetadata::create((void*)getsetDelete, UNKNOWN, 2))); - capi_getset_cls->giveAttr("__delete__", - new BoxedFunction(FunctionMetadata::create((void*)getsetDelete, UNKNOWN, 2))); - pyston_getset_cls->freeze(); - capi_getset_cls->freeze(); - SLICE = typeFromClass(slice_cls); SET = typeFromClass(set_cls); FROZENSET = typeFromClass(frozenset_cls); @@ -4362,9 +4260,9 @@ void setupRuntime() { typeCallObj->internal_callable.capi_val = &typeCallInternal; typeCallObj->internal_callable.cxx_val = &typeCallInternal; - type_cls->giveAttrDescriptor("__name__", typeName, typeSetName); - type_cls->giveAttrDescriptor("__bases__", typeBases, typeSetBases); - type_cls->giveAttrDescriptor("__abstractmethods__", typeAbstractMethods, typeSetAbstractMethods); + type_cls->giveAttrDescriptor("__name__", type_name, type_set_name); + type_cls->giveAttrDescriptor("__bases__", type_bases, (setter)type_set_bases); + type_cls->giveAttrDescriptor("__abstractmethods__", (getter)type_abstractmethods, (setter)type_set_abstractmethods); type_cls->giveAttr("__call__", new BoxedFunction(typeCallObj)); @@ -4373,11 +4271,9 @@ void setupRuntime() { new BoxedFunction(FunctionMetadata::create((void*)typeNewGeneric, UNKNOWN, 4, false, false), { NULL, NULL })); type_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)typeRepr, STR, 1))); type_cls->tp_hash = (hashfunc)_Py_HashPointer; - type_cls->giveAttrDescriptor("__module__", typeModule, typeSetModule); - type_cls->giveAttr("__mro__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedClass, tp_mro))); - type_cls->giveAttr("__flags__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::LONG, offsetof(BoxedClass, tp_flags))); + type_cls->giveAttrDescriptor("__module__", type_module, type_set_module); + type_cls->giveAttrMember("__mro__", T_OBJECT, offsetof(BoxedClass, tp_mro)); + type_cls->giveAttrMember("__flags__", T_LONG, offsetof(BoxedClass, tp_flags)); type_cls->giveAttr("__subclasses__", new BoxedFunction(FunctionMetadata::create((void*)typeSubclasses, UNKNOWN, 1))); type_cls->giveAttr("mro", new BoxedFunction(FunctionMetadata::create((void*)typeMro, UNKNOWN, 1))); @@ -4412,7 +4308,7 @@ void setupRuntime() { for (auto& md : object_methods) { object_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, object_cls)); } - object_cls->giveCapiAttrDescriptor("__class__", object_get_class, object_set_class); + object_cls->giveAttrDescriptor("__class__", object_get_class, object_set_class); object_cls->tp_str = object_str; add_operators(object_cls); @@ -4445,41 +4341,37 @@ void setupRuntime() { setupFrame(); function_cls->giveAttrBorrowed("__dict__", dict_descr); - function_cls->giveAttrDescriptor("__name__", funcName, funcSetName); + function_cls->giveAttrDescriptor("__name__", func_name, func_set_name); function_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)functionRepr, STR, 1))); - function_cls->giveAttr("__module__", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, - offsetof(BoxedFunction, modname), false)); - function_cls->giveAttr( - "__doc__", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedFunction, doc), false)); + function_cls->giveAttrMember("__module__", T_OBJECT, offsetof(BoxedFunction, modname), false); + function_cls->giveAttrMember("__doc__", T_OBJECT, offsetof(BoxedFunction, doc), false); function_cls->giveAttrBorrowed("func_doc", function_cls->getattr(getStaticString("__doc__"))); - function_cls->giveAttrDescriptor("__globals__", functionGlobals, NULL); + function_cls->giveAttrDescriptor("__globals__", function_globals, NULL); function_cls->giveAttr("__get__", new BoxedFunction(FunctionMetadata::create((void*)functionGet, UNKNOWN, 3))); function_cls->giveAttr("__call__", new BoxedFunction(FunctionMetadata::create((void*)functionCall, UNKNOWN, 1, true, true))); function_cls->giveAttr("__nonzero__", new BoxedFunction(FunctionMetadata::create((void*)functionNonzero, BOXED_BOOL, 1))); - function_cls->giveAttrDescriptor("func_code", functionCode, functionSetCode); + function_cls->giveAttrDescriptor("func_code", function_code, function_set_code); function_cls->giveAttrBorrowed("__code__", function_cls->getattr(getStaticString("func_code"))); function_cls->giveAttrBorrowed("func_name", function_cls->getattr(getStaticString("__name__"))); - function_cls->giveAttrDescriptor("func_defaults", functionDefaults, functionSetDefaults); + function_cls->giveAttrDescriptor("func_defaults", function_defaults, function_set_defaults); function_cls->giveAttrBorrowed("__defaults__", function_cls->getattr(getStaticString("func_defaults"))); function_cls->giveAttrBorrowed("func_globals", function_cls->getattr(getStaticString("__globals__"))); function_cls->freeze(); function_cls->tp_descr_get = function_descr_get; - builtin_function_or_method_cls->giveAttr( - "__module__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedBuiltinFunctionOrMethod, modname))); + builtin_function_or_method_cls->giveAttrMember("__module__", T_OBJECT, + offsetof(BoxedBuiltinFunctionOrMethod, modname)); builtin_function_or_method_cls->giveAttr( "__call__", new BoxedFunction(FunctionMetadata::create((void*)builtinFunctionOrMethodCall, UNKNOWN, 1, true, true))); builtin_function_or_method_cls->giveAttr( "__repr__", new BoxedFunction(FunctionMetadata::create((void*)builtinFunctionOrMethodRepr, STR, 1))); - builtin_function_or_method_cls->giveAttrDescriptor("__name__", builtinFunctionOrMethodName, NULL); - builtin_function_or_method_cls->giveAttr( - "__doc__", - new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedBuiltinFunctionOrMethod, doc), false)); + builtin_function_or_method_cls->giveAttrDescriptor("__name__", builtin_function_or_method_name, NULL); + builtin_function_or_method_cls->giveAttrMember("__doc__", T_OBJECT, offsetof(BoxedBuiltinFunctionOrMethod, doc), + false); builtin_function_or_method_cls->freeze(); instancemethod_cls->giveAttr( @@ -4493,18 +4385,13 @@ void setupRuntime() { "__get__", new BoxedFunction(FunctionMetadata::create((void*)instancemethodGet, UNKNOWN, 3, false, false))); instancemethod_cls->giveAttr( "__call__", new BoxedFunction(FunctionMetadata::create((void*)instancemethodCall, UNKNOWN, 1, true, true))); - instancemethod_cls->giveAttr( - "im_func", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedInstanceMethod, func))); + instancemethod_cls->giveAttrMember("im_func", T_OBJECT, offsetof(BoxedInstanceMethod, func)); instancemethod_cls->giveAttrBorrowed("__func__", instancemethod_cls->getattr(getStaticString("im_func"))); - instancemethod_cls->giveAttr( - "im_self", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedInstanceMethod, obj))); + instancemethod_cls->giveAttrMember("im_self", T_OBJECT, offsetof(BoxedInstanceMethod, obj)); instancemethod_cls->giveAttrBorrowed("__self__", instancemethod_cls->getattr(getStaticString("im_self"))); instancemethod_cls->freeze(); - instancemethod_cls->giveAttr("im_class", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, - offsetof(BoxedInstanceMethod, im_class), true)); - - wrapperobject_cls->giveAttrDescriptor("__name__", wrapperobjectName, NULL); + instancemethod_cls->giveAttrMember("im_class", T_OBJECT, offsetof(BoxedInstanceMethod, im_class), true); slice_cls->giveAttr( "__new__", @@ -4513,9 +4400,9 @@ void setupRuntime() { slice_cls->giveAttr("__hash__", new BoxedFunction(FunctionMetadata::create((void*)sliceHash, UNKNOWN, 1))); slice_cls->giveAttr("indices", new BoxedFunction(FunctionMetadata::create((void*)sliceIndices, BOXED_TUPLE, 2))); slice_cls->giveAttr("__reduce__", new BoxedFunction(FunctionMetadata::create((void*)sliceReduce, BOXED_TUPLE, 1))); - slice_cls->giveAttr("start", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSlice, start))); - slice_cls->giveAttr("stop", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSlice, stop))); - slice_cls->giveAttr("step", new BoxedMemberDescriptor(BoxedMemberDescriptor::OBJECT, offsetof(BoxedSlice, step))); + slice_cls->giveAttrMember("start", T_OBJECT, offsetof(BoxedSlice, start)); + slice_cls->giveAttrMember("stop", T_OBJECT, offsetof(BoxedSlice, stop)); + slice_cls->giveAttrMember("step", T_OBJECT, offsetof(BoxedSlice, step)); slice_cls->freeze(); slice_cls->tp_compare = (cmpfunc)slice_compare; diff --git a/src/runtime/types.h b/src/runtime/types.h index b3d322157..0a52dad6f 100644 --- a/src/runtime/types.h +++ b/src/runtime/types.h @@ -77,10 +77,9 @@ extern "C" BoxedString* EmptyString; extern "C" { extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float_cls, *str_cls, *function_cls, *none_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *enumerate_cls, - *xrange_cls, *member_descriptor_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, - *property_cls, *staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *pyston_getset_cls, *capi_getset_cls, - *builtin_function_or_method_cls, *set_cls, *frozenset_cls, *code_cls, *frame_cls, *capifunc_cls, *wrapperdescr_cls, - *wrapperobject_cls; + *xrange_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *property_cls, + *staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *builtin_function_or_method_cls, *set_cls, *frozenset_cls, + *code_cls, *frame_cls, *capifunc_cls; } #define unicode_cls (&PyUnicode_Type) #define memoryview_cls (&PyMemoryView_Type) @@ -1169,69 +1168,6 @@ static_assert(offsetof(BoxedSlice, start) == offsetof(PySliceObject, start), "") static_assert(offsetof(BoxedSlice, stop) == offsetof(PySliceObject, stop), ""); static_assert(offsetof(BoxedSlice, step) == offsetof(PySliceObject, step), ""); -class BoxedMemberDescriptor : public Box { -public: - enum MemberType { - BOOL = T_BOOL, - BYTE = T_BYTE, - INT = T_INT, - OBJECT = T_OBJECT, - OBJECT_EX = T_OBJECT_EX, - FLOAT = T_FLOAT, - SHORT = T_SHORT, - LONG = T_LONG, - DOUBLE = T_DOUBLE, - STRING = T_STRING, - STRING_INPLACE = T_STRING_INPLACE, - CHAR = T_CHAR, - UBYTE = T_UBYTE, - USHORT = T_USHORT, - UINT = T_UINT, - ULONG = T_ULONG, - LONGLONG = T_LONGLONG, - ULONGLONG = T_ULONGLONG, - PYSSIZET = T_PYSSIZET - } type; - - int offset; - bool readonly; - - BoxedMemberDescriptor(MemberType type, int offset, bool readonly = true) - : type(type), offset(offset), readonly(readonly) {} - BoxedMemberDescriptor(PyMemberDef* member) - : type((MemberType)member->type), offset(member->offset), readonly(member->flags & READONLY) {} - - DEFAULT_CLASS_SIMPLE(member_descriptor_cls, false); -}; - -class BoxedGetsetDescriptor : public Box { -public: - Box* (*get)(Box*, void*); - union { - void* set; - void (*set_pyston)(Box*, Box*, void*); - int (*set_capi)(Box*, Box*, void*); - }; - void* closure; - BoxedString* name; - - BoxedGetsetDescriptor(BoxedString* name, Box* (*get)(Box*, void*), void (*set)(Box*, Box*, void*), void* closure) - : get(get), set_pyston(set), closure(closure), name(name) { - assert(this->cls == pyston_getset_cls); - Py_INCREF(name); - } - - BoxedGetsetDescriptor(BoxedString* name, Box* (*get)(Box*, void*), int (*set)(Box*, Box*, void*), void* closure) - : get(get), set_capi(set), closure(closure), name(name) { - assert(this->cls == capi_getset_cls); - Py_INCREF(name); - } - - static void dealloc(Box* b) noexcept; - - // No DEFAULT_CLASS annotation here -- force callers to explicitly specifiy pyston_getset_cls or capi_getset_cls -}; - class BoxedProperty : public Box { public: Box* prop_get; @@ -1338,59 +1274,6 @@ class BoxedGenerator : public Box { DEFAULT_CLASS(generator_cls); }; -struct wrapper_def { - const llvm::StringRef name; - 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 - const llvm::StringRef doc; - int flags; - BoxedString* name_strobj; -}; - -class BoxedWrapperDescriptor : public Box { -public: - const wrapper_def* wrapper; - BoxedClass* type; - void* wrapped; - BoxedWrapperDescriptor(const wrapper_def* wrapper, BoxedClass* type, void* wrapped) - : wrapper(wrapper), type(type), wrapped(wrapped) { - Py_INCREF(type); - } - - static void dealloc(Box* b) noexcept; - static int traverse(Box* _self, visitproc visit, void* arg) noexcept; - - DEFAULT_CLASS(wrapperdescr_cls); - - static Box* descr_get(Box* self, Box* inst, Box* owner) noexcept; - static Box* __call__(BoxedWrapperDescriptor* descr, PyObject* self, BoxedTuple* args, Box** _args); - template - static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, - Box** args, const std::vector* keyword_names) noexcept(S == CAPI); -}; - -class BoxedWrapperObject : public Box { -public: - BoxedWrapperDescriptor* descr; - Box* obj; - - BoxedWrapperObject(BoxedWrapperDescriptor* descr, Box* obj) : descr(descr), obj(obj) { - Py_INCREF(descr); - Py_INCREF(obj); - } - - DEFAULT_CLASS(wrapperobject_cls); - - static Box* __call__(BoxedWrapperObject* self, Box* args, Box* kwds); - template - static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, - Box** args, const std::vector* keyword_names) noexcept(S == CAPI); - - static void dealloc(Box* self) noexcept; - static int traverse(Box* self, visitproc visit, void* arg) noexcept; -}; - class BoxedMethodDescriptor : public Box { public: PyMethodDef* method; diff --git a/test/tests/wrapperdesc.py b/test/tests/wrapperdesc.py index 7f2222dad..3774c876b 100644 --- a/test/tests/wrapperdesc.py +++ b/test/tests/wrapperdesc.py @@ -8,3 +8,4 @@ class C(object): print(None.__str__.__name__) print type(type(None).__str__.__get__(None, type(None))) print u"".__len__.__call__() +print type(u'').__dict__['__len__'].__call__(u'') From 75d0050833e8d3b79712039200caf862850ff1fe Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 01:51:38 +0000 Subject: [PATCH 05/11] Reenable our tpp_call rewriting for these types --- from_cpython/Objects/descrobject.c | 12 ++++++++++++ src/runtime/descr.cpp | 5 ----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/from_cpython/Objects/descrobject.c b/from_cpython/Objects/descrobject.c index 15d4d00ee..80a81de5a 100644 --- a/from_cpython/Objects/descrobject.c +++ b/from_cpython/Objects/descrobject.c @@ -314,6 +314,11 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, static PyObject * wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) { + // Pyston overrides this with an optimized version + assert(0 && "This shouldn't be getting hit any more"); + abort(); + +#if 0 Py_ssize_t argc; PyObject *self, *func, *result; @@ -353,6 +358,7 @@ wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) Py_DECREF(args); Py_DECREF(func); return result; +#endif } #if 0 @@ -1040,6 +1046,11 @@ static PyGetSetDef wrapper_getsets[] = { static PyObject * wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) { + // Pyston overrides this with an optimized version + assert(0 && "This shouldn't be getting hit any more"); + abort(); + +#if 0 wrapperfunc wrapper = wp->descr->d_base->wrapper; PyObject *self = wp->self; @@ -1071,6 +1082,7 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) assert(!wp->descr->d_base->flags); return (*wrapper)(self, args, wp->descr->d_wrapped); +#endif } static int diff --git a/src/runtime/descr.cpp b/src/runtime/descr.cpp index a325dce08..c7030842c 100644 --- a/src/runtime/descr.cpp +++ b/src/runtime/descr.cpp @@ -711,10 +711,6 @@ void setupDescr() { PyType_Ready(&PyGetSetDescr_Type); PyType_Ready(&PyMemberDescr_Type); - PyType_Ready(&wrappertype); - PyType_Ready(&PyWrapperDescr_Type); - -#if 0 wrappertype.tpp_call.capi_val = wrapperObjectTppCall; wrappertype.tpp_call.cxx_val = wrapperObjectTppCall; wrappertype.tp_call = proxyToTppCall; @@ -724,6 +720,5 @@ void setupDescr() { PyWrapperDescr_Type.tpp_call.cxx_val = wrapperDescrTppCall; PyWrapperDescr_Type.tp_call = proxyToTppCall; PyType_Ready(&PyWrapperDescr_Type); -#endif } } From 2f2c2f2054d1486c44eb9699cb370365d45a4c8e Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 20:19:02 +0000 Subject: [PATCH 06/11] Support Rewriter::addGCReference, now without leaks This is for adding a guard on a non-immortal object, since we need to be safe against that object getting deallocated and a different object is allocated in its spot. We had support for this already, but it leaked memory. The biggest was that we never freed our runtimeICs, so if those ended up getting any GC references in them, then we would leak memory. So I started freeing those, but then that exposed the issue that the ICInvalidators expect that their dependent ICs never get freed. So I added back a mapping from ICSlotInfo-> ICInvalidators that reference them. --- src/asm_writing/icinfo.cpp | 68 ++++++++++++++++++++++---------------- src/asm_writing/icinfo.h | 7 ++-- src/core/types.h | 4 +++ src/runtime/descr.cpp | 6 ++++ src/runtime/types.cpp | 12 +++++++ src/runtime/types.h | 2 +- 6 files changed, 67 insertions(+), 32 deletions(-) diff --git a/src/asm_writing/icinfo.cpp b/src/asm_writing/icinfo.cpp index 07390b71b..a28fc414c 100644 --- a/src/asm_writing/icinfo.cpp +++ b/src/asm_writing/icinfo.cpp @@ -35,18 +35,39 @@ using namespace pyston::assembler; #define MAX_RETRY_BACKOFF 1024 -// TODO not right place for this... int64_t ICInvalidator::version() { return cur_version; } +ICInvalidator::~ICInvalidator() { + for (ICSlotInfo* slot : dependents) { + slot->invalidators.erase(std::find(slot->invalidators.begin(), slot->invalidators.end(), this)); + } +} + void ICInvalidator::addDependent(ICSlotInfo* entry_info) { - dependents.insert(entry_info); + auto p = dependents.insert(entry_info); + bool was_inserted = p.second; + if (was_inserted) + entry_info->invalidators.push_back(this); } void ICInvalidator::invalidateAll() { cur_version++; for (ICSlotInfo* slot : dependents) { + bool found_self = false; + for (auto invalidator : slot->invalidators) { + if (invalidator == this) { + assert(!found_self); + found_self = true; + } else { + assert(invalidator->dependents.count(slot)); + invalidator->dependents.erase(slot); + } + } + assert(found_self); + + slot->invalidators.clear(); slot->clear(); } dependents.clear(); @@ -98,6 +119,8 @@ void ICSlotRewrite::commit(CommitHook* hook, std::vector gc_references, if (!still_valid) { if (VERBOSITY() >= 3) printf("not committing %s icentry since a dependency got updated before commit\n", debug_name); + for (auto p : gc_references) + Py_DECREF(p); return; } @@ -106,8 +129,11 @@ void ICSlotRewrite::commit(CommitHook* hook, std::vector gc_references, bool do_commit = hook->finishAssembly(continue_point - slot_start); - if (!do_commit) + if (!do_commit) { + for (auto p : gc_references) + Py_DECREF(p); return; + } assert(!assembler.hasFailed()); @@ -204,25 +230,8 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) { return NULL; } -// Keep track of all ICInfo(s) that we create because they contain pointers to Pyston heap objects -// that we have written into the generated code and we may need to scan those. -static llvm::DenseSet ics_list; static llvm::DenseMap ics_by_return_addr; -void registerGCTrackedICInfo(ICInfo* ic) { -#if MOVING_GC - assert(ics_list.count(ic) == 0); - ics_list.insert(ic); -#endif -} - -void deregisterGCTrackedICInfo(ICInfo* ic) { -#if MOVING_GC - assert(ics_list.count(ic) == 1); - ics_list.erase(ic); -#endif -} - ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots, int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs, assembler::GenericRegister return_register, TypeRecorder* type_recorder, @@ -248,16 +257,15 @@ ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, S } if (slowpath_rtn_addr && !this->ic_global_decref_locations.empty()) slowpath_decref_info = DecrefInfo((uint64_t)slowpath_rtn_addr, this->ic_global_decref_locations); - -#if MOVING_GC - assert(ics_list.count(this) == 0); -#endif } ICInfo::~ICInfo() { -#if MOVING_GC - assert(ics_list.count(this) == 0); -#endif + for (auto& slot : slots) { + for (auto invalidator : slot.invalidators) { + assert(invalidator->dependents.count(&slot)); + invalidator->dependents.erase(&slot); + } + } } DecrefInfo::DecrefInfo(uint64_t ip, std::vector locations) : ip(ip) { @@ -323,7 +331,9 @@ std::unique_ptr registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* } void deregisterCompiledPatchpoint(ICInfo* ic) { - assert(ics_by_return_addr.count(ic->slowpath_rtn_addr)); + ic->clearAll(); + + assert(ics_by_return_addr[ic->slowpath_rtn_addr] == ic); ics_by_return_addr.erase(ic->slowpath_rtn_addr); deregisterGCTrackedICInfo(ic); @@ -403,7 +413,7 @@ void ICInfo::appendDecrefInfosTo(std::vector& dest_decref_infos) { } void clearAllICs() { - for (auto&& p : ics_by_ast_node) { + for (auto&& p : ics_by_return_addr) { p.second->clearAll(); } } diff --git a/src/asm_writing/icinfo.h b/src/asm_writing/icinfo.h index 21d23fc16..99e35d9f7 100644 --- a/src/asm_writing/icinfo.h +++ b/src/asm_writing/icinfo.h @@ -63,6 +63,7 @@ struct ICSlotInfo { std::vector gc_references; std::vector decref_infos; + std::vector invalidators; // ICInvalidators that reference this slotinfo void clear(); }; @@ -183,8 +184,10 @@ class ICInfo { void appendDecrefInfosTo(std::vector& dest_decref_infos); }; -void registerGCTrackedICInfo(ICInfo* ic); -void deregisterGCTrackedICInfo(ICInfo* ic); +inline void registerGCTrackedICInfo(ICInfo* ic) { +} +inline void deregisterGCTrackedICInfo(ICInfo* ic) { +} class ICSetupInfo; struct CompiledFunction; diff --git a/src/core/types.h b/src/core/types.h index e6d613c05..d21275574 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -289,10 +289,14 @@ class ICInvalidator { public: ICInvalidator() : cur_version(0) {} + ~ICInvalidator(); void addDependent(ICSlotInfo* icentry); int64_t version(); void invalidateAll(); + + friend class ICInfo; + friend class ICSlotInfo; }; // Codegen types: diff --git a/src/runtime/descr.cpp b/src/runtime/descr.cpp index c7030842c..ccd7eb34a 100644 --- a/src/runtime/descr.cpp +++ b/src/runtime/descr.cpp @@ -527,6 +527,12 @@ Box* wrapperDescrTppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec } } + if (rewrite_args) { + // We are going to embed references to _self->d_base->wrapper and _self->d_wrapped + rewrite_args->obj->addGuard((intptr_t)_self); + rewrite_args->rewriter->addGCReference(_self); + } + STAT_TIMER(t0, "us_timer_boxedwrapperdecsriptor_call", (_self->cls->is_user_defined ? 10 : 20)); assert(_self->cls == &PyWrapperDescr_Type); diff --git a/src/runtime/types.cpp b/src/runtime/types.cpp index d83da3110..81c6bba2e 100644 --- a/src/runtime/types.cpp +++ b/src/runtime/types.cpp @@ -3761,6 +3761,12 @@ void BoxedClass::dealloc(Box* b) noexcept { if (PyObject_IS_GC(type)) _PyObject_GC_UNTRACK(type); + type->next_ic.reset(); + type->hasnext_ic.reset(); + type->repr_ic.reset(); + type->iter_ic.reset(); + type->nonzero_ic.reset(); + // We can for the most part avoid this, but I think it's best not to: PyObject_ClearWeakRefs((PyObject*)type); @@ -4616,6 +4622,9 @@ extern "C" void Py_Finalize() noexcept { Py_DECREF(b); } constants.clear(); + + clearAllICs(); + for (auto b : late_constants) { Py_DECREF(b); } @@ -4628,6 +4637,9 @@ extern "C" void Py_Finalize() noexcept { } Py_DECREF(b); } + + clearAllICs(); + // May need to run multiple collections to collect everything: while (PyGC_Collect()) ; diff --git a/src/runtime/types.h b/src/runtime/types.h index 0a52dad6f..8f937a3b7 100644 --- a/src/runtime/types.h +++ b/src/runtime/types.h @@ -183,7 +183,7 @@ class BoxedClass : public BoxVar { HCAttrs attrs; - // TODO: these don't actually get deallocated right now + // Any new ics here need to get reflected in BoxedClass::dealloc std::unique_ptr next_ic; std::unique_ptr hasnext_ic, repr_ic, iter_ic; std::unique_ptr nonzero_ic; From 0751c27f1eebd8866f95312b7e9373f3c4fc1714 Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 05:36:57 +0000 Subject: [PATCH 07/11] Use CPython's PyMethodDescr_Type --- Makefile | 2 +- from_cpython/Include/descrobject.h | 4 +- from_cpython/Objects/descrobject.c | 19 +----- src/capi/typeobject.cpp | 7 +-- src/capi/typeobject.h | 2 + src/runtime/capi.cpp | 16 ++--- src/runtime/descr.cpp | 94 ++---------------------------- src/runtime/float.cpp | 7 +-- src/runtime/objmodel.cpp | 13 +++-- src/runtime/set.cpp | 20 +++---- src/runtime/types.cpp | 10 +--- src/runtime/types.h | 25 +------- 12 files changed, 45 insertions(+), 174 deletions(-) diff --git a/Makefile b/Makefile index 346deae4b..69d729c26 100644 --- a/Makefile +++ b/Makefile @@ -856,7 +856,7 @@ nosearch_check_%: %.py pyston_dbg check-deps $(call make_search,check_%) nosearch_dbgpy_% nosearch_pydbg_%: %.py ext_pythondbg - export PYTHON_VERSION=$$(python2.7-dbg -V 2>&1 | awk '{print $$2}'); PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7-pydebug $(GDB) --ex "dir $(DEPS_DIR)/python-src/python2.7-$$PYTHON_VERSION/debian" $(GDB_CMDS) --args python2.7-dbg $< + export PYTHON_VERSION=$$(python2.7-dbg -V 2>&1 | awk '{print $$2}'); PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7-pydebug $(GDB) --ex "dir $(DEPS_DIR)/python-src/python2.7-$$PYTHON_VERSION/debian" $(GDB_CMDS) --args python2.7-dbg $(ARGS) $< $(call make_search,dbgpy_%) $(call make_search,pydbg_%) diff --git a/from_cpython/Include/descrobject.h b/from_cpython/Include/descrobject.h index 929cf4786..04b5b09f0 100644 --- a/from_cpython/Include/descrobject.h +++ b/from_cpython/Include/descrobject.h @@ -56,12 +56,10 @@ typedef struct { PyDescr_COMMON; } PyDescrObject; -#if 0 typedef struct { PyDescr_COMMON; PyMethodDef *d_method; } PyMethodDescrObject; -#endif typedef struct { PyDescr_COMMON; @@ -107,6 +105,8 @@ typedef struct { PyObject *self; } wrapperobject; PyAPI_DATA(PyTypeObject) wrappertype; +PyAPI_DATA(PyTypeObject) PyMethodDescr_Type; +PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type; #ifdef __cplusplus } diff --git a/from_cpython/Objects/descrobject.c b/from_cpython/Objects/descrobject.c index 80a81de5a..82f89ad8a 100644 --- a/from_cpython/Objects/descrobject.c +++ b/from_cpython/Objects/descrobject.c @@ -30,14 +30,12 @@ descr_repr(PyDescrObject *descr, char *format) descr->d_type->tp_name); } -#if 0 static PyObject * method_repr(PyMethodDescrObject *descr) { return descr_repr((PyDescrObject *)descr, ""); } -#endif static PyObject * member_repr(PyMemberDescrObject *descr) @@ -81,8 +79,6 @@ descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres) return 0; } -// Pyston change: not using this for now -#if 0 static PyObject * classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) { @@ -130,7 +126,6 @@ method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) return res; return PyCFunction_New(descr->d_method, obj); } -#endif static PyObject * member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) @@ -213,7 +208,6 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) return -1; } -#if 0 static PyObject * methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) { @@ -309,7 +303,6 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, Py_DECREF(args); return result; } -#endif static PyObject * wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) @@ -361,7 +354,6 @@ wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) #endif } -#if 0 static PyObject * method_get_doc(PyMethodDescrObject *descr, void *closure) { @@ -371,7 +363,6 @@ method_get_doc(PyMethodDescrObject *descr, void *closure) } return PyString_FromString(descr->d_method->ml_doc); } -#endif static PyMemberDef descr_members[] = { {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, @@ -379,12 +370,10 @@ static PyMemberDef descr_members[] = { {0} }; -#if 0 static PyGetSetDef method_getset[] = { {"__doc__", (getter)method_get_doc}, {0} }; -#endif static PyObject * member_get_doc(PyMemberDescrObject *descr, void *closure) @@ -439,8 +428,7 @@ descr_traverse(PyObject *self, visitproc visit, void *arg) return 0; } -#if 0 -static PyTypeObject PyMethodDescr_Type = { +/* static */ PyTypeObject PyMethodDescr_Type = { PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "method_descriptor", sizeof(PyMethodDescrObject), @@ -478,7 +466,7 @@ static PyTypeObject PyMethodDescr_Type = { }; /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */ -static PyTypeObject PyClassMethodDescr_Type = { +/* static */ PyTypeObject PyClassMethodDescr_Type = { PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) "classmethod_descriptor", sizeof(PyMethodDescrObject), @@ -514,7 +502,6 @@ static PyTypeObject PyClassMethodDescr_Type = { (descrgetfunc)classmethod_get, /* tp_descr_get */ 0, /* tp_descr_set */ }; -#endif PyTypeObject PyMemberDescr_Type = { PyVarObject_HEAD_INIT(/* Pyston change */NULL, 0) @@ -645,7 +632,6 @@ descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) return descr; } -#if 0 PyObject * PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) { @@ -669,7 +655,6 @@ PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) descr->d_method = method; return (PyObject *)descr; } -#endif PyObject * PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) diff --git a/src/capi/typeobject.cpp b/src/capi/typeobject.cpp index 76ebf7484..665c2d0f1 100644 --- a/src/capi/typeobject.cpp +++ b/src/capi/typeobject.cpp @@ -2734,7 +2734,7 @@ extern "C" int PyType_IsSubtype(PyTypeObject* a, PyTypeObject* b) noexcept { /* Initialize the __dict__ in a type object */ -static int add_methods(PyTypeObject* type, PyMethodDef* meth) noexcept { +/* static */ int add_methods(PyTypeObject* type, PyMethodDef* meth) noexcept { for (; meth->ml_name != NULL; meth++) { auto name = internStringMortal(meth->ml_name); PyObject* descr; @@ -2746,10 +2746,7 @@ static int add_methods(PyTypeObject* type, PyMethodDef* meth) noexcept { PyErr_SetString(PyExc_ValueError, "method cannot be both class and static"); return -1; } - // Pyston change: create these classmethods as normal methods, which will - // later just notice the METH_CLASS flag. - // descr = PyDescr_NewClassMethod(type, meth); - descr = PyDescr_NewMethod(type, meth); + descr = PyDescr_NewClassMethod(type, meth); } else if (meth->ml_flags & METH_STATIC) { PyObject* cfunc = PyCFunction_New(meth, NULL); if (cfunc == NULL) diff --git a/src/capi/typeobject.h b/src/capi/typeobject.h index 1a75f26ab..86eb4f51c 100644 --- a/src/capi/typeobject.h +++ b/src/capi/typeobject.h @@ -62,6 +62,8 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* attr, GetattrRewriteArgs* // Set a class's tp_call to this to have calls to tp_call (and __call__) proxy to tpp_call Box* proxyToTppCall(Box* self, Box* args, Box* kw) noexcept; + +int add_methods(PyTypeObject* type, PyMethodDef* meth) noexcept; } #endif diff --git a/src/runtime/capi.cpp b/src/runtime/capi.cpp index 40dedf7f0..e8b8a296a 100644 --- a/src/runtime/capi.cpp +++ b/src/runtime/capi.cpp @@ -47,8 +47,6 @@ namespace pyston { -BoxedClass* method_cls; - extern "C" int _PyIndex_Check(PyObject* obj) noexcept { return (Py_TYPE(obj)->tp_as_number != NULL && PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HAVE_INDEX) && Py_TYPE(obj)->tp_as_number->nb_index != NULL); @@ -1565,8 +1563,6 @@ extern "C" PyObject* Py_FindMethod(PyMethodDef* methods, PyObject* self, const c } extern "C" PyObject* PyCFunction_NewEx(PyMethodDef* ml, PyObject* self, PyObject* module) noexcept { - assert((ml->ml_flags & (~(METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O))) == 0); - return new BoxedCApiFunction(ml, self, module); } @@ -1725,6 +1721,8 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa int flags = self->method_def->ml_flags; auto func = self->method_def->ml_meth; + flags &= ~(METH_CLASS | METH_STATIC | METH_COEXIST); + ParamReceiveSpec paramspec(0, 0, true, false); Box** defaults = NULL; if (flags == METH_VARARGS) { @@ -1820,7 +1818,7 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa rewrite_args->arg1)->setType(RefType::OWNED); } else if ((flags & ~(METH_O3 | METH_D3)) == 0) { assert(paramspec.totalReceived() <= 3); // would need to pass through oargs - rtn = ((Box * (*)(Box*, Box*, Box*, Box*))func)(self->passthrough, arg1, arg2, arg3); + rtn = ((Box * (*)(Box*, Box*, Box*, Box**))func)(self->passthrough, arg1, arg2, &arg3); if (rewrite_args) { if (paramspec.totalReceived() == 1) rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, @@ -1829,11 +1827,13 @@ Box* BoxedCApiFunction::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPa rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1, rewrite_args->arg2)->setType(RefType::OWNED); - else if (paramspec.totalReceived() == 3) + else if (paramspec.totalReceived() == 3) { + auto args = rewrite_args->rewriter->allocate(1); + args->setAttr(0, rewrite_args->arg3); rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)func, r_passthrough, rewrite_args->arg1, - rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED); - else + rewrite_args->arg2, args)->setType(RefType::OWNED); + } else abort(); } } else if (flags == METH_OLDARGS) { diff --git a/src/runtime/descr.cpp b/src/runtime/descr.cpp index ccd7eb34a..ea7852929 100644 --- a/src/runtime/descr.cpp +++ b/src/runtime/descr.cpp @@ -226,13 +226,7 @@ static Box* classmethodGet(Box* self, Box* obj, Box* type) { return new BoxedInstanceMethod(type, cm->cm_callable, type); } -// TODO this should be auto-generated as a slot wrapper: -Box* BoxedMethodDescriptor::__call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args) { - BoxedDict* kwargs = static_cast(_args[0]); - return BoxedMethodDescriptor::tppCall(self, NULL, ArgPassSpec(1, 0, true, true), obj, varargs, kwargs, NULL, - NULL); -} - +#if 0 template Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, @@ -393,62 +387,7 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A return rearrangeArgumentsAndCall(paramspec, NULL, self->method->ml_name, defaults, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names, continuation); } - -static Box* methodGetName(Box* b, void*) { - assert(b->cls == method_cls); - const char* s = static_cast(b)->method->ml_name; - if (s) - return boxString(s); - return incref(None); -} -static Box* methodGetDoc(Box* b, void*) { - assert(b->cls == method_cls); - const char* s = static_cast(b)->method->ml_doc; - if (s) - return boxString(s); - return incref(None); -} - -static Box* methodRepr(Box* _o) { - assert(_o->cls == method_cls); - BoxedMethodDescriptor* md = static_cast(_o); - const char* name = md->method->ml_name; - if (!name) - name = "?"; - return PyString_FromFormat("", name, getNameOfClass(md->type)); -} - -Box* BoxedMethodDescriptor::descr_get(BoxedMethodDescriptor* self, Box* inst, Box* owner) noexcept { - RELEASE_ASSERT(self->cls == method_cls, ""); - - // CPython handles this differently: they create the equivalent of different BoxedMethodDescriptor - // objects but with different class objects, which define different __get__ and __call__ methods. - if (self->method->ml_flags & METH_CLASS) - return boxInstanceMethod(owner, self, self->type); - - if (self->method->ml_flags & METH_STATIC) - Py_FatalError("unimplemented"); - - if (inst == NULL) - return incref(self); - else - return boxInstanceMethod(inst, self, self->type); -} - -void BoxedMethodDescriptor::dealloc(Box* _self) noexcept { - BoxedMethodDescriptor* self = static_cast(_self); - - PyObject_GC_UnTrack(self); - Py_XDECREF(self->type); - self->cls->tp_free(self); -} - -int BoxedMethodDescriptor::traverse(Box* _self, visitproc visit, void* arg) noexcept { - BoxedMethodDescriptor* self = static_cast(_self); - - Py_VISIT(self->type); - return 0; -} +#endif void BoxedProperty::dealloc(Box* _self) noexcept { BoxedProperty* self = static_cast(_self); @@ -652,20 +591,6 @@ extern "C" PyObject* PyStaticMethod_New(PyObject* callable) noexcept { return new BoxedStaticmethod(callable); } -extern "C" PyObject* PyDescr_NewClassMethod(PyTypeObject* type, PyMethodDef* method) noexcept { - // Pyston change: we don't have a separate capi classmethod descriptor type, we just use the normal - // one but with the METH_CLASS flag set. - if (!(method->ml_flags & METH_CLASS)) { - method = new PyMethodDef(*method); - method->ml_flags |= METH_CLASS; - } - return new pyston::BoxedMethodDescriptor(method, type); -} - -extern "C" PyObject* PyDescr_NewMethod(PyTypeObject* type, PyMethodDef* method) noexcept { - return new BoxedMethodDescriptor(method, type); -} - void setupDescr() { property_cls->instances_are_nonzero = true; @@ -702,18 +627,6 @@ void setupDescr() { new BoxedFunction(FunctionMetadata::create((void*)classmethodGet, UNKNOWN, 3, false, false), { None })); classmethod_cls->freeze(); - method_cls->giveAttr("__get__", new BoxedFunction(FunctionMetadata::create((void*)BoxedMethodDescriptor::descr_get, - UNKNOWN, 3, ParamNames::empty(), CAPI))); - FunctionMetadata* method_call_cl - = FunctionMetadata::create((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, true, true); - method_cls->giveAttr("__call__", new BoxedFunction(method_call_cl)); - method_cls->tpp_call.capi_val = BoxedMethodDescriptor::tppCall; - method_cls->tpp_call.cxx_val = BoxedMethodDescriptor::tppCall; - method_cls->giveAttrDescriptor("__doc__", methodGetDoc, NULL); - method_cls->giveAttrDescriptor("__name__", methodGetName, NULL); - method_cls->giveAttr("__repr__", new BoxedFunction(FunctionMetadata::create((void*)methodRepr, UNKNOWN, 1))); - method_cls->freeze(); - PyType_Ready(&PyGetSetDescr_Type); PyType_Ready(&PyMemberDescr_Type); @@ -726,5 +639,8 @@ void setupDescr() { PyWrapperDescr_Type.tpp_call.cxx_val = wrapperDescrTppCall; PyWrapperDescr_Type.tp_call = proxyToTppCall; PyType_Ready(&PyWrapperDescr_Type); + + PyType_Ready(&PyMethodDescr_Type); + PyType_Ready(&PyClassMethodDescr_Type); } } diff --git a/src/runtime/float.cpp b/src/runtime/float.cpp index 0e18b0936..8515afa0f 100644 --- a/src/runtime/float.cpp +++ b/src/runtime/float.cpp @@ -1672,7 +1672,8 @@ static PyMethodDef float_methods[] { "as_integer_ratio", (PyCFunction)float_as_integer_ratio, METH_NOARGS, NULL }, { "__setformat__", (PyCFunction)float_setformat, METH_VARARGS | METH_CLASS, float_setformat_doc }, { "is_integer", (PyCFunction)float_is_integer, METH_NOARGS, NULL }, - { "__format__", (PyCFunction)float__format__, METH_VARARGS, NULL } }; + { "__format__", (PyCFunction)float__format__, METH_VARARGS, NULL }, + { NULL, NULL, 0, NULL } }; void setupFloat() { static PyNumberMethods float_as_number; @@ -1746,9 +1747,7 @@ void setupFloat() { new BoxedBuiltinFunctionOrMethod(FunctionMetadata::create((void*)floatGetFormat, STR, 1), "__getformat__", floatGetFormatDoc)); - for (auto& md : float_methods) { - float_cls->giveAttr(md.ml_name, PyDescr_NewMethod(float_cls, &md)); - } + add_methods(float_cls, float_methods); add_operators(float_cls); float_cls->freeze(); diff --git a/src/runtime/objmodel.cpp b/src/runtime/objmodel.cpp index 3920b92de..4798d9a13 100644 --- a/src/runtime/objmodel.cpp +++ b/src/runtime/objmodel.cpp @@ -1817,8 +1817,11 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box // Special case: non-data descriptor: function, instancemethod or classmethod // Returns a bound instancemethod if (descr->cls == function_cls || descr->cls == instancemethod_cls || descr->cls == classmethod_cls - || (descr->cls == method_cls - && (static_cast(descr)->method->ml_flags & (METH_CLASS | METH_STATIC)) == 0)) { + || descr->cls == &PyMethodDescr_Type) { + + if (descr->cls == &PyMethodDescr_Type) + assert((reinterpret_cast(descr)->d_method->ml_flags & (METH_CLASS | METH_STATIC)) + == 0); Box* im_self = NULL, * im_func = NULL, * im_class = obj->cls; RewriterVar* r_im_self = NULL, * r_im_func = NULL, * r_im_class = NULL; @@ -1833,7 +1836,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box r_im_self = rewrite_args->obj; r_im_func = r_descr; } - } else if (descr->cls == method_cls) { + } else if (descr->cls == &PyMethodDescr_Type) { im_self = obj; im_func = descr; if (rewrite_args) { @@ -3369,8 +3372,8 @@ extern "C" bool nonzero(Box* obj) { || obj->cls == type_cls || isSubclass(obj->cls, Exception) || obj->cls == &PyFile_Type || obj->cls == &PyTraceBack_Type || obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == capifunc_cls || obj->cls == builtin_function_or_method_cls - || obj->cls == method_cls || obj->cls == &PyMethod_Type || obj->cls == frame_cls - || obj->cls == generator_cls || obj->cls == code_cls, + || obj->cls == &PyMethod_Type || obj->cls == frame_cls || obj->cls == generator_cls + || obj->cls == code_cls, "%s.__nonzero__", getTypeName(obj)); // TODO if (rewriter.get()) { diff --git a/src/runtime/set.cpp b/src/runtime/set.cpp index 29b75efcf..ac01fef74 100644 --- a/src/runtime/set.cpp +++ b/src/runtime/set.cpp @@ -14,6 +14,7 @@ #include "runtime/set.h" +#include "capi/typeobject.h" #include "runtime/objmodel.h" namespace pyston { @@ -919,12 +920,10 @@ int BoxedSet::clear(Box* _o) noexcept { return 0; } -static PyMethodDef set_methods[] = { - { "__reduce__", (PyCFunction)set_reduce, METH_NOARGS, NULL }, -}; -static PyMethodDef frozenset_methods[] = { - { "__reduce__", (PyCFunction)set_reduce, METH_NOARGS, NULL }, -}; +static PyMethodDef set_methods[] + = { { "__reduce__", (PyCFunction)set_reduce, METH_NOARGS, NULL }, { NULL, NULL, 0, NULL } }; +static PyMethodDef frozenset_methods[] + = { { "__reduce__", (PyCFunction)set_reduce, METH_NOARGS, NULL }, { NULL, NULL, 0, NULL } }; void setupSet() { static PySequenceMethods set_as_sequence; @@ -1070,13 +1069,8 @@ void setupSet() { frozenset_cls->giveAttr("copy", new BoxedFunction(FunctionMetadata::create((void*)frozensetCopy, UNKNOWN, 1))); set_cls->giveAttr("pop", new BoxedFunction(FunctionMetadata::create((void*)setPop, UNKNOWN, 1))); - for (auto& md : set_methods) { - set_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, set_cls)); - } - - for (auto& md : frozenset_methods) { - frozenset_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, frozenset_cls)); - } + add_methods(set_cls, set_methods); + add_methods(frozenset_cls, frozenset_methods); set_cls->freeze(); frozenset_cls->freeze(); diff --git a/src/runtime/types.cpp b/src/runtime/types.cpp index 81c6bba2e..0baa8e3b8 100644 --- a/src/runtime/types.cpp +++ b/src/runtime/types.cpp @@ -3375,6 +3375,7 @@ static PyMethodDef object_methods[] = { { "__reduce_ex__", object_reduce_ex, METH_VARARGS, NULL }, // { "__reduce__", object_reduce, METH_VARARGS, NULL }, // { "__format__", object_format, METH_VARARGS, PyDoc_STR("default object formatter") }, + { NULL, NULL, 0, NULL }, }; static Box* type_name(Box* b, void*) noexcept { @@ -4123,9 +4124,6 @@ void setupRuntime() { capifunc_cls = new (0) BoxedClass(object_cls, 0, 0, sizeof(BoxedCApiFunction), false, "capifunc", true, BoxedCApiFunction::dealloc, NULL, true, BoxedCApiFunction::traverse, BoxedCApiFunction::clear); - method_cls = new (0) - BoxedClass(object_cls, 0, 0, sizeof(BoxedMethodDescriptor), false, "method_descriptor", false, - BoxedMethodDescriptor::dealloc, NULL, true, BoxedMethodDescriptor::traverse, NOCLEAR); EmptyString = new (0) BoxedString(""); constants.push_back(EmptyString); @@ -4157,7 +4155,6 @@ void setupRuntime() { builtin_function_or_method_cls->tp_mro = BoxedTuple::create({ builtin_function_or_method_cls, object_cls }); capifunc_cls->tp_mro = BoxedTuple::create({ capifunc_cls, object_cls }); module_cls->tp_mro = BoxedTuple::create({ module_cls, object_cls }); - method_cls->tp_mro = BoxedTuple::create({ method_cls, object_cls }); object_cls->tp_hash = (hashfunc)_Py_HashPointer; @@ -4212,7 +4209,6 @@ void setupRuntime() { builtin_function_or_method_cls->finishInitialization(); module_cls->finishInitialization(); capifunc_cls->finishInitialization(); - method_cls->finishInitialization(); str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; @@ -4311,9 +4307,7 @@ void setupRuntime() { setupCAPI(); // Can't set up object methods until we set up CAPI support: - for (auto& md : object_methods) { - object_cls->giveAttr(md.ml_name, new BoxedMethodDescriptor(&md, object_cls)); - } + add_methods(object_cls, object_methods); object_cls->giveAttrDescriptor("__class__", object_get_class, object_set_class); object_cls->tp_str = object_str; diff --git a/src/runtime/types.h b/src/runtime/types.h index 8f937a3b7..4f5dd5385 100644 --- a/src/runtime/types.h +++ b/src/runtime/types.h @@ -77,9 +77,9 @@ extern "C" BoxedString* EmptyString; extern "C" { extern BoxedClass* object_cls, *type_cls, *bool_cls, *int_cls, *long_cls, *float_cls, *str_cls, *function_cls, *none_cls, *instancemethod_cls, *list_cls, *slice_cls, *module_cls, *dict_cls, *tuple_cls, *enumerate_cls, - *xrange_cls, *method_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *property_cls, - *staticmethod_cls, *classmethod_cls, *attrwrapper_cls, *builtin_function_or_method_cls, *set_cls, *frozenset_cls, - *code_cls, *frame_cls, *capifunc_cls; + *xrange_cls, *closure_cls, *generator_cls, *complex_cls, *basestring_cls, *property_cls, *staticmethod_cls, + *classmethod_cls, *attrwrapper_cls, *builtin_function_or_method_cls, *set_cls, *frozenset_cls, *code_cls, + *frame_cls, *capifunc_cls; } #define unicode_cls (&PyUnicode_Type) #define memoryview_cls (&PyMemoryView_Type) @@ -1274,25 +1274,6 @@ class BoxedGenerator : public Box { DEFAULT_CLASS(generator_cls); }; -class BoxedMethodDescriptor : public Box { -public: - PyMethodDef* method; - BoxedClass* type; - - BoxedMethodDescriptor(PyMethodDef* method, BoxedClass* type) : method(method), type(type) { Py_INCREF(type); } - - DEFAULT_CLASS(method_cls); - - static Box* descr_get(BoxedMethodDescriptor* self, Box* inst, Box* owner) noexcept; - static Box* __call__(BoxedMethodDescriptor* self, Box* obj, BoxedTuple* varargs, Box** _args); - template - static Box* tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, - Box** args, const std::vector* keyword_names) noexcept(S == CAPI); - - static void dealloc(Box* self) noexcept; - static int traverse(Box* self, visitproc visit, void* arg) noexcept; -}; - Box* objectSetattr(Box* obj, Box* attr, Box* value); BORROWED(Box*) unwrapAttrWrapper(Box* b); From 7f84725f600276da2adbd5c2d5f70c5e1115127b Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 05:54:06 +0000 Subject: [PATCH 08/11] Reenable rewriting for method-descriptors --- from_cpython/Objects/descrobject.c | 6 +++ src/runtime/descr.cpp | 63 ++++++++++++++++-------------- test/tests/methoddescr.py | 2 + 3 files changed, 42 insertions(+), 29 deletions(-) create mode 100644 test/tests/methoddescr.py diff --git a/from_cpython/Objects/descrobject.c b/from_cpython/Objects/descrobject.c index 82f89ad8a..c2277e076 100644 --- a/from_cpython/Objects/descrobject.c +++ b/from_cpython/Objects/descrobject.c @@ -211,6 +211,11 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) static PyObject * methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) { + // Pyston overrides this with an optimized version + assert(0 && "This shouldn't be getting hit any more"); + abort(); + +#if 0 Py_ssize_t argc; PyObject *self, *func, *result; @@ -250,6 +255,7 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) Py_DECREF(args); Py_DECREF(func); return result; +#endif } static PyObject * diff --git a/src/runtime/descr.cpp b/src/runtime/descr.cpp index ea7852929..ea1cb414a 100644 --- a/src/runtime/descr.cpp +++ b/src/runtime/descr.cpp @@ -226,14 +226,12 @@ static Box* classmethodGet(Box* self, Box* obj, Box* type) { return new BoxedInstanceMethod(type, cm->cm_callable, type); } -#if 0 template -Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, - Box* arg2, Box* arg3, Box** args, - const std::vector* keyword_names) noexcept(S == CAPI) { +Box* methodDescrTppCall(Box* _self, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, + Box** args, const std::vector* keyword_names) noexcept(S == CAPI) { if (S == CAPI) { try { - return tppCall(_self, NULL, argspec, arg1, arg2, arg3, args, keyword_names); + return methodDescrTppCall(_self, NULL, argspec, arg1, arg2, arg3, args, keyword_names); } catch (ExcInfo e) { setCAPIException(e); return NULL; @@ -242,14 +240,16 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A STAT_TIMER(t0, "us_timer_boxedmethoddescriptor__call__", 10); - assert(_self->cls == method_cls); - BoxedMethodDescriptor* self = static_cast(_self); + assert(_self->cls == &PyMethodDescr_Type || _self->cls == &PyClassMethodDescr_Type); + PyMethodDescrObject* self = reinterpret_cast(_self); - int ml_flags = self->method->ml_flags; + bool is_classmethod = (_self->cls == &PyClassMethodDescr_Type); + + int ml_flags = self->d_method->ml_flags; int call_flags = ml_flags & ~(METH_CLASS | METH_COEXIST | METH_STATIC); if (rewrite_args && !rewrite_args->func_guarded) { - rewrite_args->obj->addAttrGuard(offsetof(BoxedMethodDescriptor, method), (intptr_t)self->method); + rewrite_args->obj->addAttrGuard(offsetof(PyMethodDescrObject, d_method), (intptr_t)self->d_method); } ParamReceiveSpec paramspec(0, 0, false, false); @@ -293,16 +293,15 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A } auto continuation = [=](CallRewriteArgs* rewrite_args, Box* arg1, Box* arg2, Box* arg3, Box** args) { - if (ml_flags & METH_CLASS) { + if (is_classmethod) { rewrite_args = NULL; if (!PyType_Check(arg1)) - raiseExcHelper(TypeError, "descriptor '%s' requires a type but received a '%s'", self->method->ml_name, - getFullTypeName(arg1).c_str()); + raiseExcHelper(TypeError, "descriptor '%s' requires a type but received a '%s'", + self->d_method->ml_name, getFullTypeName(arg1).c_str()); } else { - if (!isSubclass(arg1->cls, self->type)) + if (!isSubclass(arg1->cls, self->d_type)) raiseExcHelper(TypeError, "descriptor '%s' requires a '%s' arg1 but received a '%s'", - self->method->ml_name, getFullNameOfClass(self->type).c_str(), - getFullTypeName(arg1).c_str()); + self->d_method->ml_name, self->d_type->tp_name, getFullTypeName(arg1).c_str()); } if (rewrite_args && !arg1_class_guarded) { @@ -313,57 +312,57 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A if (call_flags == METH_NOARGS) { { UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins"); - rtn = (Box*)self->method->ml_meth(arg1, NULL); + rtn = (Box*)self->d_method->ml_meth(arg1, NULL); } if (rewrite_args) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->rewriter->loadConst(0, Location::forArg(1))) ->setType(RefType::OWNED); } else if (call_flags == METH_VARARGS) { { UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins"); - rtn = (Box*)self->method->ml_meth(arg1, arg2); + rtn = (Box*)self->d_method->ml_meth(arg1, arg2); } if (rewrite_args) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->arg2)->setType(RefType::OWNED); } else if (call_flags == (METH_VARARGS | METH_KEYWORDS)) { { UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins"); - rtn = (Box*)((PyCFunctionWithKeywords)self->method->ml_meth)(arg1, arg2, arg3); + rtn = (Box*)((PyCFunctionWithKeywords)self->d_method->ml_meth)(arg1, arg2, arg3); } if (rewrite_args) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED); } else if (call_flags == METH_O) { { UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins"); - rtn = (Box*)self->method->ml_meth(arg1, arg2); + rtn = (Box*)self->d_method->ml_meth(arg1, arg2); } if (rewrite_args) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->arg2)->setType(RefType::OWNED); } else if ((call_flags & ~(METH_O3 | METH_D3)) == 0) { { UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins"); - rtn = ((Box * (*)(Box*, Box*, Box*, Box**))self->method->ml_meth)(arg1, arg2, arg3, args); + rtn = ((Box * (*)(Box*, Box*, Box*, Box**))self->d_method->ml_meth)(arg1, arg2, arg3, args); } if (rewrite_args) { if (paramspec.totalReceived() == 2) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->arg2)->setType(RefType::OWNED); else if (paramspec.totalReceived() == 3) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->arg2, rewrite_args->arg3)->setType(RefType::OWNED); else if (paramspec.totalReceived() > 3) rewrite_args->out_rtn - = rewrite_args->rewriter->call(true, (void*)self->method->ml_meth, rewrite_args->arg1, + = rewrite_args->rewriter->call(true, (void*)self->d_method->ml_meth, rewrite_args->arg1, rewrite_args->arg2, rewrite_args->arg3, rewrite_args->args)->setType(RefType::OWNED); else @@ -384,10 +383,9 @@ Box* BoxedMethodDescriptor::tppCall(Box* _self, CallRewriteArgs* rewrite_args, A return rtn; }; - return rearrangeArgumentsAndCall(paramspec, NULL, self->method->ml_name, defaults, rewrite_args, argspec, arg1, + return rearrangeArgumentsAndCall(paramspec, NULL, self->d_method->ml_name, defaults, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names, continuation); } -#endif void BoxedProperty::dealloc(Box* _self) noexcept { BoxedProperty* self = static_cast(_self); @@ -640,7 +638,14 @@ void setupDescr() { PyWrapperDescr_Type.tp_call = proxyToTppCall; PyType_Ready(&PyWrapperDescr_Type); + PyMethodDescr_Type.tpp_call.capi_val = methodDescrTppCall; + PyMethodDescr_Type.tpp_call.cxx_val = methodDescrTppCall; + PyMethodDescr_Type.tp_call = proxyToTppCall; PyType_Ready(&PyMethodDescr_Type); + + PyClassMethodDescr_Type.tpp_call.capi_val = methodDescrTppCall; + PyClassMethodDescr_Type.tpp_call.cxx_val = methodDescrTppCall; + PyClassMethodDescr_Type.tp_call = proxyToTppCall; PyType_Ready(&PyClassMethodDescr_Type); } } diff --git a/test/tests/methoddescr.py b/test/tests/methoddescr.py new file mode 100644 index 000000000..a97490010 --- /dev/null +++ b/test/tests/methoddescr.py @@ -0,0 +1,2 @@ +for i in xrange(1000): + print float.__dict__['fromhex'](float, "f0.04a") From 04f4515ff22f756d7496640976c02346ce30998a Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Tue, 24 May 2016 06:11:00 +0000 Subject: [PATCH 09/11] Get rid of the numpy patch --- test/extra/numpy_fulltest.py | 23 ++--------------------- test/integration/numpy_patch.patch | 21 --------------------- test/integration/numpy_test.py | 19 ------------------- 3 files changed, 2 insertions(+), 61 deletions(-) delete mode 100644 test/integration/numpy_patch.patch diff --git a/test/extra/numpy_fulltest.py b/test/extra/numpy_fulltest.py index fc88bd224..57b75eec3 100644 --- a/test/extra/numpy_fulltest.py +++ b/test/extra/numpy_fulltest.py @@ -46,8 +46,6 @@ def print_progress_header(text): else: print ">>> Cython already installed." -NUMPY_PATCH_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "../integration/numpy_patch.patch")) - print_progress_header("Cloning up NumPy...") if not os.path.exists(NUMPY_DIR): url = "https://github.com/numpy/numpy" @@ -55,12 +53,6 @@ def print_progress_header(text): else: print ">>> NumPy already installed." -PATCH_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "../integration/numpy_patch.patch")) - -if USE_CUSTOM_PATCHES: - print_progress_header("Patching NumPy...") - subprocess.check_call(["patch", "-p1", "--input=" + PATCH_FILE], cwd=NUMPY_DIR) - try: env = os.environ CYTHON_BIN_DIR = os.path.abspath(os.path.join(ENV_NAME + "/bin")) @@ -76,25 +68,14 @@ def print_progress_header(text): print_progress_header("Installing NumPy...") subprocess.check_call([PYTHON_EXE, "setup.py", "install"], cwd=NUMPY_DIR, env=env) except: - if USE_CUSTOM_PATCHES: - print_progress_header("Unpatching NumPy...") - cmd = ["patch", "-p1", "--forward", "-i", NUMPY_PATCH_FILE, "-R", "-d", NUMPY_DIR] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) - # TODO: I'm not sure we need to do this: subprocess.check_call(["rm", "-rf", NUMPY_DIR + "/build"]) subprocess.check_call(["rm", "-rf", NUMPY_DIR + "/dist"]) raise -try: - test_helper.run_test(['sh', '-c', '. %s/bin/activate && python %s/numpy/tools/test-installed-numpy.py' % (ENV_DIR, ENV_DIR)], - ENV_NAME, [dict(ran=6139, errors=1, failures=1)]) -finally: - if USE_CUSTOM_PATCHES: - print_progress_header("Unpatching NumPy...") - cmd = ["patch", "-p1", "--forward", "-i", NUMPY_PATCH_FILE, "-R", "-d", NUMPY_DIR] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) +test_helper.run_test(['sh', '-c', '. %s/bin/activate && python %s/numpy/tools/test-installed-numpy.py' % (ENV_DIR, ENV_DIR)], + ENV_NAME, [dict(ran=6139, failures=1)]) print print "PASSED" diff --git a/test/integration/numpy_patch.patch b/test/integration/numpy_patch.patch deleted file mode 100644 index be2e43e3c..000000000 --- a/test/integration/numpy_patch.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c -index b9db3bb..2d24efc 100644 ---- a/numpy/core/src/multiarray/compiled_base.c -+++ b/numpy/core/src/multiarray/compiled_base.c -@@ -1337,13 +1337,13 @@ arr_add_docstring(PyObject *NPY_UNUSED(dummy), PyObject *args) - _ADDDOC(Type, new->tp_doc, new->tp_name); - } - else if (_TESTDOC2(MemberDescr)) { -- _ADDDOC(MemberDescr, new->d_member->doc, new->d_member->name); -+ /* _ADDDOC(MemberDescr, new->d_member->doc, new->d_member->name); */ - } - else if (_TESTDOC2(GetSetDescr)) { -- _ADDDOC(GetSetDescr, new->d_getset->doc, new->d_getset->name); -+ /* _ADDDOC(GetSetDescr, new->d_getset->doc, new->d_getset->name); */ - } - else if (_TESTDOC2(MethodDescr)) { -- _ADDDOC(MethodDescr, new->d_method->ml_doc, new->d_method->ml_name); -+ /* _ADDDOC(MethodDescr, new->d_method->ml_doc, new->d_method->ml_name); */ - } - else { - PyObject *doc_attr; diff --git a/test/integration/numpy_test.py b/test/integration/numpy_test.py index 3824a05d1..25a0e3607 100644 --- a/test/integration/numpy_test.py +++ b/test/integration/numpy_test.py @@ -86,8 +86,6 @@ def print_progress_header(text): else: print ">>> Cython already installed." -NUMPY_PATCH_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "numpy_patch.patch")) - print_progress_header("Cloning up NumPy...") if not os.path.exists(NUMPY_DIR): url = "https://github.com/numpy/numpy" @@ -95,12 +93,6 @@ def print_progress_header(text): else: print ">>> NumPy already installed." -PATCH_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), "numpy_patch.patch")) - -if USE_CUSTOM_PATCHES: - print_progress_header("Patching NumPy...") - subprocess.check_call(["patch", "-p1", "--input=" + PATCH_FILE], cwd=NUMPY_DIR) - try: env = os.environ CYTHON_BIN_DIR = os.path.abspath(os.path.join(ENV_NAME + "/bin")) @@ -112,12 +104,6 @@ def print_progress_header(text): print_progress_header("Installing NumPy...") subprocess.check_call([PYTHON_EXE, "setup.py", "install"], cwd=NUMPY_DIR, env=env) except: - if USE_CUSTOM_PATCHES: - print_progress_header("Unpatching NumPy...") - cmd = ["patch", "-p1", "--forward", "-i", NUMPY_PATCH_FILE, "-R", "-d", NUMPY_DIR] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) - - # TODO: I'm not sure we need to do this: subprocess.check_call(["rm", "-rf", NUMPY_DIR + "/build"]) subprocess.check_call(["rm", "-rf", NUMPY_DIR + "/dist"]) @@ -190,10 +176,5 @@ def mandelbrot( h,w, maxit=20 ): # when all the crashes are fixed. # subprocess.check_call([PYTHON_EXE, "-c", numpy_test], cwd=CYTHON_DIR) -if USE_CUSTOM_PATCHES: - print_progress_header("Unpatching NumPy...") - cmd = ["patch", "-p1", "--forward", "-i", NUMPY_PATCH_FILE, "-R", "-d", NUMPY_DIR] - subprocess.check_output(cmd, stderr=subprocess.STDOUT) - print print "PASSED" From 6dd62f790f6e5810806be32a7381e1c7b3848687 Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Wed, 25 May 2016 01:24:51 +0000 Subject: [PATCH 10/11] cffi failures scare me until I realize that it's because we were passing more tests than we expected. --- test/extra/cffi_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/extra/cffi_test.py b/test/extra/cffi_test.py index b3b6c6101..9df20975b 100644 --- a/test/extra/cffi_test.py +++ b/test/extra/cffi_test.py @@ -25,9 +25,9 @@ def install_and_test_cffi(): # looks like clang 3.5 causes more errors like: 214 != -42 doing casts if os.environ.has_key("CC") and "clang" in os.environ["CC"]: - expected = [{ "failed": 34, "passed": 1643, "skipped": 70, "xfailed": 4, "error": 5 }] + expected = [{ "failed": 20, "passed": 1657, "skipped": 70, "xfailed": 4, "error": 5 }] else: - expected = [{ "failed": 25, "passed": 1652, "skipped": 70, "xfailed": 4, "error": 5 }] + expected = [{ "failed": 11, "passed": 1666, "skipped": 70, "xfailed": 4, "error": 5 }] run_test([PYTEST_EXE], cwd=CFFI_DIR, expected=expected) create_virtenv(ENV_NAME, ["pytest==2.8.7", "py==1.4.31", "pycparser==2.14"], force_create = True) From a11ffa7386dbb2256ee2246f6cec6433f952a25d Mon Sep 17 00:00:00 2001 From: Kevin Modzelewski Date: Wed, 25 May 2016 01:25:05 +0000 Subject: [PATCH 11/11] Manually specify the output of methoddescr.py The behavior changed in CPython 2.7.4, and Travis-CI runs 2.7.3. --- test/tests/methoddescr.expected | 0 test/tests/methoddescr.py | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 test/tests/methoddescr.expected diff --git a/test/tests/methoddescr.expected b/test/tests/methoddescr.expected new file mode 100644 index 000000000..e69de29bb diff --git a/test/tests/methoddescr.py b/test/tests/methoddescr.py index a97490010..82f7abc36 100644 --- a/test/tests/methoddescr.py +++ b/test/tests/methoddescr.py @@ -1,2 +1,5 @@ +# This code was legal in CPython 2.7.3 but became illegal in 2.7.4 +# (there is a methoddescr.expected file for this test) + for i in xrange(1000): - print float.__dict__['fromhex'](float, "f0.04a") + float.__dict__['fromhex'](float, "f0.04a")