Skip to content

Commit

Permalink
gh-94673: Add _PyStaticType_InitBuiltin() (#95152)
Browse files Browse the repository at this point in the history
This is the first of several precursors to storing tp_subclasses (and tp_weaklist) on the interpreter state for static builtin types.

We do the following:

* add `_PyStaticType_InitBuiltin()`
* add `_Py_TPFLAGS_STATIC_BUILTIN`
* set it on all static builtin types in `_PyStaticType_InitBuiltin()`
* shuffle some code around to be able to use _PyStaticType_InitBuiltin()
    * rename `_PyStructSequence_InitType()` to `_PyStructSequence_InitBuiltinWithFlags()`
    * add `_PyStructSequence_InitBuiltin()`.
  • Loading branch information
ericsnowcurrently committed Jul 25, 2022
1 parent c514094 commit 4a1dd73
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 76 deletions.
9 changes: 8 additions & 1 deletion Include/internal/pycore_structseq.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@ PyAPI_FUNC(PyTypeObject *) _PyStructSequence_NewType(
PyStructSequence_Desc *desc,
unsigned long tp_flags);

PyAPI_FUNC(int) _PyStructSequence_InitType(
PyAPI_FUNC(int) _PyStructSequence_InitBuiltinWithFlags(
PyTypeObject *type,
PyStructSequence_Desc *desc,
unsigned long tp_flags);

static inline int
_PyStructSequence_InitBuiltin(PyTypeObject *type,
PyStructSequence_Desc *desc)
{
return _PyStructSequence_InitBuiltinWithFlags(type, desc, 0);
}

extern void _PyStructSequence_FiniType(PyTypeObject *type);

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct type_cache {

extern PyStatus _PyTypes_InitSlotDefs(void);

extern int _PyStaticType_InitBuiltin(PyTypeObject *type);
extern void _PyStaticType_Dealloc(PyTypeObject *type);


Expand Down
3 changes: 3 additions & 0 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ given type object has a specified feature.

#ifndef Py_LIMITED_API

/* Track types initialized using _PyStaticType_InitBuiltin(). */
#define _Py_TPFLAGS_STATIC_BUILTIN (1 << 1)

/* Placement of dict (and values) pointers are managed by the VM, not by the type.
* The VM will automatically set tp_dictoffset. Should not be used for variable sized
* classes, such as classes that extend tuple.
Expand Down
3 changes: 1 addition & 2 deletions Objects/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -3556,8 +3556,7 @@ _PyExc_InitTypes(PyInterpreterState *interp)

for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) {
PyTypeObject *exc = static_exceptions[i].exc;

if (PyType_Ready(exc) < 0) {
if (_PyStaticType_InitBuiltin(exc) < 0) {
return -1;
}
}
Expand Down
3 changes: 2 additions & 1 deletion Objects/floatobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1992,7 +1992,8 @@ _PyFloat_InitTypes(PyInterpreterState *interp)

/* Init float info */
if (FloatInfoType.tp_name == NULL) {
if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < 0) {
if (_PyStructSequence_InitBuiltin(&FloatInfoType,
&floatinfo_desc) < 0) {
return _PyStatus_ERR("can't init float info type");
}
}
Expand Down
2 changes: 1 addition & 1 deletion Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -6135,7 +6135,7 @@ _PyLong_InitTypes(PyInterpreterState *interp)

/* initialize int_info */
if (Int_InfoType.tp_name == NULL) {
if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) {
if (_PyStructSequence_InitBuiltin(&Int_InfoType, &int_info_desc) < 0) {
return _PyStatus_ERR("can't init int info type");
}
}
Expand Down
4 changes: 2 additions & 2 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1975,8 +1975,8 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
// All other static types (unless initialized elsewhere)
for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) {
PyTypeObject *type = static_types[i];
if (PyType_Ready(type) < 0) {
return _PyStatus_ERR("Can't initialize types");
if (_PyStaticType_InitBuiltin(type) < 0) {
return _PyStatus_ERR("Can't initialize builtin type");
}
if (type == &PyType_Type) {
// Sanitify checks of the two most important types
Expand Down
122 changes: 82 additions & 40 deletions Objects/structseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,21 @@ initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict,
return -1;
}

static void
initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
Py_ssize_t n_members) {
Py_ssize_t i, k;
static PyMemberDef *
initialize_members(PyStructSequence_Desc *desc,
Py_ssize_t *pn_members, Py_ssize_t *pn_unnamed_members)
{
PyMemberDef *members;
Py_ssize_t n_members, n_unnamed_members;

n_members = count_members(desc, &n_unnamed_members);
members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
if (members == NULL) {
PyErr_NoMemory();
return NULL;
}

Py_ssize_t i, k;
for (i = k = 0; i < n_members; ++i) {
if (desc->fields[i].name == PyStructSequence_UnnamedField) {
continue;
Expand All @@ -453,30 +463,17 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
k++;
}
members[k].name = NULL;

*pn_members = n_members;
*pn_unnamed_members = n_unnamed_members;
return members;
}


int
_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
unsigned long tp_flags)
static void
initialize_static_fields(PyTypeObject *type, PyStructSequence_Desc *desc,
PyMemberDef *tp_members, unsigned long tp_flags)
{
PyMemberDef *members;
Py_ssize_t n_members, n_unnamed_members;

#ifdef Py_TRACE_REFS
/* if the type object was chained, unchain it first
before overwriting its storage */
if (type->ob_base.ob_base._ob_next) {
_Py_ForgetReference((PyObject *)type);
}
#endif

/* PyTypeObject has already been initialized */
if (Py_REFCNT(type) != 0) {
PyErr_BadInternalCall();
return -1;
}

type->tp_name = desc->name;
type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
type->tp_itemsize = sizeof(PyObject *);
Expand All @@ -488,36 +485,84 @@ _PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
type->tp_new = structseq_new;
type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
type->tp_traverse = (traverseproc) structseq_traverse;
type->tp_members = tp_members;
}

n_members = count_members(desc, &n_unnamed_members);
members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
if (members == NULL) {
PyErr_NoMemory();
return -1;
}
initialize_members(desc, members, n_members);
type->tp_members = members;

static int
initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc,
Py_ssize_t n_members, Py_ssize_t n_unnamed_members) {
/* initialize_static_fields() should have been called already. */
if (PyType_Ready(type) < 0) {
PyMem_Free(members);
return -1;
}
Py_INCREF(type);

if (initialize_structseq_dict(
desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
PyMem_Free(members);
Py_DECREF(type);
return -1;
}

return 0;
}

int
_PyStructSequence_InitBuiltinWithFlags(PyTypeObject *type,
PyStructSequence_Desc *desc,
unsigned long tp_flags)
{
PyMemberDef *members;
Py_ssize_t n_members, n_unnamed_members;

members = initialize_members(desc, &n_members, &n_unnamed_members);
if (members == NULL) {
return -1;
}
initialize_static_fields(type, desc, members, tp_flags);
if (_PyStaticType_InitBuiltin(type) < 0) {
PyMem_Free(members);
PyErr_Format(PyExc_RuntimeError,
"Can't initialize builtin type %s",
desc->name);
return -1;
}
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
PyMem_Free(members);
return -1;
}
return 0;
}

int
PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
{
return _PyStructSequence_InitType(type, desc, 0);
PyMemberDef *members;
Py_ssize_t n_members, n_unnamed_members;

#ifdef Py_TRACE_REFS
/* if the type object was chained, unchain it first
before overwriting its storage */
if (type->ob_base.ob_base._ob_next) {
_Py_ForgetReference((PyObject *)type);
}
#endif

/* PyTypeObject has already been initialized */
if (Py_REFCNT(type) != 0) {
PyErr_BadInternalCall();
return -1;
}

members = initialize_members(desc, &n_members, &n_unnamed_members);
if (members == NULL) {
return -1;
}
initialize_static_fields(type, desc, members, 0);
if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
PyMem_Free(members);
return -1;
}
return 0;
}

void
Expand Down Expand Up @@ -569,13 +614,10 @@ _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags)
Py_ssize_t n_members, n_unnamed_members;

/* Initialize MemberDefs */
n_members = count_members(desc, &n_unnamed_members);
members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
members = initialize_members(desc, &n_members, &n_unnamed_members);
if (members == NULL) {
PyErr_NoMemory();
return NULL;
}
initialize_members(desc, members, n_members);

/* Initialize Slots */
slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};
Expand Down
8 changes: 8 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -6650,6 +6650,14 @@ PyType_Ready(PyTypeObject *type)
return 0;
}

