10000 bpo-41073: PyType_GetSlot() can now accept static types. (GH-21931) · python/cpython@a13b26c · GitHub
[go: up one dir, main page]

Skip to content

Commit a13b26c

Browse files
authored
bpo-41073: PyType_GetSlot() can now accept static types. (GH-21931)
PyType_GetSlot() can now accept static types. Co-Authored-By: Petr Viktorin <encukou@gmail.com> Automerge-Triggered-By: GH:encukou
1 parent ace3f9a commit a13b26c

File tree

7 files changed

+205
-101
lines changed

7 files changed

+205
-101
lines changed

Doc/c-api/type.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,12 @@ Type Objects
105105
106106
See :c:member:`PyType_Slot.slot` for possible values of the *slot* argument.
107107
108-
An exception is raised if *type* is not a heap type.
109-
110108
.. versionadded:: 3.4
111109
110+
.. versionchanged:: 3.10
111+
:c:func:`PyType_GetSlot` can now accept all types.
112+
Previously, it was limited to heap types.
113+
112114
.. c:function:: PyObject* PyType_GetModule(PyTypeObject *type)
113115
114116
Return the module object associated with the given type when the type was

Doc/whatsnew/3.10.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,9 @@ New Features
436436
slot.
437437
(Contributed by Hai Shi in :issue:`41832`.)
438438

439+
* The :c:func:`PyType_GetSlot` function can accept static types.
440+
(Contributed by Hai Shi and Petr Viktorin in :issue:`41073`.)
441+
439442

440443
Porting to Python 3.10
441444
----------------------
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:c:func:`PyType_GetSlot()` can now accept static types.

Modules/_testcapimodule.c

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,62 @@ test_buildvalue_N(PyObject *self, PyObject *Py_UNUSED(ignored))
10181018
}
10191019

10201020

