Skip to content

Commit 39ed5ea

Browse files
authored
Merge branch 'main' into deprecate-_PyLong_FromDigits/127937
2 parents d5e1fef + 3d8fc8b commit 39ed5ea

File tree

6 files changed

+118
-74
lines changed

6 files changed

+118
-74
lines changed

Include/internal/pycore_tracemalloc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ struct _tracemalloc_runtime_state {
7070
PyMemAllocatorEx obj;
7171
} allocators;
7272

73-
PyThread_type_lock tables_lock;
73+
PyMutex tables_lock;
7474
/* Size in bytes of currently traced memory.
7575
Protected by TABLES_LOCK(). */
7676
size_t traced_memory;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Convert the :mod:`decimal` module to use :pep:`757` C API (export-import
2+
integers), offering some speed-up if the integer part of the
3+
:class:`~decimal.Decimal` instance is small. Patch by Sergey B Kirpichev.

Modules/_decimal/_decimal.c

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,15 +2336,16 @@ dec_from_long(decimal_state *state, PyTypeObject *type, PyObject *v,
23362336
}
23372337
if (export_long.digits) {
23382338
const PyLongLayout *layout = PyLong_GetNativeLayout();
2339-
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
2340-
uint8_t sign = export_long.negative ? MPD_NEG : MPD_POS;
2341-
Py_ssize_t len = export_long.ndigits;
23422339

2343-
assert(layout->bits_per_digit <= 32);
2340+
assert(layout->bits_per_digit < 32);
23442341
assert(layout->digits_order == -1);
23452342
assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1));
23462343
assert(layout->digit_size == 2 || layout->digit_size == 4);
23472344

2345+
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
2346+
uint8_t sign = export_long.negative ? MPD_NEG : MPD_POS;
2347+
Py_ssize_t len = export_long.ndigits;
2348+
23482349
if (layout->digit_size == 4) {
23492350
mpd_qimport_u32(MPD(dec), export_long.digits, len, sign,
23502351
base, ctx, status);
@@ -3642,13 +3643,6 @@ dec_format(PyObject *dec, PyObject *args)
36423643
static PyObject *
36433644
dec_as_long(PyObject *dec, PyObject *context, int round)
36443645
{
3645-
PyLongObject *pylong;
3646-
digit *ob_digit;
3647-
size_t n;
3648-
mpd_t *x;
3649-
mpd_context_t workctx;
3650-
uint32_t status = 0;
3651-
36523646
if (mpd_isspecial(MPD(dec))) {
36533647
if (mpd_isnan(MPD(dec))) {
36543648
PyErr_SetString(PyExc_ValueError,
@@ -3661,12 +3655,16 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
36613655
return NULL;
36623656
}
36633657

3664-
x = mpd_qnew();
3658+
mpd_t *x = mpd_qnew();
3659+
36653660
if (x == NULL) {
36663661
PyErr_NoMemory();
36673662
return NULL;
36683663
}
3669-
workctx = *CTX(context);
3664+
3665+
mpd_context_t workctx = *CTX(context);
3666+
uint32_t status = 0;
3667+
36703668
workctx.round = round;
36713669
mpd_qround_to_int(x, MPD(dec), &workctx, &status);
36723670
if (dec_addstatus(context, status)) {
@@ -3675,34 +3673,56 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
36753673
}
36763674

36773675
status = 0;
3678-
ob_digit = NULL;
3679-
#if PYLONG_BITS_IN_DIGIT == 30
3680-
n = mpd_qexport_u32(&ob_digit, 0, PyLong_BASE, x, &status);
3681-
#elif PYLONG_BITS_IN_DIGIT == 15
3682-
n = mpd_qexport_u16(&ob_digit, 0, PyLong_BASE, x, &status);
3683-
#else
3684-
#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
3685-
#endif
3676+
int64_t val = mpd_qget_i64(x, &status);
3677+
3678+
if (!status) {
3679+
mpd_del(x);
3680+
return PyLong_FromInt64(val);
3681+
}
3682+
assert(!mpd_iszero(x));
3683+
3684+
const PyLongLayout *layout = PyLong_GetNativeLayout();
3685+
3686+
assert(layout->bits_per_digit < 32);
3687+
assert(layout->digits_order == -1);
3688+
assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1));
3689+
assert(layout->digit_size == 2 || layout->digit_size == 4);
3690+
3691+
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
3692+
/* We use a temporary buffer for digits for now, as for nonzero rdata
3693+
mpd_qexport_u32/u16() require either space "allocated by one of
3694+
libmpdec’s allocation functions" or "rlen MUST be correct" (to avoid
3695+
reallocation). This can be further optimized by using rlen from
3696+
mpd_sizeinbase(). See gh-127925. */
3697+
void *tmp_digits = NULL;
3698+
size_t n;
3699+
3700+
status = 0;
3701+
if (layout->digit_size == 4) {
3702+
n = mpd_qexport_u32((uint32_t **)&tmp_digits, 0, base, x, &status);
3703+
}
3704+
else {
3705+
n = mpd_qexport_u16((uint16_t **)&tmp_digits, 0, base, x, &status);
3706+
}
36863707

36873708
if (n == SIZE_MAX) {
36883709
PyErr_NoMemory();
36893710
mpd_del(x);
3711+
mpd_free(tmp_digits);
36903712
return NULL;
36913713
}
36923714

3693-
if (n == 1) {
3694-
sdigit val = mpd_arith_sign(x) * ob_digit[0];
3695-
mpd_free(ob_digit);
3696-
mpd_del(x);
3697-
return PyLong_FromLong(val);
3698-
}
3715+
void *digits;
3716+
PyLongWriter *writer = PyLongWriter_Create(mpd_isnegative(x), n, &digits);
36993717

3700-
assert(n > 0);
3701-
assert(!mpd_iszero(x));
3702-
pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit);
3703-
mpd_free(ob_digit);
37043718
mpd_del(x);
3705-
return (PyObject *) pylong;
3719+
if (writer == NULL) {
3720+
mpd_free(tmp_digits);
3721+
return NULL;
3722+
}
3723+
memcpy(digits, tmp_digits, layout->digit_size*n);
3724+
mpd_free(tmp_digits);
3725+
return PyLongWriter_Finish(writer);
37063726
}
37073727

