Skip to content

Commit ac5bbd4

Browse files
bpo-30248: Convert boolean arguments only once in _json. (#1423)
Rather than saving the Python object and calling PyObject_IsTrue() every time when the boolean argument is used, call it only once and save C boolean value.
1 parent 4a8bcdf commit ac5bbd4

File tree

1 file changed

+24
-40
lines changed

1 file changed

+24
-40
lines changed

Modules/_json.c

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ static PyTypeObject PyEncoderType;
1818

1919
typedef struct _PyScannerObject {
2020
PyObject_HEAD
21-
PyObject *strict;
21+
char strict;
2222
PyObject *object_hook;
2323
PyObject *object_pairs_hook;
2424
PyObject *parse_float;
@@ -28,7 +28,7 @@ typedef struct _PyScannerObject {
2828
} PyScannerObject;
2929

3030
static PyMemberDef scanner_members[] = {
31-
{"strict", T_OBJECT, offsetof(PyScannerObject, strict), READONLY, "strict"},
31+
{"strict", T_BOOL, offsetof(PyScannerObject, strict), READONLY, "strict"},
3232
{"object_hook", T_OBJECT, offsetof(PyScannerObject, object_hook), READONLY, "object_hook"},
3333
{"object_pairs_hook", T_OBJECT, offsetof(PyScannerObject, object_pairs_hook), READONLY},
3434
{"parse_float", T_OBJECT, offsetof(PyScannerObject, parse_float), READONLY, "parse_float"},
@@ -45,10 +45,10 @@ typedef struct _PyEncoderObject {
4545
PyObject *indent;
4646
PyObject *key_separator;
4747
PyObject *item_separator;
48-
PyObject *sort_keys;
49-
PyObject *skipkeys;
50-
PyCFunction fast_encode;
48+
char sort_keys;
49+
char skipkeys;
5150
int allow_nan;
51+
PyCFunction fast_encode;
5252
} PyEncoderObject;
5353

5454
static PyMemberDef encoder_members[] = {
@@ -58,8 +58,8 @@ static PyMemberDef encoder_members[] = {
5858
{"indent", T_OBJECT, offsetof(PyEncoderObject, indent), READONLY, "indent"},
5959
{"key_separator", T_OBJECT, offsetof(PyEncoderObject, key_separator), READONLY, "key_separator"},
6060
{"item_separator", T_OBJECT, offsetof(PyEncoderObject, item_separator), READONLY, "item_separator"},
61-
{"sort_keys", T_OBJECT, offsetof(PyEncoderObject, sort_keys), READONLY, "sort_keys"},
62-
{"skipkeys", T_OBJECT, offsetof(PyEncoderObject, skipkeys), READONLY, "skipkeys"},
61+
{"sort_keys", T_BOOL, offsetof(PyEncoderObject, sort_keys), READONLY, "sort_keys"},
62+
{"skipkeys", T_BOOL, offsetof(PyEncoderObject, skipkeys), READONLY, "skipkeys"},
6363
{NULL}
6464
};
6565

@@ -666,7 +666,6 @@ scanner_traverse(PyObject *self, visitproc visit, void *arg)
666666
PyScannerObject *s;
667667
assert(PyScanner_Check(self));
668668
s = (PyScannerObject *)self;
669-
Py_VISIT(s->strict);
670669
Py_VISIT(s->object_hook);
671670
Py_VISIT(s->object_pairs_hook);
672671
Py_VISIT(s->parse_float);
@@ -681,7 +680,6 @@ scanner_clear(PyObject *self)
681680
PyScannerObject *s;
682681
assert(PyScanner_Check(self));
683682
s = (PyScannerObject *)self;
684-
Py_CLEAR(s->strict);
685683
Py_CLEAR(s->object_hook);
686684
Py_CLEAR(s->object_pairs_hook);
687685
Py_CLEAR(s->parse_float);
@@ -692,7 +690,8 @@ scanner_clear(PyObject *self)
692690
}
693691

694692
static PyObject *
695-
_parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {
693+
_parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)
694+
{
696695
/* Read a JSON object from PyUnicode pystr.
697696
idx is the index of the first character after the opening curly brace.
698697
*next_idx_ptr is a return-by-reference index to the first character after
@@ -706,13 +705,9 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
706705
PyObject *val = NULL;
707706
PyObject *rval = NULL;
708707
PyObject *key = NULL;
709-
int strict = PyObject_IsTrue(s->strict);
710708
int has_pairs_hook = (s->object_pairs_hook != Py_None);
711709
Py_ssize_t next_idx;
712710

713-
if (strict < 0)
714-
return NULL;
715-
716711
if (PyUnicode_READY(pystr) == -1)
717712
return NULL;
718713

@@ -740,7 +735,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
740735
raise_errmsg("Expecting property name enclosed in double quotes", pystr, idx);
741736
goto bail;
742737
}
743-
key = scanstring_unicode(pystr, idx + 1, strict, &next_idx);
738+
key = scanstring_unicode(pystr, idx + 1, s->strict, &next_idx);
744739
if (key == NULL)
745740
goto bail;
746741
memokey = PyDict_GetItem(s->memo, key);
@@ -1060,7 +1055,6 @@ scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
10601055
void *str;
10611056
int kind;
10621057
Py_ssize_t length;
1063-
int strict;
10641058

10651059
if (PyUnicode_READY(pystr) == -1)
10661060
return NULL;
@@ -1081,10 +1075,7 @@ scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
10811075
switch (PyUnicode_READ(kind, str, idx)) {
10821076
case '"':
10831077
/* string */
1084-
strict = PyObject_IsTrue(s->strict);
1085-
if (strict < 0)
1086-
return NULL;
1087-
return scanstring_unicode(pystr, idx + 1, strict, next_idx_ptr);
1078+
return scanstring_unicode(pystr, idx + 1, s->strict, next_idx_ptr);
10881079
case '{':
10891080
/* object */
10901081
if (Py_EnterRecursiveCall(" while decoding a JSON object "
@@ -1197,6 +1188,7 @@ scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
11971188
{
11981189
PyScannerObject *s;
11991190
PyObject *ctx;
1191+
PyObject *strict;
12001192
static char *kwlist[] = {"context", NULL};
12011193

12021194
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:make_scanner", kwlist, &ctx))
@@ -1212,8 +1204,12 @@ scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
12121204
goto bail;
12131205

12141206
/* All of these will fail "gracefully" so we don't need to verify them */
1215-
s->strict = PyObject_GetAttrString(ctx, "strict");
1216-
if (s->strict == NULL)
1207+
strict = PyObject_GetAttrString(ctx, "strict");
1208+
if (strict == NULL)
1209+
goto bail;
1210+
s->strict = PyObject_IsTrue(strict);
1211+
Py_DECREF(strict);
1212+
if (s->strict < 0)
12171213
goto bail;
12181214
s->object_hook = PyObject_GetAttrString(ctx, "object_hook");
12191215
if (s->object_hook == NULL)
@@ -1290,10 +1286,10 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
12901286

12911287
PyEncoderObject *s;
12921288
PyObject *markers, *defaultfn, *encoder, *indent, *key_separator;
1293-
PyObject *item_separator, *sort_keys, *skipkeys;
1294-
int allow_nan;
1289+
PyObject *item_separator;
1290+
int sort_keys, skipkeys, allow_nan;
12951291

1296-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOUUOOp:make_encoder", kwlist,
1292+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOUUppp:make_encoder", kwlist,
12971293
&markers, &defaultfn, &encoder, &indent,
12981294
&key_separator, &item_separator,
12991295
&sort_keys, &skipkeys, &allow_nan))
@@ -1318,6 +1314,7 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
13181314
s->item_separator = item_separator;
13191315
s->sort_keys = sort_keys;
13201316
s->skipkeys = skipkeys;
1317+
s->allow_nan = allow_nan;
13211318
s->fast_encode = NULL;
13221319
if (PyCFunction_Check(s->encoder)) {
13231320
PyCFunction f = PyCFunction_GetFunction(s->encoder);
@@ -1326,16 +1323,13 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
13261323
s->fast_encode = f;
13271324
}
13281325
}
1329-
s->allow_nan = allow_nan;
13301326

13311327
Py_INCREF(s->markers);
13321328
Py_INCREF(s->defaultfn);
13331329
Py_INCREF(s->encoder);
13341330
Py_INCREF(s->indent);
13351331
Py_INCREF(s->key_separator);
13361332
Py_INCREF(s->item_separator);
1337-
Py_INCREF(s->sort_keys);
1338-
Py_INCREF(s->skipkeys);
13391333
return (PyObject *)s;
13401334
}
13411335

@@ -1551,8 +1545,6 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
15511545
PyObject *it = NULL;
15521546
PyObject *items;
15531547
PyObject *item = NULL;
1554-
int skipkeys;
1555-
int sortkeys;
15561548
Py_ssize_t idx;
15571549

15581550
if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) {
@@ -1597,16 +1589,12 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
15971589
items = PyMapping_Items(dct);
15981590
if (items == NULL)
15991591
goto bail;
1600-
sortkeys = PyObject_IsTrue(s->sort_keys);
1601-
if (sortkeys < 0 || (sortkeys && PyList_Sort(items) < 0))
1592+
if (s->sort_keys && PyList_Sort(items) < 0)
16021593
goto bail;
16031594
it = PyObject_GetIter(items);
16041595
Py_DECREF(items);
16051596
if (it == NULL)
16061597
goto bail;
1607-
skipkeys = PyObject_IsTrue(s->skipkeys);
1608-
if (skipkeys < 0)
1609-
goto bail;
16101598
idx = 0;
16111599
while ((item = PyIter_Next(it)) != NULL) {
16121600
PyObject *encoded, *key, *value;
@@ -1637,7 +1625,7 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
16371625
goto bail;
16381626
}
16391627
}
1640-
else if (skipkeys) {
1628+
else if (s->skipkeys) {
16411629
Py_DECREF(item);
16421630
continue;
16431631
}
@@ -1805,8 +1793,6 @@ encoder_traverse(PyObject *self, visitproc visit, void *arg)
18051793
Py_VISIT(s->indent);
18061794
Py_VISIT(s->key_separator);
18071795
Py_VISIT(s->item_separator);
1808-
Py_VISIT(s->sort_keys);
1809-
Py_VISIT(s->skipkeys);
18101796
return 0;
18111797
}
18121798

@@ -1823,8 +1809,6 @@ encoder_clear(PyObject *self)
18231809
Py_CLEAR(s->indent);
18241810
Py_CLEAR(s->key_separator);
18251811
Py_CLEAR(s->item_separator);
1826-
Py_CLEAR(s->sort_keys);
1827-
Py_CLEAR(s->skipkeys);
18281812
return 0;
18291813
}
18301814

0 commit comments

Comments
 (0)