Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Include/internal/pycore_pyatomic_ft_wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ extern "C" {
_Py_atomic_load_ullong_relaxed(&value)
#define FT_ATOMIC_ADD_SSIZE(value, new_value) \
(void)_Py_atomic_add_ssize(&value, new_value)
#define FT_MUTEX_LOCK(lock) PyMutex_Lock(lock)
#define FT_MUTEX_UNLOCK(lock) PyMutex_Unlock(lock)

#else
#define FT_ATOMIC_LOAD_PTR(value) value
Expand Down Expand Up @@ -159,6 +161,8 @@ extern "C" {
#define FT_ATOMIC_LOAD_ULLONG_RELAXED(value) value
#define FT_ATOMIC_STORE_ULLONG_RELAXED(value, new_value) value = new_value
#define FT_ATOMIC_ADD_SSIZE(value, new_value) (void)(value += new_value)
#define FT_MUTEX_LOCK(lock) do {} while (0)
#define FT_MUTEX_UNLOCK(lock) do {} while (0)

#endif

Expand Down
1 change: 0 additions & 1 deletion Lib/asyncio/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,6 @@ def connection_lost(self, exc):
self._closed.set_exception(exc)
super().connection_lost(exc)
self._stream_reader_wr = None
self._stream_writer = None
self._task = None
self._transport = None

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:mod:`json` now encodes strings up to 2.2x faster if they consist solely of characters that don’t require escaping.
15 changes: 5 additions & 10 deletions Modules/_ctypes/malloc_closure.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@

#ifdef Py_GIL_DISABLED
static PyMutex malloc_closure_lock;
# define MALLOC_CLOSURE_LOCK() PyMutex_Lock(&malloc_closure_lock)
# define MALLOC_CLOSURE_UNLOCK() PyMutex_Unlock(&malloc_closure_lock)
#else
# define MALLOC_CLOSURE_LOCK() ((void)0)
# define MALLOC_CLOSURE_UNLOCK() ((void)0)
#endif

typedef union _tagITEM {
Expand Down Expand Up @@ -120,11 +115,11 @@ void Py_ffi_closure_free(void *p)
}
#endif
#endif
MALLOC_CLOSURE_LOCK();
FT_MUTEX_LOCK(&malloc_closure_lock);
ITEM *item = (ITEM *)p;
item->next = free_list;
free_list = item;
MALLOC_CLOSURE_UNLOCK();
FT_MUTEX_UNLOCK(&malloc_closure_lock);
}

/* return one item from the free list, allocating more if needed */
Expand All @@ -143,13 +138,13 @@ void *Py_ffi_closure_alloc(size_t size, void** codeloc)
}
#endif
#endif
MALLOC_CLOSURE_LOCK();
FT_MUTEX_LOCK(&malloc_closure_lock);
ITEM *item;
if (!free_list) {
more_core();
}
if (!free_list) {
MALLOC_CLOSURE_UNLOCK();
FT_MUTEX_UNLOCK(&malloc_closure_lock);
return NULL;
}
item = free_list;
Expand All @@ -160,6 +155,6 @@ void *Py_ffi_closure_alloc(size_t size, void** codeloc)
#else
*codeloc = (void *)item;
#endif
MALLOC_CLOSURE_UNLOCK();
FT_MUTEX_UNLOCK(&malloc_closure_lock);
return (void *)item;
}
188 changes: 144 additions & 44 deletions Modules/_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ typedef struct _PyEncoderObject {
char sort_keys;
char skipkeys;
int allow_nan;
PyCFunction fast_encode;
int (*fast_encode)(PyUnicodeWriter *, PyObject *);
} PyEncoderObject;

#define PyEncoderObject_CAST(op) ((PyEncoderObject *)(op))
Expand Down Expand Up @@ -102,8 +102,10 @@ static PyObject *
_encoded_const(PyObject *obj);
static void
raise_errmsg(const char *msg, PyObject *s, Py_ssize_t end);
static PyObject *
encoder_encode_string(PyEncoderObject *s, PyObject *obj);
static int
_steal_accumulate(PyUnicodeWriter *writer, PyObject *stolen);
static int
encoder_write_string(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *obj);
static PyObject *
encoder_encode_float(PyEncoderObject *s, PyObject *obj);

Expand Down Expand Up @@ -146,22 +148,11 @@ ascii_escape_unichar(Py_UCS4 c, unsigned char *output, Py_ssize_t chars)
return chars;
}

