Skip to content

gh-87613: Use AC vectorcall for weakref.ref() - #159470

Open
eendebakpt wants to merge 5 commits into
python:mainfrom
eendebakpt:weakref-vectorcall
Open

eendebakpt wants to merge 5 commits into
python:mainfrom
eendebakpt:weakref-vectorcall

Conversation

@eendebakpt

@eendebakpt eendebakpt commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Convert weakref.ref.__new__ to Argument Clinic with the @vectorcall decorator. weakref.ref.__init__, which only validates the arguments that __new__ already consumed, is converted to Argument Clinic as well. This will also improve the signature of weakref.ref.

+------------------------------+---------------+-----------------------+
| Benchmark                    | weakref_base3 | weakref_patch3        |
+==============================+===============+=======================+
| ref(o)                       | 116 ns        | 89.1 ns: 1.31x faster |
+------------------------------+---------------+-----------------------+
| ref(O())                     | 183 ns        | 172 ns: 1.07x faster  |
+------------------------------+---------------+-----------------------+
| ref(o, cb)                   | 121 ns        | 77.9 ns: 1.55x faster |
+------------------------------+---------------+-----------------------+
| o in WeakSet                 | 287 ns        | 216 ns: 1.32x faster  |
+------------------------------+---------------+-----------------------+
| WeakSet.add; WeakSet.discard | 424 ns        | 324 ns: 1.31x faster  |
+------------------------------+---------------+-----------------------+
| Geometric mean               | (ref)         | 1.30x faster          |
+------------------------------+---------------+-----------------------+
Benchmark script
import pyperf
runner = pyperf.Runner()
setup = """
from weakref import ref, WeakSet
class O: pass
o = O()
cb = lambda r: None
ws = WeakSet()
ws.add(o)
"""
runner.timeit("ref(o)", "ref(o)", setup)
runner.timeit("ref(O())", "ref(O())", setup)
runner.timeit("ref(o, cb)", "ref(o, cb)", setup)
runner.timeit("o in WeakSet", "o in ws", setup)
runner.timeit("WeakSet.add; WeakSet.discard", "ws.add(o); ws.discard(o)", setup)

Generated with help from Claude Code

eendebakpt and others added 3 commits October 15, 2026 11:55
Convert weakref.ref.__new__ to Argument Clinic with the @vectorcall
decorator so that creating a weak reference no longer builds an argument
tuple that is then unpacked twice (by __new__ and by __init__), and so
that the call can be specialized as CALL_BUILTIN_CLASS.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
It only validates the arguments that __new__ already consumed, so the
generated parser replaces the PyArg_UnpackTuple call and the arity
error message now matches the one from __new__.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Name the Argument Clinic class after tp_name (weakref.ReferenceType) so
that the generated docstring's signature line is recognised, which makes
help(weakref.ref) show the signature and inspect.signature() work. The
argument errors now name ReferenceType instead of ref/__new__/__init__.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cmaloney cmaloney left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. Not a ton of usage but some in the import machinery which will help startup a bit. Have been looking at similar for some common decorators.

Comment thread Objects/weakrefobject.c Outdated
eendebakpt and others added 2 commits October 23, 2026 21:06
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts:
#	Objects/clinic/weakrefobject.c.h
#	Objects/weakrefobject.c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review type-feature A feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants