Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Include/internal/pycore_object.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ extern "C"{
# error "this header requires Py_BUILD_CORE define"
#endif

#include "pycore_pystate.h" /* _PyRuntime.gc */
#include "pycore_pystate.h" /* PyInterpreterState.gc */

PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type);
PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content);
Expand DownExpand Up@@ -94,6 +94,15 @@ _PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
return (PyObject **)((char *)op + offset);
}

// Fast inlined version of PyType_HasFeature()
static inline int
_PyType_HasFeature(PyTypeObject *type, unsigned long feature){
return ((type->tp_flags & feature) != 0);
}

// Fast inlined version of PyType_IS_GC()
#define _PyType_IS_GC(t) _PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 0 additions & 4 deletions Include/object.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -614,11 +614,7 @@ times.

static inline int
PyType_HasFeature(PyTypeObject *type, unsigned long feature){
#ifdef Py_LIMITED_API
return ((PyType_GetFlags(type) & feature) != 0);
#else
return ((type->tp_flags & feature) != 0);
#endif
}

#define PyType_FastSubclass(type, flag) PyType_HasFeature(type, flag)
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
:c:func:`PyType_HasFeature` now always calls :c:func:`PyType_GetFlags` to
hide implementation details. Previously, it accessed directly the
:c:member:`PyTypeObject.tp_flags` member when the limited C API was not
used.
10 changes: 5 additions & 5 deletions Objects/object.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -187,11 +187,11 @@ PyObject_CallFinalizer(PyObject *self)
if (tp->tp_finalize == NULL)
return;
/* tp_finalize should only be called once. */
if (PyType_IS_GC(tp) && _PyGC_FINALIZED(self))
if (_PyType_IS_GC(tp) && _PyGC_FINALIZED(self))
return;

tp->tp_finalize(self);
if (PyType_IS_GC(tp)){
if (_PyType_IS_GC(tp)){
_PyGC_SET_FINALIZED(self);
}
}
Expand DownExpand Up@@ -228,7 +228,7 @@ PyObject_CallFinalizerFromDealloc(PyObject *self)
Py_SET_REFCNT(self, refcnt);

_PyObject_ASSERT(self,
(!PyType_IS_GC(Py_TYPE(self))
(!_PyType_IS_GC(Py_TYPE(self))
|| _PyObject_GC_IS_TRACKED(self)));
/* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased
_Py_RefTotal, so we need to undo that. */
Expand DownExpand Up@@ -1103,7 +1103,7 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
descr = _PyType_Lookup(tp, name);
if (descr != NULL){
Py_INCREF(descr);
if (PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)){
if (_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)){
meth_found = 1;
} else{
f = Py_TYPE(descr)->tp_descr_get;
Expand DownExpand Up@@ -2176,7 +2176,7 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg,
to crash than dumping the traceback. */
void *ptr;
PyTypeObject *type = Py_TYPE(obj);
if (PyType_IS_GC(type)){
if (_PyType_IS_GC(type)){
ptr = (void *)((char *)obj - sizeof(PyGC_Head));
}
else{
Expand Down
47 changes: 27 additions & 20 deletions Objects/typeobject.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -269,7 +269,7 @@ PyType_Modified(PyTypeObject *type)
PyObject *raw, *ref;
Py_ssize_t i;

if (!PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
if (!_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
return;

raw = type->tp_subclasses;
Expand DownExpand Up@@ -307,7 +307,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases){
PyObject *mro_meth = NULL;
PyObject *type_mro_meth = NULL;

if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
if (!_PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
return;

if (custom){
Expand All@@ -332,7 +332,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases){
assert(PyType_Check(b));
cls = (PyTypeObject *)b;

if (!PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
if (!_PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) ||
!PyType_IsSubtype(type, cls)){
goto clear;
}
Expand All@@ -356,11 +356,11 @@ assign_version_tag(PyTypeObject *type)
Py_ssize_t i, n;
PyObject *bases;

if (PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
if (_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG))
return 1;
if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
if (!_PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG))
return 0;
if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
if (!_PyType_HasFeature(type, Py_TPFLAGS_READY))
return 0;

type->tp_version_tag = next_version_tag++;
Expand DownExpand Up@@ -1028,23 +1028,29 @@ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
/* note that we need to add one, for the sentinel */

if (PyType_IS_GC(type))
if (_PyType_IS_GC(type)){
obj = _PyObject_GC_Malloc(size);
else
}
else{
obj = (PyObject *)PyObject_MALLOC(size);
}

if (obj == NULL)
if (obj == NULL){
return PyErr_NoMemory();
}

memset(obj, '\0', size);

if (type->tp_itemsize == 0)
if (type->tp_itemsize == 0){
(void)PyObject_INIT(obj, type);
else
}
else{
(void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
}

if (PyType_IS_GC(type))
if (_PyType_IS_GC(type)){
_PyObject_GC_TRACK(obj);
}
return obj;
}

Expand DownExpand Up@@ -1178,7 +1184,7 @@ subtype_dealloc(PyObject *self)

/* Test whether the type has GC exactly once */

if (!PyType_IS_GC(type)){
if (!_PyType_IS_GC(type)){
/* A non GC dynamic type allows certain simplifications:
there's no need to call clear_slots(), or DECREF the dict,
or clear weakrefs. */
Expand DownExpand Up@@ -1304,8 +1310,9 @@ subtype_dealloc(PyObject *self)
/* Call the base tp_dealloc(); first retrack self if
* basedealloc knows about gc.
*/
if (PyType_IS_GC(base))
if (_PyType_IS_GC(base)){
_PyObject_GC_TRACK(self);
}
assert(basedealloc);
basedealloc(self);

Expand DownExpand Up@@ -1435,7 +1442,7 @@ lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
return NULL;
}

if (PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)){
if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)){
/* Avoid temporary PyMethodObject */
*unbound = 1;
Py_INCREF(res);
Expand DownExpand Up@@ -2026,7 +2033,7 @@ best_base(PyObject *bases)
if (PyType_Ready(base_i) < 0)
return NULL;
}
if (!PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)){
if (!_PyType_HasFeature(base_i, Py_TPFLAGS_BASETYPE)){
PyErr_Format(PyExc_TypeError,
"type '%.100s' is not an acceptable base type",
base_i->tp_name);
Expand DownExpand Up@@ -2933,7 +2940,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
if (base == NULL){
goto fail;
}
if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)){
if (!_PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)){
PyErr_Format(PyExc_TypeError,
"type '%.100s' is not an acceptable base type",
base->tp_name);
Expand DownExpand Up@@ -3051,7 +3058,7 @@ PyType_FromSpec(PyType_Spec *spec)
void *
PyType_GetSlot(PyTypeObject *type, int slot)
{
if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0){
if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0){
PyErr_BadInternalCall();
return NULL;
}
Expand DownExpand Up@@ -3134,7 +3141,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
unsigned int h;

if (MCACHE_CACHEABLE_NAME(name) &&
PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)){
_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)){
/* fast path */
h = MCACHE_HASH_METHOD(type, name);
if (method_cache[h].version == type->tp_version_tag &&
Expand DownExpand Up@@ -5404,7 +5411,7 @@ PyType_Ready(PyTypeObject *type)
}

/* Sanity check for tp_free. */
if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&
if (_PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&
(type->tp_free == NULL || type->tp_free == PyObject_Del)){
/* This base class needs to call tp_free, but doesn't have
* one, or its tp_free is for non-gc'ed objects.
Expand Down