static PyObject *
ascii_escape_unicode(PyObject *pystr)
static Py_ssize_t
ascii_escape_size(const void *input, int kind, Py_ssize_t input_chars)
{
/* Take a PyUnicode pystr and return a new ASCII-only escaped PyUnicode */
Py_ssize_t i;
Py_ssize_t input_chars;
Py_ssize_t output_size;
Py_ssize_t chars;
PyObject *rval;
const void *input;
Py_UCS1 *output;
int kind;

input_chars = PyUnicode_GET_LENGTH(pystr);
input = PyUnicode_DATA(pystr);
kind = PyUnicode_KIND(pystr);

/* Compute the output size */
for (i = 0, output_size = 2; i < input_chars; i++) {
Expand All @@ -181,11 +172,22 @@ ascii_escape_unicode(PyObject *pystr)
}
if (output_size > PY_SSIZE_T_MAX - d) {
PyErr_SetString(PyExc_OverflowError, "string is too long to escape");
return NULL;
return -1;
}
output_size += d;
}

return output_size;
}

static PyObject *
ascii_escape_unicode_and_size(const void *input, int kind, Py_ssize_t input_chars, Py_ssize_t output_size)
{
Py_ssize_t i;
Py_ssize_t chars;
PyObject *rval;
Py_UCS1 *output;

rval = PyUnicode_New(output_size, 127);
if (rval == NULL) {
return NULL;
Expand All @@ -210,23 +212,62 @@ ascii_escape_unicode(PyObject *pystr)
}

static PyObject *
escape_unicode(PyObject *pystr)
ascii_escape_unicode(PyObject *pystr)
{
/* Take a PyUnicode pystr and return a new ASCII-only escaped PyUnicode */
Py_ssize_t input_chars = PyUnicode_GET_LENGTH(pystr);
const void *input = PyUnicode_DATA(pystr);
int kind = PyUnicode_KIND(pystr);

Py_ssize_t output_size = ascii_escape_size(input, kind, input_chars);
if (output_size < 0) {
return NULL;
}

return ascii_escape_unicode_and_size(input, kind, input_chars, output_size);
}

static int
write_escaped_ascii(PyUnicodeWriter *writer, PyObject *pystr)
{
/* Take a PyUnicode pystr and return a new escaped PyUnicode */
Py_ssize_t i;
Py_ssize_t input_chars;
Py_ssize_t output_size;
Py_ssize_t chars;
PyObject *rval;
const void *input;
int kind;
Py_UCS4 maxchar;

maxchar = PyUnicode_MAX_CHAR_VALUE(pystr);
input_chars = PyUnicode_GET_LENGTH(pystr);
input = PyUnicode_DATA(pystr);
kind = PyUnicode_KIND(pystr);

Py_ssize_t output_size = ascii_escape_size(input, kind, input_chars);
if (output_size < 0) {
return -1;
}

if (output_size == input_chars + 2) {
/* No need to escape anything */
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
return -1;
}
if (PyUnicodeWriter_WriteStr(writer, pystr) < 0) {
return -1;
}
return PyUnicodeWriter_WriteChar(writer, '"');
}

PyObject *rval = ascii_escape_unicode_and_size(input, kind, input_chars, output_size);
if (rval == NULL) {
return -1;
}

return _steal_accumulate(writer, rval);
}

static Py_ssize_t
escape_size(const void *input, int kind, Py_ssize_t input_chars)
{
Py_ssize_t i;
Py_ssize_t output_size;

/* Compute the output size */
for (i = 0, output_size = 2; i < input_chars; i++) {
Py_UCS4 c = PyUnicode_READ(kind, input, i);
Expand All @@ -244,11 +285,21 @@ escape_unicode(PyObject *pystr)
}
if (output_size > PY_SSIZE_T_MAX - d) {
PyErr_SetString(PyExc_OverflowError, "string is too long to escape");
return NULL;
return -1;
}
output_size += d;
}

return output_size;
}

static PyObject *
escape_unicode_and_size(const void *input, int kind, Py_UCS4 maxchar, Py_ssize_t input_chars, Py_ssize_t output_size)
{
Py_ssize_t i;
Py_ssize_t chars;
PyObject *rval;

rval = PyUnicode_New(output_size, maxchar);
if (rval == NULL)
return NULL;
Expand Down Expand Up @@ -303,6 +354,55 @@ escape_unicode(PyObject *pystr)
return rval;
}

