Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-94673: Add _PyStaticType_InitBuiltin() #95152

Merged
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
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) {
ericsnowcurrently marked this conversation as resolved.
Show resolved Hide resolved
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