Skip to content

Commit 76dc047

Browse files
authored
bpo-46481: Implement vectorcall for weakref.ref.__call__ method. (GH-30820)
1 parent 1f715d5 commit 76dc047

File tree

4 files changed

+35
-52
lines changed

4 files changed

+35
-52
lines changed

Include/cpython/weakrefobject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct _PyWeakReference {
2929
*/
3030
PyWeakReference *wr_prev;
3131
PyWeakReference *wr_next;
32+
vectorcallfunc vectorcall;
3233
};
3334

3435
PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head);

Lib/test/test_sys.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,11 +1538,11 @@ class newstyleclass(object): pass
15381538
# TODO: add check that forces layout of unicodefields
15391539
# weakref
15401540
import weakref
1541-
check(weakref.ref(int), size('2Pn2P'))
1541+
check(weakref.ref(int), size('2Pn3P'))
15421542
# weakproxy
15431543
# XXX
15441544
# weakcallableproxy
1545-
check(weakref.proxy(int), size('2Pn2P'))
1545+
check(weakref.proxy(int), size('2Pn3P'))
15461546

15471547
def check_slots(self, obj, base, extra):
15481548
expected = sys.getsizeof(base) + struct.calcsize(extra)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up calls to :meth:`weakref.ref.__call__` by using the :pep:`590`
2+
``vectorcall`` calling convention. Patch by Dong-hee Na.

Objects/weakrefobject.c

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ _PyWeakref_GetWeakrefCount(PyWeakReference *head)
1919
return count;
2020
}
2121

22+
static PyObject *weakref_vectorcall(PyWeakReference *self, PyObject *const *args, size_t nargsf, PyObject *kwnames);
2223

2324
static void
2425
init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
@@ -27,8 +28,8 @@ init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
2728
self->wr_object = ob;
2829
self->wr_prev = NULL;
2930
self->wr_next = NULL;
30-
Py_XINCREF(callback);
31-
self->wr_callback = callback;
31+
self->wr_callback = Py_XNewRef(callback);
32+
self->vectorcall = (vectorcallfunc)weakref_vectorcall;
3233
}
3334

3435
static PyWeakReference *
@@ -128,19 +129,19 @@ gc_clear(PyWeakReference *self)
128129

129130

130131
static PyObject *
131-
weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
132+
weakref_vectorcall(PyWeakReference *self, PyObject *const *args,
133+
size_t nargsf, PyObject *kwnames)
132134
{
133-
static char *kwlist[] = {NULL};
134-
135-
if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
136-
PyObject *object = PyWeakref_GET_OBJECT(self);
137-
Py_INCREF(object);
138-
return (object);
135+
if (!_PyArg_NoKwnames("weakref", kwnames)) {
136+
return NULL;
137+
}
138+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
139+
if (!_PyArg_CheckPositional("weakref", nargs, 0, 0)) {
140+
return NULL;
139141
}
140-
return NULL;
142+
return Py_NewRef(PyWeakref_GET_OBJECT(self));
141143
}
142144

143-
144145
static Py_hash_t
145146
weakref_hash(PyWeakReference *self)
146147
{
@@ -371,45 +372,24 @@ static PyMethodDef weakref_methods[] = {
371372
PyTypeObject
372373
_PyWeakref_RefType = {
373374
PyVarObject_HEAD_INIT(&PyType_Type, 0)
374-
"weakref",
375-
sizeof(PyWeakReference),
376-
0,
377-
weakref_dealloc, /*tp_dealloc*/
378-
0, /*tp_vectorcall_offset*/
379-
0, /*tp_getattr*/
380-
0, /*tp_setattr*/
381-
0, /*tp_as_async*/
382-
(reprfunc)weakref_repr, /*tp_repr*/
383-
0, /*tp_as_number*/
384-
0, /*tp_as_sequence*/
385-
0, /*tp_as_mapping*/
386-
(hashfunc)weakref_hash, /*tp_hash*/
387-
(ternaryfunc)weakref_call, /*tp_call*/
388-
0, /*tp_str*/
389-
0, /*tp_getattro*/
390-
0, /*tp_setattro*/
391-
0, /*tp_as_buffer*/
392-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
393-
| Py_TPFLAGS_BASETYPE, /*tp_flags*/
394-
0, /*tp_doc*/
395-
(traverseproc)gc_traverse, /*tp_traverse*/
396-
(inquiry)gc_clear, /*tp_clear*/
397-
(richcmpfunc)weakref_richcompare, /*tp_richcompare*/
398-
0, /*tp_weaklistoffset*/
399-
0, /*tp_iter*/
400-
0, /*tp_iternext*/
401-
weakref_methods, /*tp_methods*/
402-
weakref_members, /*tp_members*/
403-
0, /*tp_getset*/
404-
0, /*tp_base*/
405-
0, /*tp_dict*/
406-
0, /*tp_descr_get*/
407-
0, /*tp_descr_set*/
408-
0, /*tp_dictoffset*/
409-
weakref___init__, /*tp_init*/
410-
PyType_GenericAlloc, /*tp_alloc*/
411-
weakref___new__, /*tp_new*/
412-
PyObject_GC_Del, /*tp_free*/
375+
.tp_name = "weakref",
376+
.tp_basicsize = sizeof(PyWeakReference),
377+
.tp_dealloc = weakref_dealloc,
378+
.tp_vectorcall_offset = offsetof(PyWeakReference, vectorcall),
379+
.tp_call = PyVectorcall_Call,
380+
.tp_repr = (reprfunc)weakref_repr,
381+
.tp_hash = (hashfunc)weakref_hash,
382+
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
383+
Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE,
384+
.tp_traverse = (traverseproc)gc_traverse,
385+
.tp_clear = (inquiry)gc_clear,
386+
.tp_richcompare = (richcmpfunc)weakref_richcompare,
387+
.tp_methods = weakref_methods,
388+
.tp_members = weakref_members,
389+
.tp_init = weakref___init__,
390+
.tp_alloc = PyType_GenericAlloc,
391+
.tp_new = weakref___new__,
392+
.tp_free = PyObject_GC_Del,
413393
};
414394

415395

0 commit comments

Comments
 (0)