int
_PyStaticType_InitBuiltin(PyTypeObject *self)
{
self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN;

return PyType_Ready(self);
}


static int
add_subclass(PyTypeObject *base, PyTypeObject *type)
Expand Down
6 changes: 3 additions & 3 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -14604,13 +14604,13 @@ _PyUnicode_InitTypes(PyInterpreterState *interp)
return _PyStatus_OK();
}

if (PyType_Ready(&EncodingMapType) < 0) {
if (_PyStaticType_InitBuiltin(&EncodingMapType) < 0) {
goto error;
}
if (PyType_Ready(&PyFieldNameIter_Type) < 0) {
if (_PyStaticType_InitBuiltin(&PyFieldNameIter_Type) < 0) {
goto error;
}
if (PyType_Ready(&PyFormatterIter_Type) < 0) {
if (_PyStaticType_InitBuiltin(&PyFormatterIter_Type) < 0) {
goto error;
}
return _PyStatus_OK();
Expand Down
4 changes: 2 additions & 2 deletions Python/errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -1229,8 +1229,8 @@ _PyErr_InitTypes(PyInterpreterState *interp)
}

if (UnraisableHookArgsType.tp_name == NULL) {
if (PyStructSequence_InitType2(&UnraisableHookArgsType,
&UnraisableHookArgs_desc) < 0) {
if (_PyStructSequence_InitBuiltin(&UnraisableHookArgsType,
&UnraisableHookArgs_desc) < 0) {
return _PyStatus_ERR("failed to initialize UnraisableHookArgs type");
}
}
Expand Down
41 changes: 18 additions & 23 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Data members:
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
#include "pycore_pystate.h" // _PyThreadState_GET()
#include "pycore_structseq.h" // _PyStructSequence_InitType()
#include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags()
#include "pycore_tuple.h" // _PyTuple_FromArray()

#include "frameobject.h" // PyFrame_FastToLocalsWithError()
Expand Down Expand Up @@ -2921,7 +2921,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
SET_SYS("int_info", PyLong_GetInfo());
/* initialize hash_info */
if (Hash_InfoType.tp_name == NULL) {
if (PyStructSequence_InitType2(&Hash_InfoType, &hash_info_desc) < 0) {
if (_PyStructSequence_InitBuiltin(&Hash_InfoType, &hash_info_desc) < 0) {
goto type_init_failed;
}
}
Expand All @@ -2943,42 +2943,37 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)
SET_SYS_FROM_STRING("abiflags", ABIFLAGS);
#endif

#define ENSURE_INFO_TYPE(TYPE, DESC) \
do { \
if (TYPE.tp_name == NULL) { \
if (_PyStructSequence_InitBuiltinWithFlags( \
&TYPE, &DESC, Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) { \
goto type_init_failed; \
} \
} \
} while (0)

/* version_info */
if (VersionInfoType.tp_name == NULL) {
if (_PyStructSequence_InitType(&VersionInfoType,
&version_info_desc,
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
goto type_init_failed;
}
}
ENSURE_INFO_TYPE(VersionInfoType, version_info_desc);
version_info = make_version_info(tstate);
SET_SYS("version_info", version_info);

/* implementation */
SET_SYS("implementation", make_impl_info(version_info));

// sys.flags: updated in-place later by _PySys_UpdateConfig()
if (FlagsType.tp_name == 0) {
if (_PyStructSequence_InitType(&FlagsType, &flags_desc,
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
goto type_init_failed;
}
}
ENSURE_INFO_TYPE(FlagsType, flags_desc);
SET_SYS("flags", make_flags(tstate->interp));

#if defined(MS_WINDOWS)
/* getwindowsversion */
if (WindowsVersionType.tp_name == 0) {
if (_PyStructSequence_InitType(&WindowsVersionType,
&windows_version_desc,
Py_TPFLAGS_DISALLOW_INSTANTIATION) < 0) {
goto type_init_failed;
}
}
ENSURE_INFO_TYPE(WindowsVersionType, windows_version_desc);

SET_SYS_FROM_STRING("_vpath", VPATH);
#endif

#undef ENSURE_INFO_TYPE

/* float repr style: 0.03 (short) vs 0.029999999999999999 (legacy) */
#if _PY_SHORT_FLOAT_REPR == 1
SET_SYS_FROM_STRING("float_repr_style", "short");
Expand All @@ -2990,7 +2985,7 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict)

/* initialize asyncgen_hooks */
if (AsyncGenHooksType.tp_name == NULL) {
if (PyStructSequence_InitType2(
if (_PyStructSequence_InitBuiltin(
&AsyncGenHooksType, &asyncgen_hooks_desc) < 0) {
goto type_init_failed;
}
Expand Down
3 changes: 2 additions & 1 deletion Python/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ PyThread_GetInfo(void)
#endif

if (ThreadInfoType.tp_name == 0) {
if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
if (_PyStructSequence_InitBuiltin(&ThreadInfoType,
&threadinfo_desc) < 0)
return NULL;
}

Expand Down

0 comments on commit 4a1dd73

Please sign in to comment.