diff options
Diffstat (limited to 'Objects/object.c')
-rw-r--r-- | Objects/object.c | 293 |
1 files changed, 210 insertions, 83 deletions
diff --git a/Objects/object.c b/Objects/object.c index 87c8e1a..137752d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -32,7 +32,7 @@ dump_counts(void) for (tp = type_list; tp; tp = tp->tp_next) fprintf(stderr, "%s alloc'd: %d, freed: %d, max in use: %d\n", - tp->tp_name, tp->tp_alloc, tp->tp_free, + tp->tp_name, tp->tp_allocs, tp->tp_frees, tp->tp_maxalloc); fprintf(stderr, "fast tuple allocs: %d, empty: %d\n", fast_tuple_allocs, tuple_zero_allocs); @@ -53,8 +53,8 @@ get_counts(void) if (result == NULL) return NULL; for (tp = type_list; tp; tp = tp->tp_next) { - v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_alloc, - tp->tp_free, tp->tp_maxalloc); + v = Py_BuildValue("(siii)", tp->tp_name, tp->tp_allocs, + tp->tp_frees, tp->tp_maxalloc); if (v == NULL) { Py_DECREF(result); return NULL; @@ -72,16 +72,16 @@ get_counts(void) void inc_count(PyTypeObject *tp) { - if (tp->tp_alloc == 0) { + if (tp->tp_allocs == 0) { /* first time; insert in linked list */ if (tp->tp_next != NULL) /* sanity check */ Py_FatalError("XXX inc_count sanity check"); tp->tp_next = type_list; type_list = tp; } - tp->tp_alloc++; - if (tp->tp_alloc - tp->tp_free > tp->tp_maxalloc) - tp->tp_maxalloc = tp->tp_alloc - tp->tp_free; + tp->tp_allocs++; + if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc) + tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees; } #endif @@ -93,10 +93,8 @@ PyObject_Init(PyObject *op, PyTypeObject *tp) "NULL object passed to PyObject_Init"); return op; } -#ifdef WITH_CYCLE_GC if (PyType_IS_GC(tp)) op = (PyObject *) PyObject_FROM_GC(op); -#endif /* Any changes should be reflected in PyObject_INIT (objimpl.h) */ op->ob_type = tp; _Py_NewReference(op); @@ -111,10 +109,8 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, int size) "NULL object passed to PyObject_InitVar"); return op; } -#ifdef WITH_CYCLE_GC if (PyType_IS_GC(tp)) op = (PyVarObject *) PyObject_FROM_GC(op); -#endif /* Any changes should be reflected in PyObject_INIT_VAR */ op->ob_size = size; op->ob_type = tp; @@ -129,10 +125,8 @@ _PyObject_New(PyTypeObject *tp) op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); if (op == NULL) return PyErr_NoMemory(); -#ifdef WITH_CYCLE_GC if (PyType_IS_GC(tp)) op = (PyObject *) PyObject_FROM_GC(op); -#endif return PyObject_INIT(op, tp); } @@ -143,21 +137,17 @@ _PyObject_NewVar(PyTypeObject *tp, int size) op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size)); if (op == NULL) return (PyVarObject *)PyErr_NoMemory(); -#ifdef WITH_CYCLE_GC if (PyType_IS_GC(tp)) op = (PyVarObject *) PyObject_FROM_GC(op); -#endif return PyObject_INIT_VAR(op, tp, size); } void _PyObject_Del(PyObject *op) { -#ifdef WITH_CYCLE_GC if (op && PyType_IS_GC(op->ob_type)) { op = (PyObject *) PyObject_AS_GC(op); } -#endif PyObject_FREE(op); } @@ -994,26 +984,16 @@ PyObject_Hash(PyObject *v) PyObject * PyObject_GetAttrString(PyObject *v, char *name) { - if (v->ob_type->tp_getattro != NULL) { - PyObject *w, *res; - w = PyString_InternFromString(name); - if (w == NULL) - return NULL; - res = (*v->ob_type->tp_getattro)(v, w); - Py_XDECREF(w); - return res; - } + PyObject *w, *res; - if (v->ob_type->tp_getattr == NULL) { - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%.400s'", - v->ob_type->tp_name, - name); - return NULL; - } - else { + if (v->ob_type->tp_getattr != NULL) return (*v->ob_type->tp_getattr)(v, name); - } + w = PyString_InternFromString(name); + if (w == NULL) + return NULL; + res = PyObject_GetAttr(v, w); + Py_XDECREF(w); + return res; } int @@ -1031,34 +1011,24 @@ PyObject_HasAttrString(PyObject *v, char *name) int PyObject_SetAttrString(PyObject *v, char *name, PyObject *w) { - if (v->ob_type->tp_setattro != NULL) { - PyObject *s; - int res; - s = PyString_InternFromString(name); - if (s == NULL) - return -1; - res = (*v->ob_type->tp_setattro)(v, s, w); - Py_XDECREF(s); - return res; - } + PyObject *s; + int res; - if (v->ob_type->tp_setattr == NULL) { - if (v->ob_type->tp_getattr == NULL) - PyErr_SetString(PyExc_TypeError, - "attribute-less object (assign or del)"); - else - PyErr_SetString(PyExc_TypeError, - "object has read-only attributes"); - return -1; - } - else { + if (v->ob_type->tp_setattr != NULL) return (*v->ob_type->tp_setattr)(v, name, w); - } + s = PyString_InternFromString(name); + if (s == NULL) + return -1; + res = PyObject_SetAttr(v, s, w); + Py_XDECREF(s); + return res; } PyObject * PyObject_GetAttr(PyObject *v, PyObject *name) { + PyTypeObject *tp = v->ob_type; + /* The Unicode to string conversion is done here because the existing tp_getattro slots expect a string object as name and we wouldn't want to break those. */ @@ -1067,16 +1037,19 @@ PyObject_GetAttr(PyObject *v, PyObject *name) if (name == NULL) return NULL; } - if (!PyString_Check(name)) { PyErr_SetString(PyExc_TypeError, "attribute name must be string"); return NULL; } - if (v->ob_type->tp_getattro != NULL) - return (*v->ob_type->tp_getattro)(v, name); - else - return PyObject_GetAttrString(v, PyString_AS_STRING(name)); + if (tp->tp_getattro != NULL) + return (*tp->tp_getattro)(v, name); + if (tp->tp_getattr != NULL) + return (*tp->tp_getattr)(v, PyString_AS_STRING(name)); + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(name)); + return NULL; } int @@ -1094,6 +1067,7 @@ PyObject_HasAttr(PyObject *v, PyObject *name) int PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) { + PyTypeObject *tp = v->ob_type; int err; /* The Unicode to string conversion is done here because the @@ -1104,25 +1078,182 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) if (name == NULL) return -1; } - else - Py_INCREF(name); - - if (!PyString_Check(name)){ + else if (!PyString_Check(name)){ PyErr_SetString(PyExc_TypeError, "attribute name must be string"); - err = -1; + return -1; } - else { - PyString_InternInPlace(&name); - if (v->ob_type->tp_setattro != NULL) - err = (*v->ob_type->tp_setattro)(v, name, value); - else - err = PyObject_SetAttrString(v, - PyString_AS_STRING(name), value); + else + Py_INCREF(name); + + PyString_InternInPlace(&name); + if (tp->tp_setattro != NULL) { + err = (*tp->tp_setattro)(v, name, value); + Py_DECREF(name); + return err; + } + if (tp->tp_setattr != NULL) { + err = (*tp->tp_setattr)(v, PyString_AS_STRING(name), value); + Py_DECREF(name); + return err; } - Py_DECREF(name); - return err; + if (tp->tp_getattr == NULL && tp->tp_getattro == NULL) + PyErr_Format(PyExc_TypeError, + "'%.100s' object has no attributes " + "(%s .%.100s)", + tp->tp_name, + value==NULL ? "del" : "assign to", + PyString_AS_STRING(name)); + else + PyErr_Format(PyExc_TypeError, + "'%.100s' object has only read-only attributes " + "(%s .%.100s)", + tp->tp_name, + value==NULL ? "del" : "assign to", + PyString_AS_STRING(name)); + return -1; +} + +/* Helper to get a pointer to an object's __dict__ slot, if any */ + +PyObject ** +_PyObject_GetDictPtr(PyObject *obj) +{ +#define PTRSIZE (sizeof(PyObject *)) + + long dictoffset; + PyTypeObject *tp = obj->ob_type; + + if (!(tp->tp_flags & Py_TPFLAGS_HAVE_CLASS)) + return NULL; + dictoffset = tp->tp_dictoffset; + if (dictoffset == 0) + return NULL; + if (dictoffset < 0) { + dictoffset += PyType_BASICSIZE(tp); + assert(dictoffset > 0); /* Sanity check */ + if (tp->tp_itemsize > 0) { + int n = ((PyVarObject *)obj)->ob_size; + if (n > 0) { + dictoffset += tp->tp_itemsize * n; + /* Round up, if necessary */ + if (tp->tp_itemsize % PTRSIZE != 0) { + dictoffset += PTRSIZE - 1; + dictoffset /= PTRSIZE; + dictoffset *= PTRSIZE; + } + } + } + } + return (PyObject **) ((char *)obj + dictoffset); +} + +/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */ + +PyObject * +PyObject_GenericGetAttr(PyObject *obj, PyObject *name) +{ + PyTypeObject *tp = obj->ob_type; + PyObject *descr; + descrgetfunc f; + PyObject **dictptr; + + if (tp->tp_dict == NULL) { + if (PyType_InitDict(tp) < 0) + return NULL; + } + + descr = _PyType_Lookup(tp, name); + f = NULL; + if (descr != NULL) { + f = descr->ob_type->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) + return f(descr, obj, (PyObject *)obj->ob_type); + } + + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict != NULL) { + PyObject *res = PyDict_GetItem(dict, name); + if (res != NULL) { + Py_INCREF(res); + return res; + } + } + } + + if (f != NULL) + return f(descr, obj, (PyObject *)obj->ob_type); + + if (descr != NULL) { + Py_INCREF(descr); + return descr; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(name)); + return NULL; +} + +int +PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) +{ + PyTypeObject *tp = obj->ob_type; + PyObject *descr; + descrsetfunc f; + PyObject **dictptr; + + if (tp->tp_dict == NULL) { + if (PyType_InitDict(tp) < 0) + return -1; + } + + descr = _PyType_Lookup(tp, name); + f = NULL; + if (descr != NULL) { + f = descr->ob_type->tp_descr_set; + if (f != NULL && PyDescr_IsData(descr)) + return f(descr, obj, value); + } + + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL && value != NULL) { + dict = PyDict_New(); + if (dict == NULL) + return -1; + *dictptr = dict; + } + if (dict != NULL) { + int res; + if (value == NULL) + res = PyDict_DelItem(dict, name); + else + res = PyDict_SetItem(dict, name, value); + if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) + PyErr_SetObject(PyExc_AttributeError, name); + return res; + } + } + + if (f != NULL) + return f(descr, obj, value); + + if (descr == NULL) { + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(name)); + return -1; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object attribute '%.400s' is read-only", + tp->tp_name, PyString_AS_STRING(name)); + return -1; } /* Test a value used as condition, e.g., in a for or if statement. @@ -1218,12 +1349,6 @@ PyCallable_Check(PyObject *x) { if (x == NULL) return 0; - if (x->ob_type->tp_call != NULL || - PyFunction_Check(x) || - PyMethod_Check(x) || - PyCFunction_Check(x) || - PyClass_Check(x)) - return 1; if (PyInstance_Check(x)) { PyObject *call = PyObject_GetAttrString(x, "__call__"); if (call == NULL) { @@ -1235,7 +1360,9 @@ PyCallable_Check(PyObject *x) Py_DECREF(call); return 1; } - return 0; + else { + return x->ob_type->tp_call != NULL; + } } @@ -1365,7 +1492,7 @@ _Py_ForgetReference(register PyObject *op) op->_ob_prev->_ob_next = op->_ob_next; op->_ob_next = op->_ob_prev = NULL; #ifdef COUNT_ALLOCS - op->ob_type->tp_free++; + op->ob_type->tp_frees++; #endif } |