37083728
/* Convert a Decimal to its exact integer ratio representation. */

Modules/_json.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,13 @@ _build_rval_index_tuple(PyObject *rval, Py_ssize_t idx) {
353353
return tpl;
354354
}
355355

356+
static inline int
357+
_PyUnicodeWriter_IsEmpty(PyUnicodeWriter *writer_pub)
358+
{
359+
_PyUnicodeWriter *writer = (_PyUnicodeWriter*)writer_pub;
360+
return (writer->pos == 0);
361+
}
362+
356363
static PyObject *
357364
scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr)
358365
{
@@ -371,9 +378,10 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
371378
const void *buf;
372379
int kind;
373380

374-
_PyUnicodeWriter writer;
375-
_PyUnicodeWriter_Init(&writer);
376-
writer.overallocate = 1;
381+
PyUnicodeWriter *writer = PyUnicodeWriter_Create(0);
382+
if (writer == NULL) {
383+
goto bail;
384+
}
377385

378386
len = PyUnicode_GET_LENGTH(pystr);
379387
buf = PyUnicode_DATA(pystr);
@@ -404,7 +412,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
404412

405413
if (c == '"') {
406414
// Fast path for simple case.
407-
if (writer.buffer == NULL) {
415+
if (_PyUnicodeWriter_IsEmpty(writer)) {
408416
PyObject *ret = PyUnicode_Substring(pystr, end, next);
409417
if (ret == NULL) {
410418
goto bail;
@@ -420,7 +428,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
420428

421429
/* Pick up this chunk if it's not zero length */
422430
if (next != end) {
423-
if (_PyUnicodeWriter_WriteSubstring(&writer, pystr, end, next) < 0) {
431+
if (PyUnicodeWriter_WriteSubstring(writer, pystr, end, next) < 0) {
424432
goto bail;
425433
}
426434
}
@@ -511,18 +519,18 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
511519
end -= 6;
512520
}
513521
}
514-
if (_PyUnicodeWriter_WriteChar(&writer, c) < 0) {
522+
if (PyUnicodeWriter_WriteChar(writer, c) < 0) {
515523
goto bail;
516524
}
517525
}
518526

519-
rval = _PyUnicodeWriter_Finish(&writer);
527+
rval = PyUnicodeWriter_Finish(writer);
520528
*next_end_ptr = end;
521529
return rval;
522530

523531
bail:
524532
*next_end_ptr = -1;
525-
_PyUnicodeWriter_Dealloc(&writer);
533+
PyUnicodeWriter_Discard(writer);
526534
return NULL;
527535
}
528536

Python/codecs.c

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -659,44 +659,64 @@ PyObject *PyCodec_LookupError(const char *name)
659659
return handler;
660660
}
661661

662-
static void wrong_exception_type(PyObject *exc)
662+
663+
static inline void
664+
wrong_exception_type(PyObject *exc)
663665
{
664666
PyErr_Format(PyExc_TypeError,
665-
"don't know how to handle %.200s in error callback",
666-
Py_TYPE(exc)->tp_name);
667+
"don't know how to handle %T in error callback", exc);
667668
}
668669

670+
671+
#define _PyIsUnicodeEncodeError(EXC) \
672+
PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeEncodeError)
673+
#define _PyIsUnicodeDecodeError(EXC) \
674+
PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeDecodeError)
675+
#define _PyIsUnicodeTranslateError(EXC) \
676+
PyObject_TypeCheck(EXC, (PyTypeObject *)PyExc_UnicodeTranslateError)
677+
678+
679+
// --- handler: 'strict' ------------------------------------------------------
680+
669681
PyObject *PyCodec_StrictErrors(PyObject *exc)
670682
{
671-
if (PyExceptionInstance_Check(exc))
683+
if (PyExceptionInstance_Check(exc)) {
672684
PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
673-
else
685+
}
686+
else {
674687
PyErr_SetString(PyExc_TypeError, "codec must pass exception instance");
688+
}
675689
return NULL;
676690
}
677691

