mirror of
https://github.com/python/cpython.git
synced 2025-12-09 02:35:14 +00:00
Guido suggests, and I agree, to insist that SIZEOF_VOID_P be a power of 2.
This simplifies the rounding in _PyObject_VAR_SIZE, allows to restore the pre-rounding calling sequence, and allows some nice little simplifications in its callers. I'm still making it return a size_t, though.
This commit is contained in:
parent
0a1fc4e389
commit
f2a67daca2
4 changed files with 31 additions and 47 deletions
|
|
@ -173,40 +173,36 @@ extern DL_IMPORT(void) _PyObject_Del(PyObject *);
|
||||||
|
|
||||||
#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
|
#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize )
|
||||||
|
|
||||||
/* _PyObject_VAR_SIZE computes the amount of memory allocated for a vrbl-
|
/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a
|
||||||
size object with nitems items, exclusive of gc overhead (if any). The
|
vrbl-size object with nitems items, exclusive of gc overhead (if any). The
|
||||||
value is rounded up to the closest multiple of sizeof(void *), in order
|
value is rounded up to the closest multiple of sizeof(void *), in order to
|
||||||
to ensure that pointer fields at the end of the object are correctly
|
ensure that pointer fields at the end of the object are correctly aligned
|
||||||
aligned for the platform (this is of special importance for subclasses
|
for the platform (this is of special importance for subclasses of, e.g.,
|
||||||
of, e.g., str or long, so that pointers can be stored after the embedded
|
str or long, so that pointers can be stored after the embedded data).
|
||||||
data).
|
|
||||||
|
|
||||||
Note that there's no memory wastage in doing this, as malloc has to
|
Note that there's no memory wastage in doing this, as malloc has to
|
||||||
return (at worst) pointer-aligned memory anyway
|
return (at worst) pointer-aligned memory anyway.
|
||||||
|
|
||||||
However, writing the macro to *return* the result is clumsy due to the
|
|
||||||
calculations needed. Instead you must pass the result lvalue as the first
|
|
||||||
argument, and it should be of type size_t (both because that's the
|
|
||||||
correct conceptual type, and because using an unsigned type allows the
|
|
||||||
compiler to generate faster code for the mod computation inside the
|
|
||||||
macro).
|
|
||||||
*/
|
*/
|
||||||
#define _PyObject_VAR_SIZE(result, typeobj, nitems) \
|
#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0
|
||||||
do { \
|
# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2"
|
||||||
size_t mod; \
|
#endif
|
||||||
(result) = (size_t) (typeobj)->tp_basicsize; \
|
|
||||||
(result) += (size_t) ((nitems)*(typeobj)->tp_itemsize); \
|
#define _PyObject_VAR_SIZE(typeobj, nitems) \
|
||||||
mod = (result) % SIZEOF_VOID_P; \
|
(size_t) \
|
||||||
if (mod) \
|
( ( (typeobj)->tp_basicsize + \
|
||||||
(result) += SIZEOF_VOID_P - mod; \
|
(nitems)*(typeobj)->tp_itemsize + \
|
||||||
} while(0)
|
(SIZEOF_VOID_P - 1) \
|
||||||
|
) & ~(SIZEOF_VOID_P - 1) \
|
||||||
|
)
|
||||||
|
|
||||||
#define PyObject_NEW(type, typeobj) \
|
#define PyObject_NEW(type, typeobj) \
|
||||||
( (type *) PyObject_Init( \
|
( (type *) PyObject_Init( \
|
||||||
(PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) )
|
(PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) )
|
||||||
|
|
||||||
#define PyObject_NEW_VAR(type, typeobj, nitems) \
|
#define PyObject_NEW_VAR(type, typeobj, n) \
|
||||||
((type *) _PyObject_NewVar(typeobj, nitems))
|
( (type *) PyObject_InitVar( \
|
||||||
|
(PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n)) ),\
|
||||||
|
(typeobj), (n)) )
|
||||||
|
|
||||||
#define PyObject_DEL(op) PyObject_FREE(op)
|
#define PyObject_DEL(op) PyObject_FREE(op)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -801,14 +801,10 @@ PyObject *
|
||||||
_PyObject_GC_Malloc(PyTypeObject *tp, int nitems)
|
_PyObject_GC_Malloc(PyTypeObject *tp, int nitems)
|
||||||
{
|
{
|
||||||
PyObject *op;
|
PyObject *op;
|
||||||
size_t basicsize;
|
const size_t basicsize = _PyObject_VAR_SIZE(tp, nitems);
|
||||||
#ifdef WITH_CYCLE_GC
|
#ifdef WITH_CYCLE_GC
|
||||||
size_t nbytes;
|
const size_t nbytes = sizeof(PyGC_Head) + basicsize;
|
||||||
PyGC_Head *g;
|
PyGC_Head *g = PyObject_MALLOC(nbytes);
|
||||||
|
|
||||||
_PyObject_VAR_SIZE(basicsize, tp, nitems);
|
|
||||||
nbytes = sizeof(PyGC_Head) + basicsize;
|
|
||||||
g = PyObject_MALLOC(nbytes);
|
|
||||||
if (g == NULL)
|
if (g == NULL)
|
||||||
return (PyObject *)PyErr_NoMemory();
|
return (PyObject *)PyErr_NoMemory();
|
||||||
g->gc_next = NULL;
|
g->gc_next = NULL;
|
||||||
|
|
@ -824,7 +820,6 @@ _PyObject_GC_Malloc(PyTypeObject *tp, int nitems)
|
||||||
}
|
}
|
||||||
op = FROM_GC(g);
|
op = FROM_GC(g);
|
||||||
#else
|
#else
|
||||||
_PyObject_VAR_SIZE(basicsize, tp, nitems);
|
|
||||||
op = PyObject_MALLOC(basicsize);
|
op = PyObject_MALLOC(basicsize);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return (PyObject *)PyErr_NoMemory();
|
return (PyObject *)PyErr_NoMemory();
|
||||||
|
|
@ -850,17 +845,14 @@ _PyObject_GC_NewVar(PyTypeObject *tp, int nitems)
|
||||||
PyVarObject *
|
PyVarObject *
|
||||||
_PyObject_GC_Resize(PyVarObject *op, int nitems)
|
_PyObject_GC_Resize(PyVarObject *op, int nitems)
|
||||||
{
|
{
|
||||||
size_t basicsize;
|
const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems);
|
||||||
#ifdef WITH_CYCLE_GC
|
#ifdef WITH_CYCLE_GC
|
||||||
PyGC_Head *g = AS_GC(op);
|
PyGC_Head *g = AS_GC(op);
|
||||||
|
|
||||||
_PyObject_VAR_SIZE(basicsize, op->ob_type, nitems);
|
|
||||||
g = PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize);
|
g = PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize);
|
||||||
if (g == NULL)
|
if (g == NULL)
|
||||||
return (PyVarObject *)PyErr_NoMemory();
|
return (PyVarObject *)PyErr_NoMemory();
|
||||||
op = (PyVarObject *) FROM_GC(g);
|
op = (PyVarObject *) FROM_GC(g);
|
||||||
#else
|
#else
|
||||||
_PyObject_VAR_SIZE(basicsize, op->ob_type, nitems);
|
|
||||||
op = PyObject_REALLOC(op, basicsize);
|
op = PyObject_REALLOC(op, basicsize);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return (PyVarObject *)PyErr_NoMemory();
|
return (PyVarObject *)PyErr_NoMemory();
|
||||||
|
|
|
||||||
|
|
@ -130,9 +130,7 @@ PyVarObject *
|
||||||
_PyObject_NewVar(PyTypeObject *tp, int nitems)
|
_PyObject_NewVar(PyTypeObject *tp, int nitems)
|
||||||
{
|
{
|
||||||
PyVarObject *op;
|
PyVarObject *op;
|
||||||
size_t size;
|
const size_t size = _PyObject_VAR_SIZE(tp, nitems);
|
||||||
|
|
||||||
_PyObject_VAR_SIZE(size, tp, nitems);
|
|
||||||
op = (PyVarObject *) PyObject_MALLOC(size);
|
op = (PyVarObject *) PyObject_MALLOC(size);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return (PyVarObject *)PyErr_NoMemory();
|
return (PyVarObject *)PyErr_NoMemory();
|
||||||
|
|
@ -1158,8 +1156,8 @@ _PyObject_GetDictPtr(PyObject *obj)
|
||||||
if (dictoffset == 0)
|
if (dictoffset == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (dictoffset < 0) {
|
if (dictoffset < 0) {
|
||||||
size_t size;
|
const size_t size = _PyObject_VAR_SIZE(tp,
|
||||||
_PyObject_VAR_SIZE(size, tp, ((PyVarObject *)obj)->ob_size);
|
((PyVarObject *)obj)->ob_size);
|
||||||
dictoffset += (long)size;
|
dictoffset += (long)size;
|
||||||
assert(dictoffset > 0);
|
assert(dictoffset > 0);
|
||||||
assert(dictoffset % SIZEOF_VOID_P == 0);
|
assert(dictoffset % SIZEOF_VOID_P == 0);
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,7 @@ PyObject *
|
||||||
PyType_GenericAlloc(PyTypeObject *type, int nitems)
|
PyType_GenericAlloc(PyTypeObject *type, int nitems)
|
||||||
{
|
{
|
||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
size_t size;
|
const size_t size = _PyObject_VAR_SIZE(type, nitems);
|
||||||
|
|
||||||
_PyObject_VAR_SIZE(size, type, nitems);
|
|
||||||
|
|
||||||
if (PyType_IS_GC(type))
|
if (PyType_IS_GC(type))
|
||||||
obj = _PyObject_GC_Malloc(type, nitems);
|
obj = _PyObject_GC_Malloc(type, nitems);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue