diff options
author | Victor Stinner <vstinner@python.org> | 2020-04-07 22:38:15 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-07 22:38:15 (GMT) |
commit | 9205520d8c43488696d66cbdd9aefbb21871c508 (patch) | |
tree | 6c6d03828fddd763f261d89a9afef18b109c0d3d | |
parent | f9dd51e7db27d04e0b716d41a2804d5acbf145d1 (diff) | |
download | cpython-9205520d8c43488696d66cbdd9aefbb21871c508.zip cpython-9205520d8c43488696d66cbdd9aefbb21871c508.tar.gz cpython-9205520d8c43488696d66cbdd9aefbb21871c508.tar.bz2 |
bpo-40170: PyObject_NEW() becomes an alias to PyObject_New() (GH-19379)
The PyObject_NEW() macro becomes an alias to the PyObject_New()
macro, and the PyObject_NEW_VAR() macro becomes an alias to the
PyObject_NewVar() macro, to hide implementation details. They no
longer access directly the PyTypeObject.tp_basicsize member.
Exclude _PyObject_SIZE() and _PyObject_VAR_SIZE() macros from
the limited C API.
Replace PyObject_NEW() with PyObject_New() and replace
PyObject_NEW_VAR() with PyObject_NewVar().
-rw-r--r-- | Include/cpython/objimpl.h | 50 | ||||
-rw-r--r-- | Include/objimpl.h | 70 | ||||
-rw-r--r-- | Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst | 4 | ||||
-rw-r--r-- | Modules/_curses_panel.c | 2 | ||||
-rw-r--r-- | Modules/_cursesmodule.c | 2 | ||||
-rw-r--r-- | Modules/_sre.c | 8 | ||||
-rw-r--r-- | Objects/capsule.c | 2 | ||||
-rw-r--r-- | Objects/codeobject.c | 2 | ||||
-rw-r--r-- | Objects/object.c | 9 | ||||
-rw-r--r-- | PC/_msi.c | 8 | ||||
-rw-r--r-- | PC/winreg.c | 2 |
11 files changed, 81 insertions, 78 deletions
diff --git a/Include/cpython/objimpl.h b/Include/cpython/objimpl.h index 2f802e9..832622c 100644 --- a/Include/cpython/objimpl.h +++ b/Include/cpython/objimpl.h @@ -6,6 +6,56 @@ extern "C" { #endif +#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) + +/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a + 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 to + ensure that pointer fields at the end of the object are correctly aligned + for the platform (this is of special importance for subclasses of, e.g., + str or int, so that pointers can be stored after the embedded data). + + Note that there's no memory wastage in doing this, as malloc has to + return (at worst) pointer-aligned memory anyway. +*/ +#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0 +# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" +#endif + +#define _PyObject_VAR_SIZE(typeobj, nitems) \ + _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \ + (nitems)*(typeobj)->tp_itemsize, \ + SIZEOF_VOID_P) + + +/* This example code implements an object constructor with a custom + allocator, where PyObject_New is inlined, and shows the important + distinction between two steps (at least): + 1) the actual allocation of the object storage; + 2) the initialization of the Python specific fields + in this storage with PyObject_{Init, InitVar}. + + PyObject * + YourObject_New(...) + { + PyObject *op; + + op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct)); + if (op == NULL) + return PyErr_NoMemory(); + + PyObject_Init(op, &YourTypeStruct); + + op->ob_field = value; + ... + return op; + } + + Note that in C++, the use of the new operator usually implies that + the 1st step is performed automatically for you, so in a C++ class + constructor you would start directly with PyObject_Init/InitVar. */ + + /* Inline functions trading binary compatibility for speed: PyObject_INIT() is the fast version of PyObject_Init(), and PyObject_INIT_VAR() is the fast version of PyObject_InitVar(). diff --git a/Include/objimpl.h b/Include/objimpl.h index 4591925..6e7549c 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -122,12 +122,18 @@ PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *, PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *); PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); -#define PyObject_New(type, typeobj) \ - ( (type *) _PyObject_New(typeobj) ) +#define PyObject_New(type, typeobj) ((type *)_PyObject_New(typeobj)) + +// Alias to PyObject_New(). In Python 3.8, PyObject_NEW() called directly +// PyObject_MALLOC() with _PyObject_SIZE(). +#define PyObject_NEW(type, typeobj) PyObject_New(type, typeobj) + #define PyObject_NewVar(type, typeobj, n) \ ( (type *) _PyObject_NewVar((typeobj), (n)) ) -#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) +// Alias to PyObject_New(). In Python 3.8, PyObject_NEW() called directly +// PyObject_MALLOC() with _PyObject_VAR_SIZE(). +#define PyObject_NEW_VAR(type, typeobj, n) PyObject_NewVar(type, typeobj, n) #ifdef Py_LIMITED_API @@ -143,64 +149,6 @@ PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); #endif -/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a - 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 to - ensure that pointer fields at the end of the object are correctly aligned - for the platform (this is of special importance for subclasses of, e.g., - str or int, so that pointers can be stored after the embedded data). - - Note that there's no memory wastage in doing this, as malloc has to - return (at worst) pointer-aligned memory anyway. -*/ -#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0 -# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" -#endif - -#define _PyObject_VAR_SIZE(typeobj, nitems) \ - _Py_SIZE_ROUND_UP((typeobj)->tp_basicsize + \ - (nitems)*(typeobj)->tp_itemsize, \ - SIZEOF_VOID_P) - -#define PyObject_NEW(type, typeobj) \ -( (type *) PyObject_Init( \ - (PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) ) - -#define PyObject_NEW_VAR(type, typeobj, n) \ -( (type *) PyObject_InitVar( \ - (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n)) ),\ - (typeobj), (n)) ) - -/* This example code implements an object constructor with a custom - allocator, where PyObject_New is inlined, and shows the important - distinction between two steps (at least): - 1) the actual allocation of the object storage; - 2) the initialization of the Python specific fields - in this storage with PyObject_{Init, InitVar}. - - PyObject * - YourObject_New(...) - { - PyObject *op; - - op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct)); - if (op == NULL) - return PyErr_NoMemory(); - - PyObject_Init(op, &YourTypeStruct); - - op->ob_field = value; - ... - return op; - } - - Note that in C++, the use of the new operator usually implies that - the 1st step is performed automatically for you, so in a C++ class - constructor you would start directly with PyObject_Init/InitVar -*/ - - - /* * Garbage Collection Support * ========================== diff --git a/Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst b/Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst new file mode 100644 index 0000000..2c31cca --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-04-05-00-37-34.bpo-40170.Seuh3D.rst @@ -0,0 +1,4 @@ +The :c:func:`PyObject_NEW` macro becomes an alias to the :c:func:`PyObject_New` +macro, and the :c:func:`PyObject_NEW_VAR` macro becomes an alias to the +:c:func:`PyObject_NewVar` macro, to hide implementation details. They no longer +access directly the :c:member:`PyTypeObject.tp_basicsize` member. diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 77a6a14..7ca91f6 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -239,7 +239,7 @@ PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo) { PyCursesPanelObject *po; - po = PyObject_NEW(PyCursesPanelObject, + po = PyObject_New(PyCursesPanelObject, (PyTypeObject *)(_curses_panelstate_global)->PyCursesPanel_Type); if (po == NULL) return NULL; po->pan = pan; diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 3d16af7..ca6a89f 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -547,7 +547,7 @@ PyCursesWindow_New(WINDOW *win, const char *encoding) encoding = "utf-8"; } - wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type); + wo = PyObject_New(PyCursesWindowObject, &PyCursesWindow_Type); if (wo == NULL) return NULL; wo->win = win; wo->encoding = _PyMem_Strdup(encoding); diff --git a/Modules/_sre.c b/Modules/_sre.c index 52ed420..bee2e12 100644 --- a/Modules/_sre.c +++ b/Modules/_sre.c @@ -1338,7 +1338,7 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, n = PyList_GET_SIZE(code); /* coverity[ampersand_in_size] */ - self = PyObject_NEW_VAR(PatternObject, &Pattern_Type, n); + self = PyObject_NewVar(PatternObject, &Pattern_Type, n); if (!self) return NULL; self->weakreflist = NULL; @@ -2327,8 +2327,8 @@ pattern_new_match(PatternObject* pattern, SRE_STATE* state, Py_ssize_t status) /* create match object (with room for extra group marks) */ /* coverity[ampersand_in_size] */ - match = PyObject_NEW_VAR(MatchObject, &Match_Type, - 2*(pattern->groups+1)); + match = PyObject_NewVar(MatchObject, &Match_Type, + 2*(pattern->groups+1)); if (!match) return NULL; @@ -2468,7 +2468,7 @@ pattern_scanner(PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_ ScannerObject* scanner; /* create scanner object */ - scanner = PyObject_NEW(ScannerObject, &Scanner_Type); + scanner = PyObject_New(ScannerObject, &Scanner_Type); if (!scanner) return NULL; scanner->pattern = NULL; diff --git a/Objects/capsule.c b/Objects/capsule.c index 599893a..ed24cc1 100644 --- a/Objects/capsule.c +++ b/Objects/capsule.c @@ -50,7 +50,7 @@ PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor) return NULL; } - capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type); + capsule = PyObject_New(PyCapsule, &PyCapsule_Type); if (capsule == NULL) { return NULL; } diff --git a/Objects/codeobject.c b/Objects/codeobject.c index fd64393..1820d8c 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -219,7 +219,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, cell2arg = NULL; } } - co = PyObject_NEW(PyCodeObject, &PyCode_Type); + co = PyObject_New(PyCodeObject, &PyCode_Type); if (co == NULL) { if (cell2arg) PyMem_FREE(cell2arg); diff --git a/Objects/object.c b/Objects/object.c index 05241e8..069afc0 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -161,11 +161,12 @@ PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) PyObject * _PyObject_New(PyTypeObject *tp) { - PyObject *op; - op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); - if (op == NULL) + PyObject *op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); + if (op == NULL) { return PyErr_NoMemory(); - return PyObject_INIT(op, tp); + } + PyObject_INIT(op, tp); + return op; } PyVarObject * @@ -531,7 +531,7 @@ static PyTypeObject record_Type = { static PyObject* record_new(MSIHANDLE h) { - msiobj *result = PyObject_NEW(struct msiobj, &record_Type); + msiobj *result = PyObject_New(struct msiobj, &record_Type); if (!result) { MsiCloseHandle(h); @@ -882,7 +882,7 @@ msidb_openview(msiobj *msidb, PyObject *args) if ((status = MsiDatabaseOpenView(msidb->h, sql, &hView)) != ERROR_SUCCESS) return msierror(status); - result = PyObject_NEW(struct msiobj, &msiview_Type); + result = PyObject_New(struct msiobj, &msiview_Type); if (!result) { MsiCloseHandle(hView); return NULL; @@ -918,7 +918,7 @@ msidb_getsummaryinformation(msiobj *db, PyObject *args) if (status != ERROR_SUCCESS) return msierror(status); - oresult = PyObject_NEW(struct msiobj, &summary_Type); + oresult = PyObject_New(struct msiobj, &summary_Type); if (!oresult) { MsiCloseHandle(result); return NULL; @@ -1013,7 +1013,7 @@ static PyObject* msiopendb(PyObject *obj, PyObject *args) if (status != ERROR_SUCCESS) return msierror(status); - result = PyObject_NEW(struct msiobj, &msidb_Type); + result = PyObject_New(struct msiobj, &msidb_Type); if (!result) { MsiCloseHandle(h); return NULL; diff --git a/PC/winreg.c b/PC/winreg.c index 5dff7de..ec2f607 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -390,7 +390,7 @@ PyTypeObject PyHKEY_Type = PyObject * PyHKEY_New(HKEY hInit) { - PyHKEYObject *key = PyObject_NEW(PyHKEYObject, &PyHKEY_Type); + PyHKEYObject *key = PyObject_New(PyHKEYObject, &PyHKEY_Type); if (key) key->hkey = hInit; return (PyObject *)key; |