678692

679-
PyObject *PyCodec_IgnoreErrors(PyObject *exc)
693+
// --- handler: 'ignore' ------------------------------------------------------
694+
695+
static PyObject *
696+
_PyCodec_IgnoreError(PyObject *exc, int as_bytes)
680697
{
681698
Py_ssize_t end;
682-
683-
if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeEncodeError)) {
684-
if (PyUnicodeEncodeError_GetEnd(exc, &end))
685-
return NULL;
699+
if (_PyUnicodeError_GetParams(exc, NULL, NULL, NULL,
700+
&end, NULL, as_bytes) < 0)
701+
{
702+
return NULL;
686703
}
687-
else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeDecodeError)) {
688-
if (PyUnicodeDecodeError_GetEnd(exc, &end))
689-
return NULL;
704+
return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end);
705+
}
706+
707+
708+
PyObject *PyCodec_IgnoreErrors(PyObject *exc)
709+
{
710+
if (_PyIsUnicodeEncodeError(exc) || _PyIsUnicodeTranslateError(exc)) {
711+
return _PyCodec_IgnoreError(exc, false);
690712
}
691-
else if (PyObject_TypeCheck(exc, (PyTypeObject *)PyExc_UnicodeTranslateError)) {
692-
if (PyUnicodeTranslateError_GetEnd(exc, &end))
693-
return NULL;
713+
else if (_PyIsUnicodeDecodeError(exc)) {
714+
return _PyCodec_IgnoreError(exc, true);
694715
}
695716
else {
696717
wrong_exception_type(exc);
697718
return NULL;
698719
}
699-
return Py_BuildValue("(Nn)", Py_GetConstant(Py_CONSTANT_EMPTY_STR), end);
700720
}
701721

702722

@@ -1368,13 +1388,17 @@ PyCodec_SurrogateEscapeErrors(PyObject *exc)
13681388
}
13691389

13701390

1371-
static PyObject *strict_errors(PyObject *self, PyObject *exc)
1391+
// --- Codecs registry handlers -----------------------------------------------
1392+
1393+
static inline PyObject *
1394+
strict_errors(PyObject *Py_UNUSED(self), PyObject *exc)
13721395
{
13731396
return PyCodec_StrictErrors(exc);
13741397
}
13751398

13761399

1377-
static PyObject *ignore_errors(PyObject *self, PyObject *exc)
1400+
static inline PyObject *
1401+
ignore_errors(PyObject *Py_UNUSED(self), PyObject *exc)
13781402
{
13791403
return PyCodec_IgnoreErrors(exc);
13801404
}

Python/tracemalloc.c

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "pycore_gc.h" // PyGC_Head
44
#include "pycore_hashtable.h" // _Py_hashtable_t
55
#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY()
6+
#include "pycore_lock.h" // PyMutex_LockFlags()
67
#include "pycore_object.h" // _PyType_PreHeaderSize()
78
#include "pycore_pymem.h" // _Py_tracemalloc_config
89
#include "pycore_runtime.h" // _Py_ID()
@@ -37,8 +38,8 @@ static int _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event,
3738
the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
3839
would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
3940
#define tables_lock _PyRuntime.tracemalloc.tables_lock
40-
#define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
41-
#define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
41+
#define TABLES_LOCK() PyMutex_LockFlags(&tables_lock, _Py_LOCK_DONT_DETACH)
42+
#define TABLES_UNLOCK() PyMutex_Unlock(&tables_lock)
4243

4344

4445
#define DEFAULT_DOMAIN 0
@@ -741,13 +742,6 @@ _PyTraceMalloc_Init(void)
741742
return _PyStatus_NO_MEMORY();
742743
}
743744

744-
if (tables_lock == NULL) {
745-
tables_lock = PyThread_allocate_lock();
746-
if (tables_lock == NULL) {
747-
return _PyStatus_NO_MEMORY();
748-
}
749-
}
750-
751745
tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject,
752746
hashtable_compare_unicode,
753747
tracemalloc_clear_filename, NULL);
@@ -792,11 +786,6 @@ tracemalloc_deinit(void)
792786
_Py_hashtable_destroy(tracemalloc_tracebacks);
793787
_Py_hashtable_destroy(tracemalloc_filenames);
794788

795-
if (tables_lock != NULL) {
796-
PyThread_free_lock(tables_lock);
797-
tables_lock = NULL;
798-
}
799-
800789
PyThread_tss_delete(&tracemalloc_reentrant_key);
801790
}
802791

0 commit comments

Comments
 (0)