Skip to content

Commit 5e41a26

Browse files
cmaloneyclaude
andcommitted
gh-87613: Use AC vectorcall for bool
Move bool.__new__ to Argument Clinic with @vectorcall, dropping the hand-written bool_new and bool_vectorcall. The generated vectorcall name matches the hand-written one so the tp_vectorcall slot is unchanged, and argument error messages are unchanged on both paths. pyperf microbenchmark (PGO+LTO, run serially), no significant change on the vectorcall path: | Benchmark | base | bool | |----------------|:-------:|:---------------------:| | bool.__new__ | 23.0 ns | 21.7 ns: 1.06x faster | | bool() | 10.1 ns | 10.4 ns: 1.03x slower | | bool(int) | 12.2 ns | 12.6 ns: 1.03x slower | | bool(True) | 11.1 ns | 11.4 ns: 1.03x slower | | Geometric mean | (ref) | 1.00x slower | Benchmark hidden because not significant (2): bool(__bool__), bool(list) Instructions per call (callgrind, inclusive of bool_vectorcall or bool_new, PGO+LTO): | Case | base | bool | delta | |-----------------------|-----:|-----:|------:| | bool() | 17 | 18 | +1 | | bool(True) | 20 | 23 | +3 | | bool(12345) | 53 | 49 | -4 | | bool([1]) | 50 | 47 | -3 | | bool.__new__(bool, 1) | 127 | 69 | -58 | The compiler folds PyObject_IsTrue(Py_False) for bool(), so the default costs nothing; the small deltas are register allocation. bool.__new__ drops PyArg_UnpackTuple for inline clinic parsing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 6c695bf commit 5e41a26

2 files changed

Lines changed: 96 additions & 44 deletions

File tree

‎Objects/boolobject.c‎

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22

33
#include "Python.h"
44
#include "pycore_long.h" // FALSE_TAG TRUE_TAG
5-
#include "pycore_modsupport.h" // _PyArg_NoKwnames()
65
#include "pycore_object.h" // _Py_FatalRefcountError()
76
#include "pycore_runtime.h" // _Py_ID()
87

98
#include <stddef.h>
109

10+
/*[clinic input]
11+
class bool "PyObject *" "&PyBool_Type"
12+
[clinic start generated code]*/
13+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ee492546880a882f]*/
14+
15+
#include "clinic/boolobject.c.h"
16+
1117
/* We define bool_repr to return "False" or "True" */
1218

1319
static PyObject *
@@ -23,45 +29,28 @@ PyObject *PyBool_FromLong(long ok)
2329
return ok ? Py_True : Py_False;
2430
}
2531

26-
/* We define bool_new to always return either Py_True or Py_False */
32+
/*[clinic input]
33+
@vectorcall
34+
@classmethod
35+
bool.__new__ as bool_new
36+
object as x: object = False
37+
/
2738
28-
static PyObject *
29-
bool_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
30-
{
31-
PyObject *x = Py_False;
32-
long ok;
39+
Returns True when the argument is true, False otherwise.
3340
34-
if (!_PyArg_NoKeywords("bool", kwds))
35-
return NULL;
36-
if (!PyArg_UnpackTuple(args, "bool", 0, 1, &x))
37-
return NULL;
38-
ok = PyObject_IsTrue(x);
39-
if (ok < 0)
40-
return NULL;
41-
return PyBool_FromLong(ok);
42-
}
41+
The builtins True and False are the only two instances of the class
42+
bool. The class bool is a subclass of the class int, and cannot be
43+
subclassed.
44+
[clinic start generated code]*/
4345

4446
static PyObject *
45-
bool_vectorcall(PyObject *type, PyObject * const*args,
46-
size_t nargsf, PyObject *kwnames)
47+
bool_new_impl(PyTypeObject *type, PyObject *x)
48+
/*[clinic end generated code: output=ec434408d43a3773 input=d96e25fce5a04f73]*/
4749
{
48-
long ok = 0;
49-
if (!_PyArg_NoKwnames("bool", kwnames)) {
50-
return NULL;
51-
}
52-
53-
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
54-
if (!_PyArg_CheckPositional("bool", nargs, 0, 1)) {
50+
int ok = PyObject_IsTrue(x);
51+
if (ok < 0) {
5552
return NULL;
5653
}
57-
58-
assert(PyType_Check(type));
59-
if (nargs) {
60-
ok = PyObject_IsTrue(args[0]);
61-
if (ok < 0) {
62-
return NULL;
63-
}
64-
}
6554
return PyBool_FromLong(ok);
6655
}
6756

@@ -107,16 +96,6 @@ bool_xor(PyObject *a, PyObject *b)
10796
return PyBool_FromLong((a == Py_True) ^ (b == Py_True));
10897
}
10998

110-
/* Doc string */
111-
112-
PyDoc_STRVAR(bool_doc,
113-
"bool(object=False, /)\n\
114-
--\n\
115-
\n\
116-
Returns True when the argument is true, False otherwise.\n\
117-
The builtins True and False are the only two instances of the class bool.\n\
118-
The class bool is a subclass of the class int, and cannot be subclassed.");
119-
12099
/* Arithmetic methods -- only so we can override &, |, ^. */
121100

122101
static PyNumberMethods bool_as_number = {
@@ -189,7 +168,7 @@ PyTypeObject PyBool_Type = {
189168
0, /* tp_setattro */
190169
0, /* tp_as_buffer */
191170
Py_TPFLAGS_DEFAULT, /* tp_flags */
192-
bool_doc, /* tp_doc */
171+
bool_new__doc__, /* tp_doc */
193172
0, /* tp_traverse */
194173
0, /* tp_clear */
195174
0, /* tp_richcompare */

‎Objects/clinic/boolobject.c.h‎

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

0 commit comments

Comments
 (0)