1021+
static PyObject *
1022+
test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored))
1023+
{
1024+
newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new);
1025+
if (PyLong_Type.tp_new != tp_new) {
1026+
PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long");
1027+
return NULL;
1028+
}
1029+
1030+
reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr);
1031+
if (PyLong_Type.tp_repr != tp_repr) {
1032+
PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long");
1033+
return NULL;
1034+
}
1035+
1036+
ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call);
1037+
if (tp_call != NULL) {
1038+
PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long");
1039+
return NULL;
1040+
}
1041+
1042+
binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add);
1043+
if (PyLong_Type.tp_as_number->nb_add != nb_add) {
1044+
PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long");
1045+
return NULL;
1046+
}
1047+
1048+
lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length);
1049+
if (mp_length != NULL) {
1050+
PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long");
1051+
return NULL;
1052+
}
1053+
1054+
void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1);
1055+
if (over_value != NULL) {
1056+
PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long");
1057+
return NULL;
1058+
}
1059+
1060+
tp_new = PyType_GetSlot(&PyLong_Type, 0);
1061+
if (tp_new != NULL) {
1062+
PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long");
1063+
return NULL;
1064+
}
1065+
if (PyErr_ExceptionMatches(PyExc_SystemError)) {
1066+
// This is the right exception
1067+
PyErr_Clear();
< F438 code>1068+
}
1069+
else {
1070+
return NULL;
1071+
}
1072+
1073+
Py_RETURN_NONE;
1074+
}
1075+
1076+
10211077
static PyObject *
10221078
get_args(PyObject *self, PyObject *args)
10231079
{
@@ -5627,8 +5683,10 @@ static PyMethodDef TestMethods[] = {
56275683
{"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS},
56285684
{"test_buildvalue_N", test_buildvalue_N, METH_NOARGS},
56295685
{"test_buildvalue_issue38913", test_buildvalue_issue38913, METH_NOARGS},
5630-
{"get_args", get_args, METH_VARARGS},
5631-
{"get_kwargs", (PyCFunction)(void(*)(void))get_kwargs, METH_VARARGS|METH_KEYWORDS},
5686+
{"get_args", get_args, METH_VARARGS},
5687+
{"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS},
5688+
{"get_kwargs", (PyCFunction)(void(*)(void))get_kwargs,
5689+
METH_VARARGS|METH_KEYWORDS},
56325690
{"getargs_tuple", getargs_tuple, METH_VARARGS},
56335691
{"getargs_keywords", (PyCFunction)(void(*)(void))getargs_keywords,
56345692
METH_VARARGS|METH_KEYWORDS},

Objects/typeobject.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP];
5656
static unsigned int next_version_tag = 0;
5757
#endif
5858

59+
typedef struct PySlot_Offset {
60+
short subslot_offset;
61+
short slot_offset;
62+
} PySlot_Offset;
63+
5964
#define MCACHE_STATS 0
6065

6166
#if MCACHE_STATS
@@ -2870,8 +2875,18 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
28702875
return NULL;
28712876
}
28722877

2873-
static const short slotoffsets[] = {
2874-
-1, /* invalid slot */
2878+
/* An array of type slot offsets corresponding to Py_tp_* constants,
2879+
* for use in e.g. PyType_Spec and PyType_GetSlot.
2880+
* Each entry has two offsets: "slot_offset" and "subslot_offset".
2881+
* If is subslot_offset is -1, slot_offset is an offset within the
2882+
* PyTypeObject struct.
2883+
* Otherwise slot_offset is an offset to a pointer to a sub-slots struct
2884+
* (such as "tp_as_number"), and subslot_offset is the offset within
2885+
* that struct.
2886+
* The actual table is generated by a script.
2887+
*/
2888+
static const PySlot_Offset pyslot_offsets[] = {
2889+
{0, 0},
28752890
#include "typeslots.inc"
28762891
};
28772892

@@ -2892,6 +2907,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
28922907
const PyType_Slot *slot;
28932908
Py_ssize_t nmembers, weaklistoffset, dictoffset, vectorcalloffset;
28942909
char *res_start;
2910+
short slot_offset, subslot_offset;
28952911

28962912
nmembers = weaklistoffset = dictoffset = vectorcalloffset = 0;
28972913
for (slot = spec->slots; slot->slot; slot++) {
@@ -3001,7 +3017,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
30013017

30023018
for (slot = spec->slots; slot->slot; slot++) {
30033019
if (slot->slot < 0
3004-
|| (size_t)slot->slot >= Py_ARRAY_LENGTH(slotoffsets)) {
3020+
|| (size_t)slot->slot >= Py_ARRAY_LENGTH(pyslot_offsets)) {
30053021
PyErr_SetString(PyExc_RuntimeError, "invalid slot offset");
30063022
goto fail;
30073023
}
@@ -3034,7 +3050,15 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
30343050
}
30353051
else {
30363052
/* Copy other slots directly */
3037-
*(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
3053+
PySlot_Offset slotoffsets = pyslot_offsets[slot->slot];
3054+
slot_offset = slotoffsets.slot_offset;
3055+
if (slotoffsets.subslot_offset == -1) {
3056+
*(void**)((char*)res_start + slot_offset) = slot->pfunc;
3057+
} else {
3058+
void *parent_slot = *(void**)((char*)res_start + slot_offset);
3059+
subslot_offset = slotoffsets.subslot_offset;
3060+
*(void**)((char*)parent_slot + subslot_offset) = slot->pfunc;
3061+
}
30383062
}
30393063
}
30403064
if (type->tp_dealloc == NULL) {
@@ -3117,15 +3141,23 @@ PyType_FromSpec(PyType_Spec *spec)
31173141
void *
31183142
PyType_GetSlot(PyTypeObject *type, int slot)
31193143
{
3120-
if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0) {
3144+
void *parent_slot;
3145+
int slots_len = Py_ARRAY_LENGTH(pyslot_offsets);
3146+
3147+
if (slot <= 0 || slot >= slots_len) {
31213148
PyErr_BadInternalCall();
31223149
return NULL;
31233150
}
3124-
if ((size_t)slot >= Py_ARRAY_LENGTH(slotoffsets)) {
3125-
/* Extension module requesting slot from a future version */
3151+
3152+
parent_slot = *(void**)((char*)type + pyslot_offsets[slot].slot_offset);
3153+
if (parent_slot == NULL) {
31263154
return NULL;
31273155
}
3128-
return *(void**)(((char*)type) + slotoffsets[slot]);
3156+
/* Return slot directly if we have no sub slot. */
3157+
if (pyslot_offsets[slot].subslot_offset == -1) {
3158+
return parent_slot;
3159+
}
3160+
return *(void**)((char*)parent_slot + pyslot_offsets[slot].subslot_offset);
31293161
}
31303162

31313163
PyObject *

Objects/typeslots.inc

Lines changed: 81 additions & 81 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
0