static PyObject *
escape_unicode(PyObject *pystr)
{
/* Take a PyUnicode pystr and return a new escaped PyUnicode */
Py_ssize_t input_chars = PyUnicode_GET_LENGTH(pystr);
const void *input = PyUnicode_DATA(pystr);
int kind = PyUnicode_KIND(pystr);
Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(pystr);

Py_ssize_t output_size = escape_size(input, kind, input_chars);
if (output_size < 0) {
return NULL;
}

return escape_unicode_and_size(input, kind, maxchar, input_chars, output_size);
}

static int
write_escaped_unicode(PyUnicodeWriter *writer, PyObject *pystr)
{
Py_ssize_t input_chars = PyUnicode_GET_LENGTH(pystr);
const void *input = PyUnicode_DATA(pystr);
int kind = PyUnicode_KIND(pystr);
Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(pystr);

Py_ssize_t output_size = escape_size(input, kind, input_chars);
if (output_size < 0) {
return -1;
}

if (output_size == input_chars + 2) {
/* No need to escape anything */
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
return -1;
}
if (PyUnicodeWriter_WriteStr(writer, pystr) < 0) {
return -1;
}
return PyUnicodeWriter_WriteChar(writer, '"');
}

PyObject *rval = escape_unicode_and_size(input, kind, maxchar, input_chars, output_size);
if (rval == NULL) {
return -1;
}

return _steal_accumulate(writer, rval);
}

static void
raise_errmsg(const char *msg, PyObject *s, Py_ssize_t end)
{
Expand Down Expand Up @@ -1256,8 +1356,11 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)

if (PyCFunction_Check(s->encoder)) {
PyCFunction f = PyCFunction_GetFunction(s->encoder);
if (f == py_encode_basestring_ascii || f == py_encode_basestring) {
s->fast_encode = f;
if (f == py_encode_basestring_ascii) {
s->fast_encode = write_escaped_ascii;
}
else if (f == py_encode_basestring) {
s->fast_encode = write_escaped_unicode;
}
}

Expand Down Expand Up @@ -1438,24 +1541,27 @@ encoder_encode_float(PyEncoderObject *s, PyObject *obj)
return PyFloat_Type.tp_repr(obj);
}

static PyObject *
encoder_encode_string(PyEncoderObject *s, PyObject *obj)
static int
encoder_write_string(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *obj)
{
/* Return the JSON representation of a string */
PyObject *encoded;

if (s->fast_encode) {
return s->fast_encode(NULL, obj);
return s->fast_encode(writer, obj);
}
encoded = PyObject_CallOneArg(s->encoder, obj);
if (encoded != NULL && !PyUnicode_Check(encoded)) {
if (encoded == NULL) {
return -1;
}
if (!PyUnicode_Check(encoded)) {
PyErr_Format(PyExc_TypeError,
"encoder() must return a string, not %.80s",
Py_TYPE(encoded)->tp_name);
Py_DECREF(encoded);
return NULL;
return -1;
}
return encoded;
return _steal_accumulate(writer, encoded);
}

static int
Expand Down Expand Up @@ -1486,10 +1592,7 @@ encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer,
return PyUnicodeWriter_WriteASCII(writer, "false", 5);
}
else if (PyUnicode_Check(obj)) {
PyObject *encoded = encoder_encode_string(s, obj);
if (encoded == NULL)
return -1;
return _steal_accumulate(writer, encoded);
return encoder_write_string(s, writer, obj);
}
else if (PyLong_Check(obj)) {
if (PyLong_CheckExact(obj)) {
Expand Down Expand Up @@ -1578,7 +1681,7 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs
PyObject *item_separator)
{
PyObject *keystr = NULL;
PyObject *encoded;
int rv;

if (PyUnicode_Check(key)) {
keystr = Py_NewRef(key);
Expand Down Expand Up @@ -1624,13 +1727,10 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs
}
}

encoded = encoder_encode_string(s, keystr);
rv = encoder_write_string(s, writer, keystr);
Py_DECREF(keystr);
if (encoded == NULL) {
return -1;
}

if (_steal_accumulate(writer, encoded) < 0) {
if (rv < 0) {
return -1;
}
if (PyUnicodeWriter_WriteStr(writer, s->key_separator) < 0) {
Expand Down
Loading
Loading