From 60902dd614acf67f15459b4373fece832244dbda Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Mar 2023 17:53:58 +0100 Subject: [PATCH 01/27] Establish global state --- Modules/_decimal/_decimal.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5936fbaaf35eb0..12b2a82c244958 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -38,6 +38,13 @@ #include "docstrings.h" +typedef struct { +} decimal_state; + +static decimal_state global_state; + +#define GLOBAL_STATE() (&global_state) + #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000 #error "libmpdec version >= 2.5.0 required" From fa06750b7ad6926130c0a2ef90d0f3c491d17bd1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Mar 2023 18:15:36 +0100 Subject: [PATCH 02/27] Adapt PyDecContextManager_Type to heap type and add it to state --- Modules/_decimal/_decimal.c | 112 ++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 50 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 12b2a82c244958..99d130632e3efd 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,7 @@ #include "docstrings.h" typedef struct { + PyTypeObject *PyDecContextManager_Type; } decimal_state; static decimal_state global_state; @@ -108,7 +109,6 @@ typedef struct { static PyTypeObject PyDec_Type; static PyTypeObject *PyDecSignalDict_Type; static PyTypeObject PyDecContext_Type; -static PyTypeObject PyDecContextManager_Type; #define PyDec_CheckExact(v) Py_IS_TYPE(v, &PyDec_Type) #define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) #define PyDecSignalDict_Check(v) Py_IS_TYPE(v, PyDecSignalDict_Type) @@ -1766,40 +1766,61 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) return NULL; } - self = PyObject_New(PyDecContextManagerObject, - &PyDecContextManager_Type); - if (self == NULL) { - return NULL; - } - - self->local = context_copy(local, NULL); - if (self->local == NULL) { - self->global = NULL; - Py_DECREF(self); + PyObject *local_copy = context_copy(local, NULL); + if (local_copy == NULL) { return NULL; } - self->global = Py_NewRef(global); int ret = context_setattrs( - self->local, prec, rounding, + local_copy, prec, rounding, Emin, Emax, capitals, clamp, flags, traps ); - if (ret < 0) { - Py_DECREF(self); + Py_DECREF(local_copy); + return NULL; + } + + decimal_state *state = GLOBAL_STATE(); + self = PyObject_GC_New(PyDecContextManagerObject, + state->PyDecContextManager_Type); + if (self == NULL) { + Py_DECREF(local_copy); return NULL; } + self->local = local_copy; + self->global = Py_NewRef(global); + PyObject_GC_Track(self); + return (PyObject *)self; } +static int +ctxmanager_traverse(PyDecContextManagerObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->local); + Py_VISIT(self->global); + return 0; +} + +static int +ctxmanager_clear(PyDecContextManagerObject *self) +{ + Py_CLEAR(self->local); + Py_CLEAR(self->global); + return 0; +} + static void ctxmanager_dealloc(PyDecContextManagerObject *self) { - Py_XDECREF(self->local); - Py_XDECREF(self->global); - PyObject_Free(self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)ctxmanager_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -1838,36 +1859,20 @@ static PyMethodDef ctxmanager_methods[] = { {NULL, NULL} }; -static PyTypeObject PyDecContextManager_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.ContextManager", /* tp_name */ - sizeof(PyDecContextManagerObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) ctxmanager_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ctxmanager_methods, /* tp_methods */ +static PyType_Slot ctxmanager_slots[] = { + {Py_tp_dealloc, ctxmanager_dealloc}, + {Py_tp_traverse, ctxmanager_traverse}, + {Py_tp_clear, ctxmanager_clear}, + {Py_tp_methods, ctxmanager_methods}, + {0, NULL}, +}; + +static PyType_Spec ctxmanager_spec = { + .name = "decimal.ContextManager", + .basicsize = sizeof(PyDecContextManagerObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = ctxmanager_slots, }; @@ -5842,13 +5847,20 @@ PyInit__decimal(void) /* Init types */ PyDec_Type.tp_base = &PyBaseObject_Type; PyDecContext_Type.tp_base = &PyBaseObject_Type; - PyDecContextManager_Type.tp_base = &PyBaseObject_Type; PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; +#define CREATE_TYPE(mod, type, spec) \ + do { \ + type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ + CHECK_PTR(type); \ + } while (0) + + decimal_state *state = GLOBAL_STATE(); CHECK_INT(PyType_Ready(&PyDec_Type)); CHECK_INT(PyType_Ready(&PyDecContext_Type)); CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); - CHECK_INT(PyType_Ready(&PyDecContextManager_Type)); + CREATE_TYPE(m, state->PyDecContextManager_Type, &ctxmanager_spec); + #undef CREATE_TYPE ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); From f19c14cbdc1db67639770afca06ccc5c830a28af Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Mar 2023 18:15:53 +0100 Subject: [PATCH 03/27] fixup! Adapt PyDecContextManager_Type to heap type and add it to state --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 57b8542fb46482..37f23f933b7d87 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -386,7 +386,6 @@ Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - -Modules/_decimal/_decimal.c - PyDecContextManager_Type - Modules/_decimal/_decimal.c - PyDecContext_Type - Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - Modules/_decimal/_decimal.c - PyDec_Type - From cde5da93138f1ac519b7fe3c863d772dccbd108c Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Mar 2023 18:35:01 +0100 Subject: [PATCH 04/27] Adapt PyDecContext_Type to heap type and add it to state --- Modules/_decimal/_decimal.c | 186 +++++++++++--------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 104 insertions(+), 83 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 99d130632e3efd..d78b6d9db204b9 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -40,6 +40,7 @@ typedef struct { PyTypeObject *PyDecContextManager_Type; + PyTypeObject *PyDecContext_Type; } decimal_state; static decimal_state global_state; @@ -108,11 +109,10 @@ typedef struct { #undef CTX static PyTypeObject PyDec_Type; static PyTypeObject *PyDecSignalDict_Type; -static PyTypeObject PyDecContext_Type; #define PyDec_CheckExact(v) Py_IS_TYPE(v, &PyDec_Type) #define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) #define PyDecSignalDict_Check(v) Py_IS_TYPE(v, PyDecSignalDict_Type) -#define PyDecContext_Check(v) PyObject_TypeCheck(v, &PyDecContext_Type) +#define PyDecContext_Check(st, v) PyObject_TypeCheck(v, st->PyDecContext_Type) #define MPD(v) (&((PyDecObject *)v)->dec) #define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) #define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) @@ -1247,8 +1247,9 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) PyDecContextObject *self = NULL; mpd_context_t *ctx; - if (type == &PyDecContext_Type) { - self = PyObject_New(PyDecContextObject, &PyDecContext_Type); + decimal_state *state = GLOBAL_STATE(); + if (type == state->PyDecContext_Type) { + self = PyObject_GC_New(PyDecContextObject, state->PyDecContext_Type); } else { self = (PyDecContextObject *)type->tp_alloc(type, 0); @@ -1285,21 +1286,43 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) CtxCaps(self) = 1; self->tstate = NULL; + if (type == state->PyDecContext_Type) { + PyObject_GC_Track(self); + } + return (PyObject *)self; } +static int +context_traverse(PyDecContextObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->traps); + Py_VISIT(self->flags); + return 0; +} + +static int +context_clear(PyDecContextObject *self) +{ + Py_CLEAR(self->traps); + Py_CLEAR(self->flags); + return 0; +} + static void context_dealloc(PyDecContextObject *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); #ifndef WITH_DECIMAL_CONTEXTVAR if (self == cached_context) { cached_context = NULL; } #endif - - Py_XDECREF(self->traps); - Py_XDECREF(self->flags); - Py_TYPE(self)->tp_free(self); + (void)context_clear(self); + tp->tp_free(self); + Py_DECREF(tp); } static int @@ -1343,7 +1366,10 @@ context_repr(PyDecContextObject *self) char traps[MPD_MAX_SIGNAL_LIST]; int n, mem; - assert(PyDecContext_Check(self)); +#ifdef NDEBUG + decimal_state *state = GLOBAL_STATE(); + assert(PyDecContext_Check(state, self)); +#endif ctx = CTX(self); mem = MPD_MAX_SIGNAL_LIST; @@ -1409,7 +1435,8 @@ ieee_context(PyObject *dummy UNUSED, PyObject *v) goto error; } - context = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + decimal_state *state = GLOBAL_STATE(); + context = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (context == NULL) { return NULL; } @@ -1431,7 +1458,8 @@ context_copy(PyObject *self, PyObject *args UNUSED) { PyObject *copy; - copy = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + decimal_state *state = GLOBAL_STATE(); + copy = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (copy == NULL) { return NULL; } @@ -1493,18 +1521,18 @@ static PyGetSetDef context_getsets [] = }; -#define CONTEXT_CHECK(obj) \ - if (!PyDecContext_Check(obj)) { \ +#define CONTEXT_CHECK(state, obj) \ + if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ "argument must be a context"); \ return NULL; \ } -#define CONTEXT_CHECK_VA(obj) \ +#define CONTEXT_CHECK_VA(state, obj) \ if (obj == Py_None) { \ CURRENT_CONTEXT(obj); \ } \ - else if (!PyDecContext_Check(obj)) { \ + else if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ "optional argument must be a context"); \ return NULL; \ @@ -1543,7 +1571,8 @@ current_context_from_dict(void) PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ - CONTEXT_CHECK(tl_context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK(state, tl_context); } else { if (PyErr_Occurred()) { @@ -1612,7 +1641,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { PyObject *dict; - CONTEXT_CHECK(v); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK(state, v); dict = PyThreadState_GetDict(); if (dict == NULL) { @@ -1699,7 +1729,8 @@ PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED) static PyObject * PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { - CONTEXT_CHECK(v); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK(state, v); /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ @@ -1757,10 +1788,11 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) &prec, &rounding, &Emin, &Emax, &capitals, &clamp, &flags, &traps)) { return NULL; } + decimal_state *state = GLOBAL_STATE(); if (local == Py_None) { local = global; } - else if (!PyDecContext_Check(local)) { + else if (!PyDecContext_Check(state, local)) { PyErr_SetString(PyExc_TypeError, "optional argument must be a context"); return NULL; @@ -1781,7 +1813,6 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) return NULL; } - decimal_state *state = GLOBAL_STATE(); self = PyObject_GC_New(PyDecContextManagerObject, state->PyDecContextManager_Type); if (self == NULL) { @@ -2832,7 +2863,8 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds) &v, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); return PyDecType_FromObjectExact(type, v, context); } @@ -3685,7 +3717,8 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { @@ -3726,7 +3759,8 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { @@ -4006,7 +4040,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ \ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ } @@ -4025,7 +4060,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ \ if ((result = dec_alloc()) == NULL) { \ return NULL; \ @@ -4056,7 +4092,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ if ((result = dec_alloc()) == NULL) { \ @@ -4093,7 +4130,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ if ((result = dec_alloc()) == NULL) { \ @@ -4125,7 +4163,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &third, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = GLOBAL_STATE(); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ if ((result = dec_alloc()) == NULL) { \ @@ -4403,7 +4442,8 @@ dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); cp = mpd_class(MPD(self), CTX(context)); return PyUnicode_FromString(cp); @@ -4422,7 +4462,8 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); if (size < 0) { @@ -4454,7 +4495,8 @@ dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); result = dec_alloc(); @@ -4488,7 +4530,8 @@ dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); @@ -4522,7 +4565,8 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) &w, &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { @@ -5668,47 +5712,27 @@ static PyMethodDef context_methods [] = { NULL, NULL, 1 } }; -static PyTypeObject PyDecContext_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.Context", /* tp_name */ - sizeof(PyDecContextObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) context_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) context_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc) context_getattr, /* tp_getattro */ - (setattrofunc) context_setattr, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - doc_context, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - context_methods, /* tp_methods */ - 0, /* tp_members */ - context_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - context_init, /* tp_init */ - 0, /* tp_alloc */ - context_new, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot context_slots[] = { + {Py_tp_dealloc, context_dealloc}, + {Py_tp_traverse, context_traverse}, + {Py_tp_clear, context_clear}, + {Py_tp_repr, context_repr}, + {Py_tp_getattro, context_getattr}, + {Py_tp_setattro, context_setattr}, + {Py_tp_doc, (void *)doc_context}, + {Py_tp_methods, context_methods}, + {Py_tp_getset, context_getsets}, + {Py_tp_init, context_init}, + {Py_tp_new, context_new}, + {0, NULL}, +}; + +static PyType_Spec context_spec = { + .name = "decimal.Context", + .basicsize = sizeof(PyDecContextObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = context_slots, }; @@ -5846,7 +5870,6 @@ PyInit__decimal(void) /* Init types */ PyDec_Type.tp_base = &PyBaseObject_Type; - PyDecContext_Type.tp_base = &PyBaseObject_Type; PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; #define CREATE_TYPE(mod, type, spec) \ @@ -5857,14 +5880,14 @@ PyInit__decimal(void) decimal_state *state = GLOBAL_STATE(); CHECK_INT(PyType_Ready(&PyDec_Type)); - CHECK_INT(PyType_Ready(&PyDecContext_Type)); + CREATE_TYPE(m, state->PyDecContext_Type, &context_spec); CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); CREATE_TYPE(m, state->PyDecContextManager_Type, &ctxmanager_spec); #undef CREATE_TYPE ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); - CHECK_INT(PyDict_SetItemString(PyDecContext_Type.tp_dict, + CHECK_INT(PyDict_SetItemString(state->PyDecContext_Type->tp_dict, "__module__", obj)); Py_CLEAR(obj); @@ -5914,8 +5937,7 @@ PyInit__decimal(void) /* Add types to the module */ CHECK_INT(PyModule_AddObject(m, "Decimal", Py_NewRef(&PyDec_Type))); - CHECK_INT(PyModule_AddObject(m, "Context", - Py_NewRef(&PyDecContext_Type))); + CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); CHECK_INT(PyModule_AddObject(m, "DecimalTuple", Py_NewRef(DecimalTuple))); /* Create top level exception */ @@ -5997,7 +6019,7 @@ PyInit__decimal(void) /* Init default context template first */ ASSIGN_PTR(default_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); CHECK_INT(PyModule_AddObject(m, "DefaultContext", Py_NewRef(default_context_template))); @@ -6012,14 +6034,14 @@ PyInit__decimal(void) /* Init basic context template */ ASSIGN_PTR(basic_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); init_basic_context(basic_context_template); CHECK_INT(PyModule_AddObject(m, "BasicContext", Py_NewRef(basic_context_template))); /* Init extended context template */ ASSIGN_PTR(extended_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); init_extended_context(extended_context_template); CHECK_INT(PyModule_AddObject(m, "ExtendedContext", Py_NewRef(extended_context_template))); diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 37f23f933b7d87..2a5019e3812b1b 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -386,7 +386,6 @@ Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - -Modules/_decimal/_decimal.c - PyDecContext_Type - Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - Modules/_decimal/_decimal.c - PyDec_Type - Modules/_pickle.c - Pdata_Type - From 90955ab252054a271f59dc8b0d19b29bc708ab87 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Mar 2023 18:46:45 +0100 Subject: [PATCH 05/27] Adapt PyDecSignalDictMixin_Type to heap type and add it to state --- Modules/_decimal/_decimal.c | 91 ++++++++++----------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 42 insertions(+), 50 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index d78b6d9db204b9..90eee81b28b5b8 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -41,6 +41,7 @@ typedef struct { PyTypeObject *PyDecContextManager_Type; PyTypeObject *PyDecContext_Type; + PyTypeObject *PyDecSignalDictMixin_Type; } decimal_state; static decimal_state global_state; @@ -609,6 +610,22 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) return 0; } +static int +signaldict_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +signaldict_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + static PyObject * signaldict_repr(PyObject *self) { @@ -670,58 +687,35 @@ signaldict_copy(PyObject *self, PyObject *args UNUSED) } -static PyMappingMethods signaldict_as_mapping = { - (lenfunc)signaldict_len, /* mp_length */ - (binaryfunc)signaldict_getitem, /* mp_subscript */ - (objobjargproc)signaldict_setitem /* mp_ass_subscript */ -}; - static PyMethodDef signaldict_methods[] = { { "copy", (PyCFunction)signaldict_copy, METH_NOARGS, NULL}, {NULL, NULL} }; -static PyTypeObject PyDecSignalDictMixin_Type = -{ - PyVarObject_HEAD_INIT(0, 0) - "decimal.SignalDictMixin", /* tp_name */ - sizeof(PyDecSignalDictObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) signaldict_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - &signaldict_as_mapping, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - signaldict_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)signaldict_iter, /* tp_iter */ - 0, /* tp_iternext */ - signaldict_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)signaldict_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot signaldict_slots[] = { + {Py_tp_dealloc, signaldict_dealloc}, + {Py_tp_traverse, signaldict_traverse}, + {Py_tp_repr, signaldict_repr}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_richcompare, signaldict_richcompare}, + {Py_tp_iter, signaldict_iter}, + {Py_tp_methods, signaldict_methods}, + {Py_tp_init, signaldict_init}, + + // Mapping protocol + {Py_mp_length, signaldict_len}, + {Py_mp_subscript, signaldict_getitem}, + {Py_mp_ass_subscript, signaldict_setitem}, + {0, NULL}, +}; + +static PyType_Spec signaldict_spec = { + .name = "decimal.SignalDictMixin", + .basicsize = sizeof(PyDecSignalDictObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = signaldict_slots, }; @@ -5870,7 +5864,6 @@ PyInit__decimal(void) /* Init types */ PyDec_Type.tp_base = &PyBaseObject_Type; - PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; #define CREATE_TYPE(mod, type, spec) \ do { \ @@ -5881,7 +5874,7 @@ PyInit__decimal(void) decimal_state *state = GLOBAL_STATE(); CHECK_INT(PyType_Ready(&PyDec_Type)); CREATE_TYPE(m, state->PyDecContext_Type, &context_spec); - CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); + CREATE_TYPE(m, state->PyDecSignalDictMixin_Type, &signaldict_spec); CREATE_TYPE(m, state->PyDecContextManager_Type, &ctxmanager_spec); #undef CREATE_TYPE @@ -5923,7 +5916,7 @@ PyInit__decimal(void) ASSIGN_PTR(PyDecSignalDict_Type, (PyTypeObject *)PyObject_CallFunction( (PyObject *)&PyType_Type, "s(OO){}", - "SignalDict", &PyDecSignalDictMixin_Type, + "SignalDict", state->PyDecSignalDictMixin_Type, MutableMapping)); /* Done with collections, MutableMapping */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 2a5019e3812b1b..0f73632a4693be 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -386,7 +386,6 @@ Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - -Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - Modules/_decimal/_decimal.c - PyDec_Type - Modules/_pickle.c - Pdata_Type - Modules/_pickle.c - PicklerMemoProxyType - From ae2ac48e99162db477915424c14d51c3ae4a59ee Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sun, 12 Mar 2023 18:47:03 +0100 Subject: [PATCH 06/27] fixup! Adapt PyDecSignalDictMixin_Type to heap type and add it to state --- Modules/_decimal/_decimal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 90eee81b28b5b8..5f30790166cd09 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -109,7 +109,6 @@ typedef struct { #undef MPD #undef CTX static PyTypeObject PyDec_Type; -static PyTypeObject *PyDecSignalDict_Type; #define PyDec_CheckExact(v) Py_IS_TYPE(v, &PyDec_Type) #define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) #define PyDecSignalDict_Check(v) Py_IS_TYPE(v, PyDecSignalDict_Type) From eee3ef746abb8f590fcca8cee694fe27c0d4d69a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 14 Mar 2023 09:12:49 +0100 Subject: [PATCH 07/27] Adapt and add PyDec_Type & PyDecSignalDict_Type --- Modules/_decimal/_decimal.c | 379 ++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 - 2 files changed, 189 insertions(+), 192 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5f30790166cd09..b31c99c732fadb 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -42,6 +42,8 @@ typedef struct { PyTypeObject *PyDecContextManager_Type; PyTypeObject *PyDecContext_Type; PyTypeObject *PyDecSignalDictMixin_Type; + PyTypeObject *PyDec_Type; + PyTypeObject *PyDecSignalDict_Type; } decimal_state; static decimal_state global_state; @@ -108,10 +110,9 @@ typedef struct { #undef MPD #undef CTX -static PyTypeObject PyDec_Type; -#define PyDec_CheckExact(v) Py_IS_TYPE(v, &PyDec_Type) -#define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) -#define PyDecSignalDict_Check(v) Py_IS_TYPE(v, PyDecSignalDict_Type) +#define PyDec_CheckExact(st, v) Py_IS_TYPE(v, st->PyDec_Type) +#define PyDec_Check(st, v) PyObject_TypeCheck(v, st->PyDec_Type) +#define PyDecSignalDict_Check(st, v) Py_IS_TYPE(v, st->PyDecSignalDict_Type) #define PyDecContext_Check(st, v) PyObject_TypeCheck(v, st->PyDecContext_Type) #define MPD(v) (&((PyDecObject *)v)->dec) #define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) @@ -653,10 +654,11 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) { PyObject *res = Py_NotImplemented; - assert(PyDecSignalDict_Check(v)); + decimal_state *state = GLOBAL_STATE(); + assert(PyDecSignalDict_Check(state, v)); if (op == Py_EQ || op == Py_NE) { - if (PyDecSignalDict_Check(w)) { + if (PyDecSignalDict_Check(state, w)) { res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False; } else if (PyDict_Check(w)) { @@ -986,7 +988,8 @@ context_settraps_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - if (PyDecSignalDict_Check(value)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } else { @@ -1050,7 +1053,8 @@ context_setstatus_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - if (PyDecSignalDict_Check(value)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } else { @@ -1252,13 +1256,13 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) return NULL; } - self->traps = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + self->traps = PyObject_CallObject((PyObject *)state->PyDecSignalDict_Type, NULL); if (self->traps == NULL) { self->flags = NULL; Py_DECREF(self); return NULL; } - self->flags = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + self->flags = PyObject_CallObject((PyObject *)state->PyDecSignalDict_Type, NULL); if (self->flags == NULL) { Py_DECREF(self); return NULL; @@ -1909,8 +1913,9 @@ PyDecType_New(PyTypeObject *type) { PyDecObject *dec; - if (type == &PyDec_Type) { - dec = PyObject_New(PyDecObject, &PyDec_Type); + decimal_state *state = GLOBAL_STATE(); + if (type == state->PyDec_Type) { + dec = PyObject_GC_New(PyDecObject, state->PyDec_Type); } else { dec = (PyDecObject *)type->tp_alloc(type, 0); @@ -1930,13 +1935,23 @@ PyDecType_New(PyTypeObject *type) return (PyObject *)dec; } -#define dec_alloc() PyDecType_New(&PyDec_Type) +#define dec_alloc(st) PyDecType_New(st->PyDec_Type) + +static int +dec_traverse(PyObject *dec, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(dec)); + return 0; +} static void dec_dealloc(PyObject *dec) { + PyTypeObject *tp = Py_TYPE(dec); + PyObject_GC_UnTrack(dec); mpd_del(MPD(dec)); - Py_TYPE(dec)->tp_free(dec); + tp->tp_free(dec); + Py_DECREF(tp); } @@ -2309,7 +2324,10 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, mpd_context_t maxctx; - assert(PyType_IsSubtype(type, &PyDec_Type)); +#ifdef NDEBUG + decimal_state *state = GLOBAL_STATE(); + assert(PyType_IsSubtype(type, state->PyDec_Type)); +#endif if (PyLong_Check(v)) { return PyDecType_FromLongExact(type, v, context); @@ -2444,7 +2462,8 @@ PyDecType_FromDecimalExact(PyTypeObject *type, PyObject *v, PyObject *context) PyObject *dec; uint32_t status = 0; - if (type == &PyDec_Type && PyDec_CheckExact(v)) { + decimal_state *state = GLOBAL_STATE(); + if (type == state->PyDec_Type && PyDec_CheckExact(state, v)) { return Py_NewRef(v); } @@ -2679,37 +2698,37 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, return dec; } -#define PyDec_FromCString(str, context) \ - PyDecType_FromCString(&PyDec_Type, str, context) -#define PyDec_FromCStringExact(str, context) \ - PyDecType_FromCStringExact(&PyDec_Type, str, context) +#define PyDec_FromCString(st, str, context) \ + PyDecType_FromCString(st->PyDec_Type, str, context) +#define PyDec_FromCStringExact(st, str, context) \ + PyDecType_FromCStringExact(st->PyDec_Type, str, context) -#define PyDec_FromUnicode(unicode, context) \ - PyDecType_FromUnicode(&PyDec_Type, unicode, context) -#define PyDec_FromUnicodeExact(unicode, context) \ - PyDecType_FromUnicodeExact(&PyDec_Type, unicode, context) -#define PyDec_FromUnicodeExactWS(unicode, context) \ - PyDecType_FromUnicodeExactWS(&PyDec_Type, unicode, context) +#define PyDec_FromUnicode(st, unicode, context) \ + PyDecType_FromUnicode(st->PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExact(st, unicode, context) \ + PyDecType_FromUnicodeExact(st->PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExactWS(st, unicode, context) \ + PyDecType_FromUnicodeExactWS(st->PyDec_Type, unicode, context) -#define PyDec_FromSsize(v, context) \ - PyDecType_FromSsize(&PyDec_Type, v, context) -#define PyDec_FromSsizeExact(v, context) \ - PyDecType_FromSsizeExact(&PyDec_Type, v, context) +#define PyDec_FromSsize(st, v, context) \ + PyDecType_FromSsize(st->PyDec_Type, v, context) +#define PyDec_FromSsizeExact(st, v, context) \ + PyDecType_FromSsizeExact(st->PyDec_Type, v, context) -#define PyDec_FromLong(pylong, context) \ - PyDecType_FromLong(&PyDec_Type, pylong, context) -#define PyDec_FromLongExact(pylong, context) \ - PyDecType_FromLongExact(&PyDec_Type, pylong, context) +#define PyDec_FromLong(st, pylong, context) \ + PyDecType_FromLong(st->PyDec_Type, pylong, context) +#define PyDec_FromLongExact(st, pylong, context) \ + PyDecType_FromLongExact(st->PyDec_Type, pylong, context) -#define PyDec_FromFloat(pyfloat, context) \ - PyDecType_FromFloat(&PyDec_Type, pyfloat, context) -#define PyDec_FromFloatExact(pyfloat, context) \ - PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context) +#define PyDec_FromFloat(st, pyfloat, context) \ + PyDecType_FromFloat(st->PyDec_Type, pyfloat, context) +#define PyDec_FromFloatExact(st, pyfloat, context) \ + PyDecType_FromFloatExact(st->PyDec_Type, pyfloat, context) -#define PyDec_FromSequence(sequence, context) \ - PyDecType_FromSequence(&PyDec_Type, sequence, context) -#define PyDec_FromSequenceExact(sequence, context) \ - PyDecType_FromSequenceExact(&PyDec_Type, sequence, context) +#define PyDec_FromSequence(st, sequence, context) \ + PyDecType_FromSequence(st->PyDec_Type, sequence, context) +#define PyDec_FromSequenceExact(st, sequence, context) \ + PyDecType_FromSequenceExact(st->PyDec_Type, sequence, context) /* class method */ static PyObject * @@ -2718,9 +2737,10 @@ dec_from_float(PyObject *type, PyObject *pyfloat) PyObject *context; PyObject *result; + decimal_state *state = GLOBAL_STATE(); CURRENT_CONTEXT(context); - result = PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context); - if (type != (PyObject *)&PyDec_Type && result != NULL) { + result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); + if (type != (PyObject *)state->PyDec_Type && result != NULL) { Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); } @@ -2731,7 +2751,8 @@ dec_from_float(PyObject *type, PyObject *pyfloat) static PyObject * ctx_from_float(PyObject *context, PyObject *v) { - return PyDec_FromFloat(v, context); + decimal_state *state = GLOBAL_STATE(); + return PyDec_FromFloat(state, v, context); } /* Apply the context to the input operand. Return a new PyDecObject. */ @@ -2741,7 +2762,8 @@ dec_apply(PyObject *v, PyObject *context) PyObject *result; uint32_t status = 0; - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -2767,10 +2789,11 @@ dec_apply(PyObject *v, PyObject *context) static PyObject * PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) { + decimal_state *state = GLOBAL_STATE(); if (v == NULL) { return PyDecType_FromSsizeExact(type, 0, context); } - else if (PyDec_Check(v)) { + else if (PyDec_Check(state, v)) { return PyDecType_FromDecimalExact(type, v, context); } else if (PyUnicode_Check(v)) { @@ -2801,10 +2824,11 @@ PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) static PyObject * PyDec_FromObject(PyObject *v, PyObject *context) { + decimal_state *state = GLOBAL_STATE(); if (v == NULL) { - return PyDec_FromSsize(0, context); + return PyDec_FromSsize(state, 0, context); } - else if (PyDec_Check(v)) { + else if (PyDec_Check(state, v)) { mpd_context_t *ctx = CTX(context); if (mpd_isnan(MPD(v)) && MPD(v)->digits > ctx->prec - ctx->clamp) { @@ -2813,7 +2837,7 @@ PyDec_FromObject(PyObject *v, PyObject *context) if (dec_addstatus(context, MPD_Conversion_syntax)) { return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -2823,19 +2847,19 @@ PyDec_FromObject(PyObject *v, PyObject *context) return dec_apply(v, context); } else if (PyUnicode_Check(v)) { - return PyDec_FromUnicode(v, context); + return PyDec_FromUnicode(state, v, context); } else if (PyLong_Check(v)) { - return PyDec_FromLong(v, context); + return PyDec_FromLong(state, v, context); } else if (PyTuple_Check(v) || PyList_Check(v)) { - return PyDec_FromSequence(v, context); + return PyDec_FromSequence(state, v, context); } else if (PyFloat_Check(v)) { if (dec_addstatus(context, MPD_Float_operation)) { return NULL; } - return PyDec_FromFloat(v, context); + return PyDec_FromFloat(state, v, context); } else { PyErr_Format(PyExc_TypeError, @@ -2887,13 +2911,13 @@ ctx_create_decimal(PyObject *context, PyObject *args) Py_LOCAL_INLINE(int) convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) { - - if (PyDec_Check(v)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDec_Check(state, v)) { *conv = Py_NewRef(v); return 1; } if (PyLong_Check(v)) { - *conv = PyDec_FromLongExact(v, context); + *conv = PyDec_FromLongExact(state, v, context); if (*conv == NULL) { return 0; } @@ -2992,7 +3016,8 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) if (tmp == NULL) { return NULL; } - denom = PyDec_FromLongExact(tmp, context); + decimal_state *state = GLOBAL_STATE(); + denom = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); if (denom == NULL) { return NULL; @@ -3004,7 +3029,7 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) PyErr_NoMemory(); return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(denom); mpd_del(vv); @@ -3046,7 +3071,8 @@ numerator_as_decimal(PyObject *r, PyObject *context) return NULL; } - num = PyDec_FromLongExact(tmp, context); + decimal_state *state = GLOBAL_STATE(); + num = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); return num; } @@ -3064,11 +3090,12 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, *vcmp = v; - if (PyDec_Check(w)) { + decimal_state *state = GLOBAL_STATE(); + if (PyDec_Check(state, w)) { *wcmp = Py_NewRef(w); } else if (PyLong_Check(w)) { - *wcmp = PyDec_FromLongExact(w, context); + *wcmp = PyDec_FromLongExact(state, w, context); } else if (PyFloat_Check(w)) { if (op != Py_EQ && op != Py_NE && @@ -3077,7 +3104,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } else { ctx->status |= MPD_Float_operation; - *wcmp = PyDec_FromFloatExact(w, context); + *wcmp = PyDec_FromFloatExact(state, w, context); } } else if (PyComplex_Check(w) && (op == Py_EQ || op == Py_NE)) { @@ -3092,7 +3119,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } else { ctx->status |= MPD_Float_operation; - *wcmp = PyDec_FromFloatExact(tmp, context); + *wcmp = PyDec_FromFloatExact(state, tmp, context); Py_DECREF(tmp); } } @@ -3624,7 +3651,8 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) CURRENT_CONTEXT(context); - tmp = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + tmp = dec_alloc(state); if (tmp == NULL) { return NULL; } @@ -3724,7 +3752,7 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3766,7 +3794,7 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3841,7 +3869,8 @@ PyDec_Round(PyObject *dec, PyObject *args) if (y == -1 && PyErr_Occurred()) { return NULL; } - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3969,8 +3998,9 @@ nm_##MPDFUNC(PyObject *self) \ PyObject *context; \ uint32_t status = 0; \ \ + decimal_state *state = GLOBAL_STATE(); \ CURRENT_CONTEXT(context); \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ \ @@ -3996,7 +4026,8 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ CURRENT_CONTEXT(context) ; \ CONVERT_BINOP(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4056,7 +4087,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ decimal_state *state = GLOBAL_STATE(); \ CONTEXT_CHECK_VA(state, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ \ @@ -4089,7 +4120,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4127,7 +4158,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4160,7 +4191,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ Py_DECREF(c); \ @@ -4222,13 +4253,14 @@ nm_mpd_qdivmod(PyObject *v, PyObject *w) CURRENT_CONTEXT(context); CONVERT_BINOP(&a, &b, v, w, context); - q = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); Py_DECREF(b); return NULL; } - r = dec_alloc(); + r = dec_alloc(state); if (r == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4270,7 +4302,8 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) } } - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4371,7 +4404,8 @@ dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) { PyObject *result; - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -4386,7 +4420,8 @@ dec_mpd_qcopy_abs(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - if ((result = dec_alloc()) == NULL) { + decimal_state *state = GLOBAL_STATE(); + if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4406,7 +4441,8 @@ dec_mpd_qcopy_negate(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - if ((result = dec_alloc()) == NULL) { + decimal_state *state = GLOBAL_STATE(); + if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4492,7 +4528,7 @@ dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4574,7 +4610,7 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) CONVERT_BINOP_RAISE(&a, &b, v, w, context); - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4603,7 +4639,10 @@ dec_richcompare(PyObject *v, PyObject *w, int op) int a_issnan, b_issnan; int r; - assert(PyDec_Check(v)); +#ifdef NDEBUG + decimal_state *state = GLOBAL_STATE(); + assert(PyDec_Check(state, v)); +#endif CURRENT_CONTEXT(context); CONVERT_BINOP_CMP(&a, &b, v, w, op, context); @@ -4874,7 +4913,8 @@ dec_imag(PyObject *self UNUSED, void *closure UNUSED) { PyObject *result; - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -4891,43 +4931,6 @@ static PyGetSetDef dec_getsets [] = {NULL} }; -static PyNumberMethods dec_number_methods = -{ - (binaryfunc) nm_mpd_qadd, - (binaryfunc) nm_mpd_qsub, - (binaryfunc) nm_mpd_qmul, - (binaryfunc) nm_mpd_qrem, - (binaryfunc) nm_mpd_qdivmod, - (ternaryfunc) nm_mpd_qpow, - (unaryfunc) nm_mpd_qminus, - (unaryfunc) nm_mpd_qplus, - (unaryfunc) nm_mpd_qabs, - (inquiry) nm_nonzero, - (unaryfunc) 0, /* no bit-complement */ - (binaryfunc) 0, /* no shiftl */ - (binaryfunc) 0, /* no shiftr */ - (binaryfunc) 0, /* no bit-and */ - (binaryfunc) 0, /* no bit-xor */ - (binaryfunc) 0, /* no bit-ior */ - (unaryfunc) nm_dec_as_long, - 0, /* nb_reserved */ - (unaryfunc) PyDec_AsFloat, - 0, /* binaryfunc nb_inplace_add; */ - 0, /* binaryfunc nb_inplace_subtract; */ - 0, /* binaryfunc nb_inplace_multiply; */ - 0, /* binaryfunc nb_inplace_remainder; */ - 0, /* ternaryfunc nb_inplace_power; */ - 0, /* binaryfunc nb_inplace_lshift; */ - 0, /* binaryfunc nb_inplace_rshift; */ - 0, /* binaryfunc nb_inplace_and; */ - 0, /* binaryfunc nb_inplace_xor; */ - 0, /* binaryfunc nb_inplace_or; */ - (binaryfunc) nm_mpd_qdivint, /* binaryfunc nb_floor_divide; */ - (binaryfunc) nm_mpd_qdiv, /* binaryfunc nb_true_divide; */ - 0, /* binaryfunc nb_inplace_floor_divide; */ - 0, /* binaryfunc nb_inplace_true_divide; */ -}; - static PyMethodDef dec_methods [] = { /* Unary arithmetic functions, optional context arg */ @@ -5020,48 +5023,43 @@ static PyMethodDef dec_methods [] = { NULL, NULL, 1 } }; -static PyTypeObject PyDec_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.Decimal", /* tp_name */ - sizeof(PyDecObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) dec_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) dec_repr, /* tp_repr */ - &dec_number_methods, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) dec_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) dec_str, /* tp_str */ - (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - (Py_TPFLAGS_DEFAULT| - Py_TPFLAGS_BASETYPE), /* tp_flags */ - doc_decimal, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - dec_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - dec_methods, /* tp_methods */ - 0, /* tp_members */ - dec_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dec_new, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot dec_slots[] = { + {Py_tp_dealloc, dec_dealloc}, + {Py_tp_traverse, dec_traverse}, + {Py_tp_repr, dec_repr}, + {Py_tp_hash, dec_hash}, + {Py_tp_str, dec_str}, + {Py_tp_doc, (void *)doc_decimal}, + {Py_tp_richcompare, dec_richcompare}, + {Py_tp_methods, dec_methods}, + {Py_tp_getset, dec_getsets}, + {Py_tp_new, dec_new}, + + // Number protocol + {Py_nb_add, nm_mpd_qadd}, + {Py_nb_subtract, nm_mpd_qsub}, + {Py_nb_multiply, nm_mpd_qmul}, + {Py_nb_remainder, nm_mpd_qrem}, + {Py_nb_divmod, nm_mpd_qdivmod}, + {Py_nb_power, nm_mpd_qpow}, + {Py_nb_negative, nm_mpd_qminus}, + {Py_nb_positive, nm_mpd_qplus}, + {Py_nb_absolute, nm_mpd_qabs}, + {Py_nb_bool, nm_nonzero}, + {Py_nb_int, nm_dec_as_long}, + {Py_nb_float, PyDec_AsFloat}, + {Py_nb_floor_divide, nm_mpd_qdivint}, + {Py_nb_true_divide, nm_mpd_qdiv}, + {0, NULL}, +}; + + +static PyType_Spec dec_spec = { + .name = "decimal.Decimal", + .basicsize = sizeof(PyDecObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = dec_slots, }; @@ -5113,8 +5111,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ uint32_t status = 0; \ \ CONVERT_OP_RAISE(&a, v, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ return NULL; \ } \ @@ -5144,8 +5142,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -5179,8 +5177,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -5208,8 +5206,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = GLOBAL_STATE(); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ Py_DECREF(c); \ @@ -5274,14 +5272,14 @@ ctx_mpd_qdivmod(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - - q = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); Py_DECREF(b); return NULL; } - r = dec_alloc(); + r = dec_alloc(state); if (r == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5329,7 +5327,8 @@ ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5380,7 +5379,8 @@ DecCtx_BoolFunc_NO_CTX(mpd_iszero) static PyObject * ctx_iscanonical(PyObject *context UNUSED, PyObject *v) { - if (!PyDec_Check(v)) { + decimal_state *state = GLOBAL_STATE(); + if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); return NULL; @@ -5405,7 +5405,8 @@ PyDecContext_Apply(PyObject *context, PyObject *v) static PyObject * ctx_canonical(PyObject *context UNUSED, PyObject *v) { - if (!PyDec_Check(v)) { + decimal_state *state = GLOBAL_STATE(); + if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); return NULL; @@ -5421,8 +5422,8 @@ ctx_mpd_qcopy_abs(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); return NULL; @@ -5454,8 +5455,8 @@ ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); return NULL; @@ -5551,8 +5552,8 @@ ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - - result = dec_alloc(); + decimal_state *state = GLOBAL_STATE(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5862,8 +5863,6 @@ PyInit__decimal(void) /* Init types */ - PyDec_Type.tp_base = &PyBaseObject_Type; - #define CREATE_TYPE(mod, type, spec) \ do { \ type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ @@ -5871,14 +5870,14 @@ PyInit__decimal(void) } while (0) decimal_state *state = GLOBAL_STATE(); - CHECK_INT(PyType_Ready(&PyDec_Type)); + CREATE_TYPE(m, state->PyDec_Type, &dec_spec); CREATE_TYPE(m, state->PyDecContext_Type, &context_spec); CREATE_TYPE(m, state->PyDecSignalDictMixin_Type, &signaldict_spec); CREATE_TYPE(m, state->PyDecContextManager_Type, &ctxmanager_spec); #undef CREATE_TYPE ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); - CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(state->PyDec_Type->tp_dict, "__module__", obj)); CHECK_INT(PyDict_SetItemString(state->PyDecContext_Type->tp_dict, "__module__", obj)); Py_CLEAR(obj); @@ -5889,7 +5888,7 @@ PyInit__decimal(void) ASSIGN_PTR(Number, PyObject_GetAttrString(numbers, "Number")); /* Register Decimal with the Number abstract base class */ ASSIGN_PTR(obj, PyObject_CallMethod(Number, "register", "(O)", - (PyObject *)&PyDec_Type)); + (PyObject *)state->PyDec_Type)); Py_CLEAR(obj); /* Rational is a global variable used for fraction comparisons. */ ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); @@ -5912,7 +5911,7 @@ PyInit__decimal(void) ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections_abc, "MutableMapping")); /* Create SignalDict type */ - ASSIGN_PTR(PyDecSignalDict_Type, + ASSIGN_PTR(state->PyDecSignalDict_Type, (PyTypeObject *)PyObject_CallFunction( (PyObject *)&PyType_Type, "s(OO){}", "SignalDict", state->PyDecSignalDictMixin_Type, @@ -5928,7 +5927,7 @@ PyInit__decimal(void) ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); /* Add types to the module */ - CHECK_INT(PyModule_AddObject(m, "Decimal", Py_NewRef(&PyDec_Type))); + CHECK_INT(PyModule_AddType(m, state->PyDec_Type)); CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); CHECK_INT(PyModule_AddObject(m, "DecimalTuple", Py_NewRef(DecimalTuple))); diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 0f73632a4693be..15b44ceeb98191 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -386,7 +386,6 @@ Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - -Modules/_decimal/_decimal.c - PyDec_Type - Modules/_pickle.c - Pdata_Type - Modules/_pickle.c - PicklerMemoProxyType - Modules/_pickle.c - Pickler_Type - @@ -406,7 +405,6 @@ Modules/xxsubtype.c - spamlist_type - ## heap types Modules/_decimal/_decimal.c - DecimalTuple - -Modules/_decimal/_decimal.c - PyDecSignalDict_Type - Modules/_tkinter.c - PyTclObject_Type - Modules/_tkinter.c - Tkapp_Type - Modules/_tkinter.c - Tktt_Type - From f9c3573c7d0f2d497d0e6bd3e901e23892042e65 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 14 Mar 2023 09:16:01 +0100 Subject: [PATCH 08/27] Add DecimalTuple to state --- Modules/_decimal/_decimal.c | 15 ++++++++------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index b31c99c732fadb..34a9498bbf046c 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -44,6 +44,7 @@ typedef struct { PyTypeObject *PyDecSignalDictMixin_Type; PyTypeObject *PyDec_Type; PyTypeObject *PyDecSignalDict_Type; + PyTypeObject *DecimalTuple; } decimal_state; static decimal_state global_state; @@ -3889,7 +3890,6 @@ PyDec_Round(PyObject *dec, PyObject *args) } } -static PyTypeObject *DecimalTuple = NULL; /* Return the DecimalTuple representation of a PyDecObject. */ static PyObject * PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) @@ -3972,7 +3972,8 @@ PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) } } - result = PyObject_CallFunctionObjArgs((PyObject *)DecimalTuple, + decimal_state *state = GLOBAL_STATE(); + result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); out: @@ -5851,6 +5852,7 @@ PyInit__decimal(void) mpd_free = PyMem_Free; mpd_setminalloc(_Py_DEC_MINALLOC); + decimal_state *state = GLOBAL_STATE(); /* Init external C-API functions */ _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -5869,7 +5871,6 @@ PyInit__decimal(void) CHECK_PTR(type); \ } while (0) - decimal_state *state = GLOBAL_STATE(); CREATE_TYPE(m, state->PyDec_Type, &dec_spec); CREATE_TYPE(m, state->PyDecContext_Type, &context_spec); CREATE_TYPE(m, state->PyDecSignalDictMixin_Type, &signaldict_spec); @@ -5898,12 +5899,12 @@ PyInit__decimal(void) /* DecimalTuple */ ASSIGN_PTR(collections, PyImport_ImportModule("collections")); - ASSIGN_PTR(DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, + ASSIGN_PTR(state->DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, "namedtuple", "(ss)", "DecimalTuple", "sign digits exponent")); ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); - CHECK_INT(PyDict_SetItemString(DecimalTuple->tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(state->DecimalTuple->tp_dict, "__module__", obj)); Py_CLEAR(obj); /* MutableMapping */ @@ -5929,7 +5930,7 @@ PyInit__decimal(void) /* Add types to the module */ CHECK_INT(PyModule_AddType(m, state->PyDec_Type)); CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); - CHECK_INT(PyModule_AddObject(m, "DecimalTuple", Py_NewRef(DecimalTuple))); + CHECK_INT(PyModule_AddObjectRef(m, "DecimalTuple", state->DecimalTuple)); /* Create top level exception */ ASSIGN_PTR(DecimalException, PyErr_NewException( @@ -6074,7 +6075,7 @@ PyInit__decimal(void) Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 15b44ceeb98191..515a2284345d47 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -404,7 +404,6 @@ Modules/xxsubtype.c - spamlist_type - ## non-static types - initialized once ## heap types -Modules/_decimal/_decimal.c - DecimalTuple - Modules/_tkinter.c - PyTclObject_Type - Modules/_tkinter.c - Tkapp_Type - Modules/_tkinter.c - Tktt_Type - From 57316db77b9ad85463d7bd85c7630853406f555a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 14 Mar 2023 09:20:36 +0100 Subject: [PATCH 09/27] fixup! Add DecimalTuple to state --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 34a9498bbf046c..164308e1cd0237 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -5930,7 +5930,7 @@ PyInit__decimal(void) /* Add types to the module */ CHECK_INT(PyModule_AddType(m, state->PyDec_Type)); CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); - CHECK_INT(PyModule_AddObjectRef(m, "DecimalTuple", state->DecimalTuple)); + CHECK_INT(PyModule_AddType(m, state->DecimalTuple)); /* Create top level exception */ ASSIGN_PTR(DecimalException, PyErr_NewException( From 30e4128c68b2a12455d4dc92bc948f398afe9882 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 14 Mar 2023 09:21:54 +0100 Subject: [PATCH 10/27] Add DecimalException to state --- Modules/_decimal/_decimal.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 164308e1cd0237..f2761a72018dbf 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -45,6 +45,9 @@ typedef struct { PyTypeObject *PyDec_Type; PyTypeObject *PyDecSignalDict_Type; PyTypeObject *DecimalTuple; + + /* Top level Exception; inherits from ArithmeticError */ + PyObject *DecimalException; } decimal_state; static decimal_state global_state; @@ -164,9 +167,6 @@ typedef struct { PyObject *ex; /* corresponding exception */ } DecCondMap; -/* Top level Exception; inherits from ArithmeticError */ -static PyObject *DecimalException = NULL; - /* Exceptions that correspond to IEEE signals */ #define SUBNORMAL 5 #define INEXACT 6 @@ -5933,10 +5933,10 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddType(m, state->DecimalTuple)); /* Create top level exception */ - ASSIGN_PTR(DecimalException, PyErr_NewException( + ASSIGN_PTR(state->DecimalException, PyErr_NewException( "decimal.DecimalException", PyExc_ArithmeticError, NULL)); - CHECK_INT(PyModule_AddObject(m, "DecimalException", Py_NewRef(DecimalException))); + CHECK_INT(PyModule_AddType(m, (PyTypeObject *)state->DecimalException)); /* Create signal tuple */ ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); @@ -5949,10 +5949,10 @@ PyInit__decimal(void) switch (cm->flag) { case MPD_Float_operation: - base = PyTuple_Pack(2, DecimalException, PyExc_TypeError); + base = PyTuple_Pack(2, state->DecimalException, PyExc_TypeError); break; case MPD_Division_by_zero: - base = PyTuple_Pack(2, DecimalException, PyExc_ZeroDivisionError); + base = PyTuple_Pack(2, state->DecimalException, PyExc_ZeroDivisionError); break; case MPD_Overflow: base = PyTuple_Pack(2, signal_map[INEXACT].ex, @@ -5964,7 +5964,7 @@ PyInit__decimal(void) signal_map[SUBNORMAL].ex); break; default: - base = PyTuple_Pack(1, DecimalException); + base = PyTuple_Pack(1, state->DecimalException); break; } From f92e385c974514a75ed0e144f315f90f605125c5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 14 Mar 2023 09:22:05 +0100 Subject: [PATCH 11/27] fixup! Add DecimalException to state --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 1 file changed, 1 deletion(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 515a2284345d47..ac6c9f37ca1e62 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -412,7 +412,6 @@ Modules/xxlimited_35.c - Xxo_Type - ## exception types Modules/_ctypes/_ctypes.c - PyExc_ArgError - Modules/_cursesmodule.c - PyCursesError - -Modules/_decimal/_decimal.c - DecimalException - Modules/_tkinter.c - Tkinter_TclError - Modules/ossaudiodev.c - OSSAudioError - Modules/socketmodule.c - socket_herror - From 8b6c0c70b1a7f5a0306285a315a4f647e1bc1073 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Thu, 30 Mar 2023 16:04:37 +0800 Subject: [PATCH 12/27] Add `basic_context_template` to state --- Modules/_decimal/_decimal.c | 18 ++++++++++-------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index f2761a72018dbf..457a2bdb85cbca 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -48,6 +48,9 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; + + /* Basic and extended context templates */ + PyObject *basic_context_template; } decimal_state; static decimal_state global_state; @@ -150,8 +153,7 @@ static PyObject *current_context_var = NULL; /* Template for creating new thread contexts, calling Context() without * arguments and initializing the module_context on first access. */ static PyObject *default_context_template = NULL; -/* Basic and extended context templates */ -static PyObject *basic_context_template = NULL; + static PyObject *extended_context_template = NULL; @@ -1652,7 +1654,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ if (v == default_context_template || - v == basic_context_template || + v == state->basic_context_template || v == extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { @@ -1733,7 +1735,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ if (v == default_context_template || - v == basic_context_template || + v == state->basic_context_template || v == extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { @@ -6025,11 +6027,11 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); /* Init basic context template */ - ASSIGN_PTR(basic_context_template, + ASSIGN_PTR(state->basic_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); - init_basic_context(basic_context_template); + init_basic_context(state->basic_context_template); CHECK_INT(PyModule_AddObject(m, "BasicContext", - Py_NewRef(basic_context_template))); + Py_NewRef(state->basic_context_template))); /* Init extended context template */ ASSIGN_PTR(extended_context_template, @@ -6082,7 +6084,7 @@ PyInit__decimal(void) #else Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ #endif - Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(m); /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index ac6c9f37ca1e62..4f14879c035cab 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -443,7 +443,6 @@ Modules/_datetimemodule.c - us_per_hour - Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - -Modules/_decimal/_decimal.c - basic_context_template - Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - default_context_template - Modules/_decimal/_decimal.c - extended_context_template - From 2ea6d98cf2c995f9ef0cfcacd413d69e772cd52c Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Thu, 30 Mar 2023 16:23:45 +0800 Subject: [PATCH 13/27] Add `extended_context_template` to state --- Modules/_decimal/_decimal.c | 16 +++++++--------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 457a2bdb85cbca..e3f4794dafa322 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -51,6 +51,7 @@ typedef struct { /* Basic and extended context templates */ PyObject *basic_context_template; + PyObject *extended_context_template; } decimal_state; static decimal_state global_state; @@ -154,9 +155,6 @@ static PyObject *current_context_var = NULL; * arguments and initializing the module_context on first access. */ static PyObject *default_context_template = NULL; -static PyObject *extended_context_template = NULL; - - /* Error codes for functions that return signals or conditions */ #define DEC_INVALID_SIGNALS (MPD_Max_status+1U) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) @@ -1655,7 +1653,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) * This is the current behavior of decimal.py. */ if (v == default_context_template || v == state->basic_context_template || - v == extended_context_template) { + v == state->extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { return NULL; @@ -1736,7 +1734,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) * This is the current behavior of decimal.py. */ if (v == default_context_template || v == state->basic_context_template || - v == extended_context_template) { + v == state->extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { return NULL; @@ -6034,11 +6032,11 @@ PyInit__decimal(void) Py_NewRef(state->basic_context_template))); /* Init extended context template */ - ASSIGN_PTR(extended_context_template, + ASSIGN_PTR(state->extended_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); - init_extended_context(extended_context_template); + init_extended_context(state->extended_context_template); CHECK_INT(PyModule_AddObject(m, "ExtendedContext", - Py_NewRef(extended_context_template))); + Py_NewRef(state->extended_context_template))); /* Init mpd_ssize_t constants */ @@ -6085,7 +6083,7 @@ PyInit__decimal(void) Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ #endif Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */ - Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(m); /* GCOV_NOT_REACHED */ return NULL; /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 4f14879c035cab..9deea8dee86a0c 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -445,7 +445,6 @@ Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - default_context_template - -Modules/_decimal/_decimal.c - extended_context_template - Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - From 7bf48be862091791fa7d58efff724e51fbc8c640 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Thu, 30 Mar 2023 18:24:12 +0800 Subject: [PATCH 14/27] Add `default_context_template` to state --- Modules/_decimal/_decimal.c | 28 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index e3f4794dafa322..c57734bcb901bf 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -49,6 +49,10 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; + /* Template for creating new thread contexts, calling Context() without + * arguments and initializing the module_context on first access. */ + PyObject *default_context_template; + /* Basic and extended context templates */ PyObject *basic_context_template; PyObject *extended_context_template; @@ -151,9 +155,7 @@ static PyDecContextObject *cached_context = NULL; static PyObject *current_context_var = NULL; #endif -/* Template for creating new thread contexts, calling Context() without - * arguments and initializing the module_context on first access. */ -static PyObject *default_context_template = NULL; + /* Error codes for functions that return signals or conditions */ #define DEC_INVALID_SIGNALS (MPD_Max_status+1U) @@ -1271,8 +1273,8 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) ctx = CTX(self); - if (default_context_template) { - *ctx = *CTX(default_context_template); + if (state->default_context_template) { + *ctx = *CTX(state->default_context_template); } else { *ctx = dflt_ctx; @@ -1554,6 +1556,7 @@ static PyObject * current_context_from_dict(void) { PyThreadState *tstate = _PyThreadState_GET(); + decimal_state *state = GLOBAL_STATE(); #ifdef Py_DEBUG // The caller must hold the GIL _Py_EnsureTstateNotNULL(tstate); @@ -1569,7 +1572,6 @@ current_context_from_dict(void) PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ - decimal_state *state = GLOBAL_STATE(); CONTEXT_CHECK(state, tl_context); } else { @@ -1578,7 +1580,7 @@ current_context_from_dict(void) } /* Set up a new thread local context. */ - tl_context = context_copy(default_context_template, NULL); + tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } @@ -1651,7 +1653,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ - if (v == default_context_template || + if (v == state->default_context_template || v == state->basic_context_template || v == state->extended_context_template) { v = context_copy(v, NULL); @@ -1677,7 +1679,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) static PyObject * init_current_context(void) { - PyObject *tl_context = context_copy(default_context_template, NULL); + PyObject *tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } @@ -1732,7 +1734,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ - if (v == default_context_template || + if (v == state->default_context_template || v == state->basic_context_template || v == state->extended_context_template) { v = context_copy(v, NULL); @@ -6010,10 +6012,10 @@ PyInit__decimal(void) /* Init default context template first */ - ASSIGN_PTR(default_context_template, + ASSIGN_PTR(state->default_context_template, PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); CHECK_INT(PyModule_AddObject(m, "DefaultContext", - Py_NewRef(default_context_template))); + Py_NewRef(state->default_context_template))); #ifndef WITH_DECIMAL_CONTEXTVAR ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); @@ -6076,7 +6078,7 @@ PyInit__decimal(void) Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ #else diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 9deea8dee86a0c..11b1972c707d6d 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -444,7 +444,6 @@ Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - Modules/_decimal/_decimal.c - current_context_var - -Modules/_decimal/_decimal.c - default_context_template - Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - From cd41d2c034024fa1105a90f091c374ed6947f373 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Fri, 31 Mar 2023 15:13:16 +0800 Subject: [PATCH 15/27] Add context var to state --- Modules/_decimal/_decimal.c | 58 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index c57734bcb901bf..0d28f155b9117a 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -49,6 +49,15 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; + #ifndef WITH_DECIMAL_CONTEXTVAR + /* Key for thread state dictionary */ + PyObject *tls_context_key; + /* Invariant: NULL or the most recently accessed thread local context */ + PyDecContextObject *cached_context; + #else + PyObject *current_context_var; + #endif + /* Template for creating new thread contexts, calling Context() without * arguments and initializing the module_context on first access. */ PyObject *default_context_template; @@ -146,17 +155,6 @@ incr_false(void) } -#ifndef WITH_DECIMAL_CONTEXTVAR -/* Key for thread state dictionary */ -static PyObject *tls_context_key = NULL; -/* Invariant: NULL or the most recently accessed thread local context */ -static PyDecContextObject *cached_context = NULL; -#else -static PyObject *current_context_var = NULL; -#endif - - - /* Error codes for functions that return signals or conditions */ #define DEC_INVALID_SIGNALS (MPD_Max_status+1U) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) @@ -1314,10 +1312,11 @@ static void context_dealloc(PyDecContextObject *self) { PyTypeObject *tp = Py_TYPE(self); + decimal_state *state = GLOBAL_STATE(); // FIXME: add find_module_state_by_def(self) PyObject_GC_UnTrack(self); #ifndef WITH_DECIMAL_CONTEXTVAR - if (self == cached_context) { - cached_context = NULL; + if (self == state->cached_context) { + state->cached_context = NULL; } #endif (void)context_clear(self); @@ -1569,7 +1568,7 @@ current_context_from_dict(void) return NULL; } - PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); + PyObject *tl_context = PyDict_GetItemWithError(dict, state->tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ CONTEXT_CHECK(state, tl_context); @@ -1586,7 +1585,7 @@ current_context_from_dict(void) } CTX(tl_context)->status = 0; - if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) { + if (PyDict_SetItem(dict, state->tls_context_key, tl_context) < 0) { Py_DECREF(tl_context); return NULL; } @@ -1595,8 +1594,8 @@ current_context_from_dict(void) /* Cache the context of the current thread, assuming that it * will be accessed several times before a thread switch. */ - cached_context = (PyDecContextObject *)tl_context; - cached_context->tstate = tstate; + state->cached_context = (PyDecContextObject *)tl_context; + state->cached_context->tstate = tstate; /* Borrowed reference with refcount==1 */ return tl_context; @@ -1607,8 +1606,9 @@ static PyObject * current_context(void) { PyThreadState *tstate = _PyThreadState_GET(); - if (cached_context && cached_context->tstate == tstate) { - return (PyObject *)cached_context; + decimal_state *state = GLOBAL_STATE(); + if (state->cached_context && state->cached_context->tstate == tstate) { + return (PyObject *)(state->cached_context); } return current_context_from_dict(); @@ -1666,8 +1666,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - cached_context = NULL; - if (PyDict_SetItem(dict, tls_context_key, v) < 0) { + state->cached_context = NULL; + if (PyDict_SetItem(dict, state->tls_context_key, v) < 0) { Py_DECREF(v); return NULL; } @@ -1680,12 +1680,13 @@ static PyObject * init_current_context(void) { PyObject *tl_context = context_copy(state->default_context_template, NULL); + decimal_state *state = GLOBAL_STATE(); if (tl_context == NULL) { return NULL; } CTX(tl_context)->status = 0; - PyObject *tok = PyContextVar_Set(current_context_var, tl_context); + PyObject *tok = PyContextVar_Set(state->current_context_var, tl_context); if (tok == NULL) { Py_DECREF(tl_context); return NULL; @@ -1699,7 +1700,8 @@ static inline PyObject * current_context(void) { PyObject *tl_context; - if (PyContextVar_Get(current_context_var, NULL, &tl_context) < 0) { + decimal_state *state = GLOBAL_STATE(); + if (PyContextVar_Get(state->current_context_var, NULL, &tl_context) < 0) { return NULL; } @@ -1747,7 +1749,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - PyObject *tok = PyContextVar_Set(current_context_var, v); + PyObject *tok = PyContextVar_Set(state->current_context_var, v); Py_DECREF(v); if (tok == NULL) { return NULL; @@ -6018,10 +6020,10 @@ PyInit__decimal(void) Py_NewRef(state->default_context_template))); #ifndef WITH_DECIMAL_CONTEXTVAR - ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); + ASSIGN_PTR(state->tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_False))); #else - ASSIGN_PTR(current_context_var, PyContextVar_New("decimal_context", NULL)); + ASSIGN_PTR(state->current_context_var, PyContextVar_New("decimal_context", NULL)); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_True))); #endif CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); @@ -6080,9 +6082,9 @@ PyInit__decimal(void) Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR - Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->tls_context_key); /* GCOV_NOT_REACHED */ #else - Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->current_context_var); /* GCOV_NOT_REACHED */ #endif Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 11b1972c707d6d..0137eba79c3a1e 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -443,7 +443,6 @@ Modules/_datetimemodule.c - us_per_hour - Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - -Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - From 44b08438b8fd37b80cc32beb334a5f37c771ba28 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Fri, 31 Mar 2023 15:30:18 +0800 Subject: [PATCH 16/27] fixup! Add default_context_template to state --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 0d28f155b9117a..39db5a98935f38 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1679,8 +1679,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) static PyObject * init_current_context(void) { - PyObject *tl_context = context_copy(state->default_context_template, NULL); decimal_state *state = GLOBAL_STATE(); + PyObject *tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } From db7b9885093df325b1ad096b56593e3d4456dc5a Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Fri, 31 Mar 2023 16:42:54 +0800 Subject: [PATCH 17/27] Add round_map to state --- Modules/_decimal/_decimal.c | 27 ++++++++++++--------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 39db5a98935f38..d125f7f2f1b1ed 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -38,6 +38,12 @@ #include "docstrings.h" +#ifdef EXTRA_FUNCTIONALITY + #define _PY_DEC_ROUND_GUARD MPD_ROUND_GUARD +#else + #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) +#endif + typedef struct { PyTypeObject *PyDecContextManager_Type; PyTypeObject *PyDecContext_Type; @@ -65,6 +71,8 @@ typedef struct { /* Basic and extended context templates */ PyObject *basic_context_template; PyObject *extended_context_template; + + PyObject *round_map[_PY_DEC_ROUND_GUARD]; } decimal_state; static decimal_state global_state; @@ -216,13 +224,6 @@ static const char *dec_signal_string[MPD_NUM_FLAGS] = { "Underflow", }; -#ifdef EXTRA_FUNCTIONALITY - #define _PY_DEC_ROUND_GUARD MPD_ROUND_GUARD -#else - #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) -#endif -static PyObject *round_map[_PY_DEC_ROUND_GUARD]; - static const char *invalid_rounding_err = "valid values for rounding are:\n\ [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n\ @@ -520,15 +521,16 @@ static int getround(PyObject *v) { int i; + decimal_state *state = GLOBAL_STATE(); if (PyUnicode_Check(v)) { for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - if (v == round_map[i]) { + if (v == state->round_map[i]) { return i; } } for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - if (PyUnicode_Compare(v, round_map[i]) == 0) { + if (PyUnicode_Compare(v, state->round_map[i]) == 0) { return i; } } @@ -753,8 +755,9 @@ static PyObject * context_getround(PyObject *self, void *closure UNUSED) { int i = mpd_getround(CTX(self)); + decimal_state *state = GLOBAL_STATE(); - return Py_NewRef(round_map[i]); + return Py_NewRef(state->round_map[i]); } static PyObject * @@ -6058,8 +6061,8 @@ PyInit__decimal(void) /* Init string constants */ for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - ASSIGN_PTR(round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); - CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(round_map[i]))); + ASSIGN_PTR(state->round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); + CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(state->round_map[i]))); } /* Add specification version number */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 0137eba79c3a1e..d2b3e877d24524 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -443,7 +443,6 @@ Modules/_datetimemodule.c - us_per_hour - Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - -Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - Modules/arraymodule.c array_array___reduce_ex___impl array_reconstructor - From 86170a2f306dec8fbc653fca5051b449c21e3c99 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Fri, 31 Mar 2023 17:22:58 +0800 Subject: [PATCH 18/27] Add `Rational` and `SignalTuple` to state --- Modules/_decimal/_decimal.c | 23 ++++++++++++--------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 -- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index d125f7f2f1b1ed..cc017061fb0658 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -73,6 +73,11 @@ typedef struct { PyObject *extended_context_template; PyObject *round_map[_PY_DEC_ROUND_GUARD]; + + /* Convert rationals for comparison */ + PyObject *Rational; + + PyObject *SignalTuple; } decimal_state; static decimal_state global_state; @@ -563,11 +568,11 @@ signaldict_len(PyObject *self UNUSED) return SIGNAL_MAP_LEN; } -static PyObject *SignalTuple; static PyObject * signaldict_iter(PyObject *self UNUSED) { - return PyTuple_Type.tp_iter(SignalTuple); + decimal_state *state = GLOBAL_STATE(); // FIXME: use find_module_state_by_def + return PyTuple_Type.tp_iter(state->SignalTuple); } static PyObject * @@ -3006,8 +3011,6 @@ convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) /* Implicit conversions to Decimal for comparison */ /******************************************************************************/ -/* Convert rationals for comparison */ -static PyObject *Rational = NULL; static PyObject * multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) { @@ -3136,7 +3139,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } } else { - int is_rational = PyObject_IsInstance(w, Rational); + int is_rational = PyObject_IsInstance(w, state->Rational); if (is_rational < 0) { *wcmp = NULL; } @@ -5899,7 +5902,7 @@ PyInit__decimal(void) (PyObject *)state->PyDec_Type)); Py_CLEAR(obj); /* Rational is a global variable used for fraction comparisons. */ - ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); + ASSIGN_PTR(state->Rational, PyObject_GetAttrString(numbers, "Rational")); /* Done with numbers, Number */ Py_CLEAR(numbers); Py_CLEAR(Number); @@ -5946,7 +5949,7 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddType(m, (PyTypeObject *)state->DecimalException)); /* Create signal tuple */ - ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); + ASSIGN_PTR(state->SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); /* Add exceptions that correspond to IEEE signals */ for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) { @@ -5986,7 +5989,7 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); /* add to signal tuple */ - PyTuple_SET_ITEM(SignalTuple, i, Py_NewRef(cm->ex)); + PyTuple_SET_ITEM(state->SignalTuple, i, Py_NewRef(cm->ex)); } /* @@ -6077,11 +6080,11 @@ PyInit__decimal(void) Py_CLEAR(obj); /* GCOV_NOT_REACHED */ Py_CLEAR(numbers); /* GCOV_NOT_REACHED */ Py_CLEAR(Number); /* GCOV_NOT_REACHED */ - Py_CLEAR(Rational); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->Rational); /* GCOV_NOT_REACHED */ Py_CLEAR(collections); /* GCOV_NOT_REACHED */ Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ - Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->SignalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index d2b3e877d24524..3147553e3ebf14 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -443,8 +443,6 @@ Modules/_datetimemodule.c - us_per_hour - Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - -Modules/_decimal/_decimal.c - Rational - -Modules/_decimal/_decimal.c - SignalTuple - Modules/arraymodule.c array_array___reduce_ex___impl array_reconstructor - ## state From bc8df8fd726a8aaacd90d41e476d78edb7c4c13b Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Mon, 3 Apr 2023 15:53:11 +0800 Subject: [PATCH 19/27] Add external C-API functions to state --- Modules/_decimal/_decimal.c | 44 ++++++++++----------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 6 --- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index cc017061fb0658..a66d80ddc1756b 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -78,6 +78,14 @@ typedef struct { PyObject *Rational; PyObject *SignalTuple; + + /* External C-API functions */ + binaryfunc _py_long_multiply; + binaryfunc _py_long_floor_divide; + ternaryfunc _py_long_power; + unaryfunc _py_float_abs; + PyCFunction _py_long_bit_length; + PyCFunction _py_float_as_integer_ratio; } decimal_state; static decimal_state global_state; @@ -2313,14 +2321,6 @@ PyDecType_FromLongExact(PyTypeObject *type, PyObject *v, return dec; } -/* External C-API functions */ -static binaryfunc _py_long_multiply; -static binaryfunc _py_long_floor_divide; -static ternaryfunc _py_long_power; -static unaryfunc _py_float_abs; -static PyCFunction _py_long_bit_length; -static PyCFunction _py_float_as_integer_ratio; - /* Return a PyDecObject or a subtype from a PyFloatObject. Conversion is exact. */ static PyObject * @@ -2374,13 +2374,13 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, } /* absolute value of the float */ - tmp = _py_float_abs(v); + tmp = state->_py_float_abs(v); if (tmp == NULL) { return NULL; } /* float as integer ratio: numerator/denominator */ - n_d = _py_float_as_integer_ratio(tmp, NULL); + n_d = state->_py_float_as_integer_ratio(tmp, NULL); Py_DECREF(tmp); if (n_d == NULL) { return NULL; @@ -2388,7 +2388,7 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, n = PyTuple_GET_ITEM(n_d, 0); d = PyTuple_GET_ITEM(n_d, 1); - tmp = _py_long_bit_length(d, NULL); + tmp = state->_py_long_bit_length(d, NULL); if (tmp == NULL) { Py_DECREF(n_d); return NULL; @@ -3694,14 +3694,14 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) goto error; } - Py_SETREF(exponent, _py_long_power(tmp, exponent, Py_None)); + Py_SETREF(exponent, state->_py_long_power(tmp, exponent, Py_None)); Py_DECREF(tmp); if (exponent == NULL) { goto error; } if (exp >= 0) { - Py_SETREF(numerator, _py_long_multiply(numerator, exponent)); + Py_SETREF(numerator, state->_py_long_multiply(numerator, exponent)); if (numerator == NULL) { goto error; } @@ -3717,8 +3717,8 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) if (tmp == NULL) { goto error; } - Py_SETREF(numerator, _py_long_floor_divide(numerator, tmp)); - Py_SETREF(denominator, _py_long_floor_divide(denominator, tmp)); + Py_SETREF(numerator, state->_py_long_floor_divide(numerator, tmp)); + Py_SETREF(denominator, state->_py_long_floor_divide(denominator, tmp)); Py_DECREF(tmp); if (numerator == NULL || denominator == NULL) { goto error; @@ -5865,13 +5865,13 @@ PyInit__decimal(void) decimal_state *state = GLOBAL_STATE(); /* Init external C-API functions */ - _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; - _py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide; - _py_long_power = PyLong_Type.tp_as_number->nb_power; - _py_float_abs = PyFloat_Type.tp_as_number->nb_absolute; - ASSIGN_PTR(_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type, - "as_integer_ratio")); - ASSIGN_PTR(_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length")); + state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; + state->_py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide; + state->_py_long_power = PyLong_Type.tp_as_number->nb_power; + state->_py_float_abs = PyFloat_Type.tp_as_number->nb_absolute; + ASSIGN_PTR(state->_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type, + "as_integer_ratio")); + ASSIGN_PTR(state->_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length")); /* Init types */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 3147553e3ebf14..1fc41e7143dadd 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -473,12 +473,6 @@ Modules/_cursesmodule.c - initialised - Modules/_cursesmodule.c - initialised_setupterm - Modules/_cursesmodule.c - initialisedcolors - Modules/_cursesmodule.c - screen_encoding - -Modules/_decimal/_decimal.c - _py_long_multiply - -Modules/_decimal/_decimal.c - _py_long_floor_divide - -Modules/_decimal/_decimal.c - _py_long_power - -Modules/_decimal/_decimal.c - _py_float_abs - -Modules/_decimal/_decimal.c - _py_long_bit_length - -Modules/_decimal/_decimal.c - _py_float_as_integer_ratio - Modules/_elementtree.c - expat_capi - Modules/cjkcodecs/_codecs_hk.c - big5_encmap - Modules/cjkcodecs/_codecs_hk.c - big5_decmap - From 4ff1074b2c964e2dc09b4d0b2a0389339612b2a4 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Mon, 3 Apr 2023 19:52:50 +0800 Subject: [PATCH 20/27] port _decimal module to multi-initialization --- Modules/_decimal/_decimal.c | 126 +++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 22 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index a66d80ddc1756b..84358c9fb2fb5d 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -88,6 +88,7 @@ typedef struct { PyCFunction _py_float_as_integer_ratio; } decimal_state; +// FIXME: convert to module state. static decimal_state global_state; #define GLOBAL_STATE() (&global_state) @@ -2335,10 +2336,9 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, mpd_t *d1, *d2; uint32_t status = 0; mpd_context_t maxctx; - + decimal_state *state = GLOBAL_STATE(); #ifdef NDEBUG - decimal_state *state = GLOBAL_STATE(); assert(PyType_IsSubtype(type, state->PyDec_Type)); #endif @@ -5752,17 +5752,6 @@ static PyMethodDef _decimal_methods [] = { NULL, NULL, 1, NULL } }; -static struct PyModuleDef _decimal_module = { - PyModuleDef_HEAD_INIT, - "decimal", - doc__decimal, - -1, - _decimal_methods, - NULL, - NULL, - NULL, - NULL -}; struct ssize_constmap { const char *name; mpd_ssize_t val; }; static struct ssize_constmap ssize_constants [] = { @@ -5838,10 +5827,9 @@ cfunc_noargs(PyTypeObject *t, const char *name) } -PyMODINIT_FUNC -PyInit__decimal(void) +static int +_decimal_exec(PyObject *m) { - PyObject *m = NULL; PyObject *numbers = NULL; PyObject *Number = NULL; PyObject *collections = NULL; @@ -5933,10 +5921,6 @@ PyInit__decimal(void) Py_CLEAR(collections_abc); Py_CLEAR(MutableMapping); - - /* Create the module */ - ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); - /* Add types to the module */ CHECK_INT(PyModule_AddType(m, state->PyDec_Type)); CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); @@ -6073,7 +6057,7 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version())); - return m; + return 0; error: @@ -6096,5 +6080,103 @@ PyInit__decimal(void) Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */ Py_CLEAR(m); /* GCOV_NOT_REACHED */ - return NULL; /* GCOV_NOT_REACHED */ + return -1; /* GCOV_NOT_REACHED */ +} + +static int +decimal_traverse(PyObject *module, visitproc visit, void *arg) +{ + decimal_state *state = GLOBAL_STATE(); + Py_VISIT(state->PyDecContextManager_Type); + Py_VISIT(state->PyDecContext_Type); + Py_VISIT(state->PyDecSignalDictMixin_Type); + Py_VISIT(state->PyDec_Type); + Py_VISIT(state->PyDecSignalDict_Type); + Py_VISIT(state->DecimalTuple); + Py_VISIT(state->DecimalException); + +#ifndef WITH_DECIMAL_CONTEXTVAR + Py_VISIT(state->tls_context_key); + Py_VISIT(state->cached_context); +#else + Py_VISIT(state->current_context_var); +#endif + + Py_VISIT(state->default_context_template); + Py_VISIT(state->basic_context_template); + Py_VISIT(state->extended_context_template); + Py_VISIT(state->round_map); + Py_VISIT(state->Rational); + Py_VISIT(state->SignalTuple); + + Py_VISIT(state->_py_long_multiply); + Py_VISIT(state->_py_long_floor_divide); + Py_VISIT(state->_py_long_power); + Py_VISIT(state->_py_float_abs); + Py_VISIT(state->_py_long_bit_length); + Py_VISIT(state->_py_float_as_integer_ratio); +} + +static int +decimal_clear(PyObject *module) +{ + decimal_state *state = GLOBAL_STATE(); + Py_CLEAR(state->PyDecContextManager_Type); + Py_CLEAR(state->PyDecContext_Type); + Py_CLEAR(state->PyDecSignalDictMixin_Type); + Py_CLEAR(state->PyDec_Type); + Py_CLEAR(state->PyDecSignalDict_Type); + Py_CLEAR(state->DecimalTuple); + Py_CLEAR(state->DecimalException); + +#ifndef WITH_DECIMAL_CONTEXTVAR + Py_CLEAR(state->tls_context_key); + Py_CLEAR(state->cached_context); +#else + Py_CLEAR(state->current_context_var); +#endif + + Py_CLEAR(state->default_context_template); + Py_CLEAR(state->basic_context_template); + Py_CLEAR(state->extended_context_template); + Py_CLEAR(state->round_map); + Py_CLEAR(state->Rational); + Py_CLEAR(state->SignalTuple); + + Py_CLEAR(state->_py_long_multiply); + Py_CLEAR(state->_py_long_floor_divide); + Py_CLEAR(state->_py_long_power); + Py_CLEAR(state->_py_float_abs); + Py_CLEAR(state->_py_long_bit_length); + Py_CLEAR(state->_py_float_as_integer_ratio); +} + +static void +decimal_free(void *module) +{ + (void)module_clear((PyObject *)module); +} + +static struct PyModuleDef_Slot _decimal_slots[] = { + {Py_mod_exec, _decimal_exec}, + {0, NULL}, +}; + +static struct PyModuleDef _decimal_module = { + PyModuleDef_HEAD_INIT, + .m_name = "decimal", + .m_doc = doc__decimal, + .m_size = sizeof(decimal_state), + .m_methods = _decimal_methods, + .m_slots = _decimal_slots, + + .m_traverse = decimal_traverse, + .m_clear = decimal_clear, + .m_free = decimal_free, +}; + +PyMODINIT_FUNC +PyInit__decimal(void) +{ + return PyModuleDef_Init(&_decimal_module); } From 8fba9e87431f9e9f1228a9a4043a610bb8579347 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Mon, 3 Apr 2023 20:20:35 +0800 Subject: [PATCH 21/27] Move global state to module state --- Modules/_decimal/_decimal.c | 286 ++++++++++++++++++++---------------- 1 file changed, 157 insertions(+), 129 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 84358c9fb2fb5d..9e7c2d245405ba 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -55,14 +55,14 @@ typedef struct { /* Top level Exception; inherits from ArithmeticError */ PyObject *DecimalException; - #ifndef WITH_DECIMAL_CONTEXTVAR +#ifndef WITH_DECIMAL_CONTEXTVAR /* Key for thread state dictionary */ PyObject *tls_context_key; /* Invariant: NULL or the most recently accessed thread local context */ PyDecContextObject *cached_context; - #else +#else PyObject *current_context_var; - #endif +#endif /* Template for creating new thread contexts, calling Context() without * arguments and initializing the module_context on first access. */ @@ -88,10 +88,43 @@ typedef struct { PyCFunction _py_float_as_integer_ratio; } decimal_state; -// FIXME: convert to module state. -static decimal_state global_state; +static inline decimal_state * +get_module_state(PyObject *mod) +{ + decimal_state *state = _PyModule_GetState(mod); + assert(state != NULL); + return state; +} -#define GLOBAL_STATE() (&global_state) +static inline decimal_state * +get_module_state_by_cls(PyTypeObject *cls) +{ + decimal_state *state = (decimal_state *)PyType_GetModuleState(cls); + assert(state != NULL); + return state; +} + +static struct PyModuleDef _decimal_module; + +static inline decimal_state * +get_module_state_by_def(PyTypeObject *tp) +{ + PyObject *mod = PyType_GetModuleByDef(tp, &_decimal_module); + assert(mod != NULL); + return get_module_state(mod); +} + +static inline decimal_state * +find_state_left_or_right(PyObject *left, PyObject *right) +{ + PyObject *mod = PyType_GetModuleByDef(Py_TYPE(left), &_decimal_module); + if (mod == NULL) { + PyErr_Clear(); + mod = PyType_GetModuleByDef(Py_TYPE(right), &_decimal_module); + } + assert(mod != NULL); + return get_module_state(mod); +} #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000 @@ -465,6 +498,8 @@ dict_as_flags(PyObject *val) if (PyErr_Occurred()) { return DEC_ERR_OCCURRED; } + // FIXME: Raise error while running test_decimal.py + // Seems to be caused by static signal_map PyErr_SetString(PyExc_KeyError, "invalid signal dict"); return DEC_INVALID_SIGNALS; @@ -532,11 +567,9 @@ dec_addstatus(PyObject *context, uint32_t status) } static int -getround(PyObject *v) +getround(decimal_state *state, PyObject *v) { int i; - decimal_state *state = GLOBAL_STATE(); - if (PyUnicode_Check(v)) { for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { if (v == state->round_map[i]) { @@ -578,9 +611,9 @@ signaldict_len(PyObject *self UNUSED) } static PyObject * -signaldict_iter(PyObject *self UNUSED) +signaldict_iter(PyObject *self) { - decimal_state *state = GLOBAL_STATE(); // FIXME: use find_module_state_by_def + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); return PyTuple_Type.tp_iter(state->SignalTuple); } @@ -671,7 +704,7 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) { PyObject *res = Py_NotImplemented; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = find_state_left_or_right(v, w); assert(PyDecSignalDict_Check(state, v)); if (op == Py_EQ || op == Py_NE) { @@ -769,7 +802,7 @@ static PyObject * context_getround(PyObject *self, void *closure UNUSED) { int i = mpd_getround(CTX(self)); - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); return Py_NewRef(state->round_map[i]); } @@ -928,7 +961,8 @@ context_setround(PyObject *self, PyObject *value, void *closure UNUSED) mpd_context_t *ctx; int x; - x = getround(value); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + x = getround(state, value); if (x == -1) { return -1; } @@ -1006,7 +1040,7 @@ context_settraps_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } @@ -1071,7 +1105,7 @@ context_setstatus_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } @@ -1262,7 +1296,7 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) PyDecContextObject *self = NULL; mpd_context_t *ctx; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(type); if (type == state->PyDecContext_Type) { self = PyObject_GC_New(PyDecContextObject, state->PyDecContext_Type); } @@ -1329,9 +1363,9 @@ static void context_dealloc(PyDecContextObject *self) { PyTypeObject *tp = Py_TYPE(self); - decimal_state *state = GLOBAL_STATE(); // FIXME: add find_module_state_by_def(self) PyObject_GC_UnTrack(self); #ifndef WITH_DECIMAL_CONTEXTVAR + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if (self == state->cached_context) { state->cached_context = NULL; } @@ -1383,7 +1417,7 @@ context_repr(PyDecContextObject *self) int n, mem; #ifdef NDEBUG - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); assert(PyDecContext_Check(state, self)); #endif ctx = CTX(self); @@ -1451,7 +1485,7 @@ ieee_context(PyObject *dummy UNUSED, PyObject *v) goto error; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(v)); context = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (context == NULL) { return NULL; @@ -1474,7 +1508,7 @@ context_copy(PyObject *self, PyObject *args UNUSED) { PyObject *copy; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); copy = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (copy == NULL) { return NULL; @@ -1546,7 +1580,7 @@ static PyGetSetDef context_getsets [] = #define CONTEXT_CHECK_VA(state, obj) \ if (obj == Py_None) { \ - CURRENT_CONTEXT(obj); \ + CURRENT_CONTEXT(state, obj); \ } \ else if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ @@ -1694,9 +1728,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) } #else static PyObject * -init_current_context(void) +init_current_context(decimal_state *state) { - decimal_state *state = GLOBAL_STATE(); PyObject *tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; @@ -1714,10 +1747,9 @@ init_current_context(void) } static inline PyObject * -current_context(void) +current_context(decimal_state *state) { PyObject *tl_context; - decimal_state *state = GLOBAL_STATE(); if (PyContextVar_Get(state->current_context_var, NULL, &tl_context) < 0) { return NULL; } @@ -1726,12 +1758,12 @@ current_context(void) return tl_context; } - return init_current_context(); + return init_current_context(state); } /* ctxobj := borrowed reference to the current context */ -#define CURRENT_CONTEXT(ctxobj) \ - ctxobj = current_context(); \ +#define CURRENT_CONTEXT(state, ctxobj) \ + ctxobj = current_context(state); \ if (ctxobj == NULL) { \ return NULL; \ } \ @@ -1741,14 +1773,15 @@ current_context(void) static PyObject * PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED) { - return current_context(); + decimal_state *state = get_module_state(self); + return current_context(state); } /* Set the thread local context to a new context, decrement old reference */ static PyObject * PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state(self); CONTEXT_CHECK(state, v); /* If the new context is one of the templates, make a copy. @@ -1781,7 +1814,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) * owns one reference to the global (outer) context and one * to the local (inner) context. */ static PyObject * -ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) +ctxmanager_new(PyObject *m UNUSED, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "ctx", "prec", "rounding", @@ -1802,12 +1835,12 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) PyObject *flags = Py_None; PyObject *traps = Py_None; - CURRENT_CONTEXT(global); + decimal_state *state = get_module_state(m); + CURRENT_CONTEXT(state, global); if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, &local, &prec, &rounding, &Emin, &Emax, &capitals, &clamp, &flags, &traps)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); if (local == Py_None) { local = global; } @@ -1878,7 +1911,7 @@ ctxmanager_set_local(PyDecContextManagerObject *self, PyObject *args UNUSED) { PyObject *ret; - ret = PyDec_SetCurrentContext(NULL, self->local); + ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->local); if (ret == NULL) { return NULL; } @@ -1893,7 +1926,7 @@ ctxmanager_restore_global(PyDecContextManagerObject *self, { PyObject *ret; - ret = PyDec_SetCurrentContext(NULL, self->global); + ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->global); if (ret == NULL) { return NULL; } @@ -1935,7 +1968,7 @@ PyDecType_New(PyTypeObject *type) { PyDecObject *dec; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(type); if (type == state->PyDec_Type) { dec = PyObject_GC_New(PyDecObject, state->PyDec_Type); } @@ -2336,7 +2369,7 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, mpd_t *d1, *d2; uint32_t status = 0; mpd_context_t maxctx; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(type); #ifdef NDEBUG assert(PyType_IsSubtype(type, state->PyDec_Type)); @@ -2475,7 +2508,7 @@ PyDecType_FromDecimalExact(PyTypeObject *type, PyObject *v, PyObject *context) PyObject *dec; uint32_t status = 0; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(type); if (type == state->PyDec_Type && PyDec_CheckExact(state, v)) { return Py_NewRef(v); } @@ -2750,8 +2783,8 @@ dec_from_float(PyObject *type, PyObject *pyfloat) PyObject *context; PyObject *result; - decimal_state *state = GLOBAL_STATE(); - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def((PyObject *)type); + CURRENT_CONTEXT(state, context); result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); if (type != (PyObject *)state->PyDec_Type && result != NULL) { Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); @@ -2764,7 +2797,7 @@ dec_from_float(PyObject *type, PyObject *pyfloat) static PyObject * ctx_from_float(PyObject *context, PyObject *v) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); return PyDec_FromFloat(state, v, context); } @@ -2775,7 +2808,7 @@ dec_apply(PyObject *v, PyObject *context) PyObject *result; uint32_t status = 0; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); result = dec_alloc(state); if (result == NULL) { return NULL; @@ -2802,7 +2835,7 @@ dec_apply(PyObject *v, PyObject *context) static PyObject * PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(type); if (v == NULL) { return PyDecType_FromSsizeExact(type, 0, context); } @@ -2837,7 +2870,7 @@ PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) static PyObject * PyDec_FromObject(PyObject *v, PyObject *context) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); if (v == NULL) { return PyDec_FromSsize(state, 0, context); } @@ -2893,7 +2926,7 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds) &v, &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(type); CONTEXT_CHECK_VA(state, context); return PyDecType_FromObjectExact(type, v, context); @@ -2924,7 +2957,7 @@ ctx_create_decimal(PyObject *context, PyObject *args) Py_LOCAL_INLINE(int) convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); if (PyDec_Check(state, v)) { *conv = Py_NewRef(v); return 1; @@ -3027,7 +3060,7 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) if (tmp == NULL) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); denom = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); if (denom == NULL) { @@ -3082,7 +3115,7 @@ numerator_as_decimal(PyObject *r, PyObject *context) return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); num = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); return num; @@ -3101,7 +3134,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, *vcmp = v; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); if (PyDec_Check(state, w)) { *wcmp = Py_NewRef(w); } @@ -3199,7 +3232,8 @@ dec_str(PyObject *dec) mpd_ssize_t size; char *cp; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); size = mpd_to_sci_size(&cp, MPD(dec), CtxCaps(context)); if (size < 0) { PyErr_NoMemory(); @@ -3217,8 +3251,8 @@ dec_repr(PyObject *dec) { PyObject *res, *context; char *cp; - - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); cp = mpd_to_sci(MPD(dec), CtxCaps(context)); if (cp == NULL) { PyErr_NoMemory(); @@ -3379,7 +3413,8 @@ dec_format(PyObject *dec, PyObject *args) mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt}; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) { return NULL; } @@ -3660,9 +3695,9 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) return NULL; } - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); - decimal_state *state = GLOBAL_STATE(); tmp = dec_alloc(state); if (tmp == NULL) { return NULL; @@ -3749,12 +3784,12 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { - int round = getround(rounding); + int round = getround(state, rounding); if (round < 0) { return NULL; } @@ -3791,12 +3826,12 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { - int round = getround(rounding); + int round = getround(state, rounding); if (round < 0) { return NULL; } @@ -3859,8 +3894,8 @@ PyDec_Round(PyObject *dec, PyObject *args) uint32_t status = 0; PyObject *context; - - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); if (!PyArg_ParseTuple(args, "|O", &x)) { return NULL; } @@ -3880,7 +3915,6 @@ PyDec_Round(PyObject *dec, PyObject *args) if (y == -1 && PyErr_Occurred()) { return NULL; } - decimal_state *state = GLOBAL_STATE(); result = dec_alloc(state); if (result == NULL) { return NULL; @@ -3982,7 +4016,7 @@ PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) } } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); @@ -4009,8 +4043,8 @@ nm_##MPDFUNC(PyObject *self) \ PyObject *context; \ uint32_t status = 0; \ \ - decimal_state *state = GLOBAL_STATE(); \ - CURRENT_CONTEXT(context); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + CURRENT_CONTEXT(state, context); \ if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ @@ -4034,10 +4068,10 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ PyObject *context; \ uint32_t status = 0; \ \ - CURRENT_CONTEXT(context) ; \ + decimal_state *state = find_state_left_or_right(self, other); \ + CURRENT_CONTEXT(state, context) ; \ CONVERT_BINOP(&a, &b, self, other, context); \ \ - decimal_state *state = GLOBAL_STATE(); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -4075,7 +4109,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ \ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ @@ -4095,7 +4129,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ \ if ((result = dec_alloc(state)) == NULL) { \ @@ -4127,7 +4161,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ @@ -4165,7 +4199,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ @@ -4198,7 +4232,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &third, &context)) { \ return NULL; \ } \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ @@ -4241,8 +4275,8 @@ static PyObject * nm_dec_as_long(PyObject *dec) { PyObject *context; - - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); return dec_as_long(dec, context, MPD_ROUND_DOWN); } @@ -4261,10 +4295,10 @@ nm_mpd_qdivmod(PyObject *v, PyObject *w) uint32_t status = 0; PyObject *ret; - CURRENT_CONTEXT(context); + decimal_state *state = find_state_left_or_right(v, w); + CURRENT_CONTEXT(state, context); CONVERT_BINOP(&a, &b, v, w, context); - decimal_state *state = GLOBAL_STATE(); q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); @@ -4302,7 +4336,8 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) PyObject *context; uint32_t status = 0; - CURRENT_CONTEXT(context); + decimal_state *state = find_state_left_or_right(base, exp); + CURRENT_CONTEXT(state, context); CONVERT_BINOP(&a, &b, base, exp, context); if (mod != Py_None) { @@ -4313,7 +4348,6 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) } } - decimal_state *state = GLOBAL_STATE(); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -4411,11 +4445,11 @@ dec_conjugate(PyObject *self, PyObject *dummy UNUSED) } static PyObject * -dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) +dec_mpd_radix(PyObject *self, PyObject *dummy UNUSED) { PyObject *result; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); result = dec_alloc(state); if (result == NULL) { return NULL; @@ -4431,7 +4465,7 @@ dec_mpd_qcopy_abs(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4452,7 +4486,7 @@ dec_mpd_qcopy_negate(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4482,7 +4516,7 @@ dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); cp = mpd_class(MPD(self), CTX(context)); @@ -4502,7 +4536,7 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); @@ -4535,7 +4569,7 @@ dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); @@ -4570,7 +4604,7 @@ dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); @@ -4605,12 +4639,12 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) &w, &rounding, &context)) { return NULL; } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(v)); CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { - int round = getround(rounding); + int round = getround(state, rounding); if (round < 0) { return NULL; } @@ -4649,13 +4683,13 @@ dec_richcompare(PyObject *v, PyObject *w, int op) uint32_t status = 0; int a_issnan, b_issnan; int r; + decimal_state *state = find_state_left_or_right(v, w); #ifdef NDEBUG - decimal_state *state = GLOBAL_STATE(); assert(PyDec_Check(state, v)); #endif - CURRENT_CONTEXT(context); + CURRENT_CONTEXT(state, context); CONVERT_BINOP_CMP(&a, &b, v, w, op, context); a_issnan = mpd_issnan(MPD(a)); @@ -4706,7 +4740,8 @@ dec_ceil(PyObject *self, PyObject *dummy UNUSED) { PyObject *context; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_CEILING); } @@ -4744,7 +4779,8 @@ dec_floor(PyObject *self, PyObject *dummy UNUSED) { PyObject *context; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_FLOOR); } @@ -4908,7 +4944,8 @@ dec_trunc(PyObject *self, PyObject *dummy UNUSED) { PyObject *context; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_DOWN); } @@ -4924,7 +4961,7 @@ dec_imag(PyObject *self UNUSED, void *closure UNUSED) { PyObject *result; - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); result = dec_alloc(state); if (result == NULL) { return NULL; @@ -5122,7 +5159,7 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ uint32_t status = 0; \ \ CONVERT_OP_RAISE(&a, v, context); \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ return NULL; \ @@ -5153,7 +5190,7 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -5188,7 +5225,7 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -5217,7 +5254,7 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ - decimal_state *state = GLOBAL_STATE(); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -5283,7 +5320,7 @@ ctx_mpd_qdivmod(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); @@ -5338,7 +5375,7 @@ ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) } } - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -5390,7 +5427,7 @@ DecCtx_BoolFunc_NO_CTX(mpd_iszero) static PyObject * ctx_iscanonical(PyObject *context UNUSED, PyObject *v) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); @@ -5416,7 +5453,7 @@ PyDecContext_Apply(PyObject *context, PyObject *v) static PyObject * ctx_canonical(PyObject *context UNUSED, PyObject *v) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); @@ -5433,7 +5470,7 @@ ctx_mpd_qcopy_abs(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -5466,7 +5503,7 @@ ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -5563,7 +5600,7 @@ ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); @@ -5848,9 +5885,15 @@ _decimal_exec(PyObject *m) mpd_reallocfunc = PyMem_Realloc; mpd_callocfunc = mpd_callocfunc_em; mpd_free = PyMem_Free; - mpd_setminalloc(_Py_DEC_MINALLOC); - decimal_state *state = GLOBAL_STATE(); + static int minalloc_is_set = 0; + if (minalloc_is_set == 0) { + // FIXME: mpd_setminalloc may be used only once at program start. + mpd_setminalloc(_Py_DEC_MINALLOC); + minalloc_is_set = 1; + } + + decimal_state *state = get_module_state(m); /* Init external C-API functions */ state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -6064,10 +6107,10 @@ _decimal_exec(PyObject *m) Py_CLEAR(obj); /* GCOV_NOT_REACHED */ Py_CLEAR(numbers); /* GCOV_NOT_REACHED */ Py_CLEAR(Number); /* GCOV_NOT_REACHED */ - Py_CLEAR(state->Rational); /* GCOV_NOT_REACHED */ Py_CLEAR(collections); /* GCOV_NOT_REACHED */ Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->Rational); /* GCOV_NOT_REACHED */ Py_CLEAR(state->SignalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ @@ -6086,7 +6129,7 @@ _decimal_exec(PyObject *m) static int decimal_traverse(PyObject *module, visitproc visit, void *arg) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state(module); Py_VISIT(state->PyDecContextManager_Type); Py_VISIT(state->PyDecContext_Type); Py_VISIT(state->PyDecSignalDictMixin_Type); @@ -6105,22 +6148,15 @@ decimal_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->default_context_template); Py_VISIT(state->basic_context_template); Py_VISIT(state->extended_context_template); - Py_VISIT(state->round_map); Py_VISIT(state->Rational); Py_VISIT(state->SignalTuple); - - Py_VISIT(state->_py_long_multiply); - Py_VISIT(state->_py_long_floor_divide); - Py_VISIT(state->_py_long_power); - Py_VISIT(state->_py_float_abs); - Py_VISIT(state->_py_long_bit_length); - Py_VISIT(state->_py_float_as_integer_ratio); + return 0; } static int decimal_clear(PyObject *module) { - decimal_state *state = GLOBAL_STATE(); + decimal_state *state = get_module_state(module); Py_CLEAR(state->PyDecContextManager_Type); Py_CLEAR(state->PyDecContext_Type); Py_CLEAR(state->PyDecSignalDictMixin_Type); @@ -6139,22 +6175,15 @@ decimal_clear(PyObject *module) Py_CLEAR(state->default_context_template); Py_CLEAR(state->basic_context_template); Py_CLEAR(state->extended_context_template); - Py_CLEAR(state->round_map); Py_CLEAR(state->Rational); Py_CLEAR(state->SignalTuple); - - Py_CLEAR(state->_py_long_multiply); - Py_CLEAR(state->_py_long_floor_divide); - Py_CLEAR(state->_py_long_power); - Py_CLEAR(state->_py_float_abs); - Py_CLEAR(state->_py_long_bit_length); - Py_CLEAR(state->_py_float_as_integer_ratio); + return 0; } static void decimal_free(void *module) { - (void)module_clear((PyObject *)module); + (void)decimal_clear((PyObject *)module); } static struct PyModuleDef_Slot _decimal_slots[] = { @@ -6169,7 +6198,6 @@ static struct PyModuleDef _decimal_module = { .m_size = sizeof(decimal_state), .m_methods = _decimal_methods, .m_slots = _decimal_slots, - .m_traverse = decimal_traverse, .m_clear = decimal_clear, .m_free = decimal_free, From be7fa2aebb827da9664cf31ebe1100f01b9df5e8 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Sat, 8 Apr 2023 23:56:50 +0800 Subject: [PATCH 22/27] Add `signal_map` to state to fix error in `decimal.Context`. --- Modules/_decimal/_decimal.c | 160 ++++++++++++++++++++---------------- 1 file changed, 91 insertions(+), 69 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 9e7c2d245405ba..9811b7a9f57f20 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -44,6 +44,15 @@ #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) #endif +#define SIGNAL_MAP_LEN 9 + +typedef struct { + const char *name; /* condition or signal name */ + const char *fqname; /* fully qualified name */ + uint32_t flag; /* libmpdec flag */ + PyObject *ex; /* corresponding exception */ +} DecCondMap; + typedef struct { PyTypeObject *PyDecContextManager_Type; PyTypeObject *PyDecContext_Type; @@ -79,6 +88,8 @@ typedef struct { PyObject *SignalTuple; + DecCondMap signal_map[SIGNAL_MAP_LEN + 1]; + /* External C-API functions */ binaryfunc _py_long_multiply; binaryfunc _py_long_floor_divide; @@ -215,30 +226,29 @@ incr_false(void) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) #define DEC_ERRORS (DEC_INVALID_SIGNALS|DEC_ERR_OCCURRED) -typedef struct { - const char *name; /* condition or signal name */ - const char *fqname; /* fully qualified name */ - uint32_t flag; /* libmpdec flag */ - PyObject *ex; /* corresponding exception */ -} DecCondMap; - /* Exceptions that correspond to IEEE signals */ #define SUBNORMAL 5 #define INEXACT 6 #define ROUNDED 7 -#define SIGNAL_MAP_LEN 9 -static DecCondMap signal_map[] = { - {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, - {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, - {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, - {"Overflow", "decimal.Overflow", MPD_Overflow, NULL}, - {"Underflow", "decimal.Underflow", MPD_Underflow, NULL}, - {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL}, - {"Inexact", "decimal.Inexact", MPD_Inexact, NULL}, - {"Rounded", "decimal.Rounded", MPD_Rounded, NULL}, - {"Clamped", "decimal.Clamped", MPD_Clamped, NULL}, - {NULL} -}; + +static inline void +signal_map_init(decimal_state *state) +{ + static DecCondMap signal_map[] = { + {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, + {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, + {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, + {"Overflow", "decimal.Overflow", MPD_Overflow, NULL}, + {"Underflow", "decimal.Underflow", MPD_Underflow, NULL}, + {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL}, + {"Inexact", "decimal.Inexact", MPD_Inexact, NULL}, + {"Rounded", "decimal.Rounded", MPD_Rounded, NULL}, + {"Clamped", "decimal.Clamped", MPD_Clamped, NULL}, + {NULL} + }; + + memcpy(state->signal_map, signal_map, sizeof(signal_map)); +} /* Exceptions that inherit from InvalidOperation */ static DecCondMap cond_map[] = { @@ -343,11 +353,11 @@ dec_traphandler(mpd_context_t *ctx UNUSED) /* GCOV_NOT_REACHED */ } static PyObject * -flags_as_exception(uint32_t flags) +flags_as_exception(decimal_state *state, uint32_t flags) { DecCondMap *cm; - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (flags&cm->flag) { return cm->ex; } @@ -357,11 +367,11 @@ flags_as_exception(uint32_t flags) } Py_LOCAL_INLINE(uint32_t) -exception_as_flag(PyObject *ex) +exception_as_flag(decimal_state *state, PyObject *ex) { DecCondMap *cm; - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (cm->ex == ex) { return cm->flag; } @@ -372,7 +382,7 @@ exception_as_flag(PyObject *ex) } static PyObject * -flags_as_list(uint32_t flags) +flags_as_list(decimal_state *state, uint32_t flags) { PyObject *list; DecCondMap *cm; @@ -389,7 +399,7 @@ flags_as_list(uint32_t flags) } } } - for (cm = signal_map+1; cm->name != NULL; cm++) { + for (cm = state->signal_map+1; cm->name != NULL; cm++) { if (flags&cm->flag) { if (PyList_Append(list, cm->ex) < 0) { goto error; @@ -405,7 +415,7 @@ flags_as_list(uint32_t flags) } static PyObject * -signals_as_list(uint32_t flags) +signals_as_list(decimal_state *state, uint32_t flags) { PyObject *list; DecCondMap *cm; @@ -415,7 +425,7 @@ signals_as_list(uint32_t flags) return NULL; } - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (flags&cm->flag) { if (PyList_Append(list, cm->ex) < 0) { Py_DECREF(list); @@ -428,7 +438,7 @@ signals_as_list(uint32_t flags) } static uint32_t -list_as_flags(PyObject *list) +list_as_flags(decimal_state *state, PyObject *list) { PyObject *item; uint32_t flags, x; @@ -440,7 +450,7 @@ list_as_flags(PyObject *list) flags = 0; for (j = 0; j < n; j++) { item = PyList_GetItem(list, j); - x = exception_as_flag(item); + x = exception_as_flag(state, item); if (x & DEC_ERRORS) { return x; } @@ -451,7 +461,7 @@ list_as_flags(PyObject *list) } static PyObject * -flags_as_dict(uint32_t flags) +flags_as_dict(decimal_state *state, uint32_t flags) { DecCondMap *cm; PyObject *dict; @@ -461,7 +471,7 @@ flags_as_dict(uint32_t flags) return NULL; } - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { PyObject *b = flags&cm->flag ? Py_True : Py_False; if (PyDict_SetItem(dict, cm->ex, b) < 0) { Py_DECREF(dict); @@ -473,7 +483,7 @@ flags_as_dict(uint32_t flags) } static uint32_t -dict_as_flags(PyObject *val) +dict_as_flags(decimal_state *state, PyObject *val) { PyObject *b; DecCondMap *cm; @@ -492,14 +502,12 @@ dict_as_flags(PyObject *val) return DEC_INVALID_SIGNALS; } - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { b = PyDict_GetItemWithError(val, cm->ex); if (b == NULL) { if (PyErr_Occurred()) { return DEC_ERR_OCCURRED; } - // FIXME: Raise error while running test_decimal.py - // Seems to be caused by static signal_map PyErr_SetString(PyExc_KeyError, "invalid signal dict"); return DEC_INVALID_SIGNALS; @@ -540,6 +548,7 @@ static int dec_addstatus(PyObject *context, uint32_t status) { mpd_context_t *ctx = CTX(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); ctx->status |= status; if (status & (ctx->traps|MPD_Malloc_error)) { @@ -550,11 +559,11 @@ dec_addstatus(PyObject *context, uint32_t status) return 1; } - ex = flags_as_exception(ctx->traps&status); + ex = flags_as_exception(state, ctx->traps&status); if (ex == NULL) { return 1; /* GCOV_NOT_REACHED */ } - siglist = flags_as_list(ctx->traps&status); + siglist = flags_as_list(state, ctx->traps&status); if (siglist == NULL) { return 1; } @@ -621,8 +630,9 @@ static PyObject * signaldict_getitem(PyObject *self, PyObject *key) { uint32_t flag; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); - flag = exception_as_flag(key); + flag = exception_as_flag(state, key); if (flag & DEC_ERRORS) { return NULL; } @@ -636,11 +646,12 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) uint32_t flag; int x; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if (value == NULL) { return value_error_int("signal keys cannot be deleted"); } - flag = exception_as_flag(key); + flag = exception_as_flag(state, key); if (flag & DEC_ERRORS) { return -1; } @@ -683,10 +694,10 @@ signaldict_repr(PyObject *self) const char *n[SIGNAL_MAP_LEN]; /* name */ const char *b[SIGNAL_MAP_LEN]; /* bool */ int i; - + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); assert(SIGNAL_MAP_LEN == 9); - for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + for (cm=state->signal_map, i=0; cm->name != NULL; cm++, i++) { n[i] = cm->fqname; b[i] = SdFlags(self)&cm->flag ? "True" : "False"; } @@ -712,7 +723,7 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False; } else if (PyDict_Check(w)) { - uint32_t flags = dict_as_flags(w); + uint32_t flags = dict_as_flags(state, w); if (flags & DEC_ERRORS) { if (flags & DEC_INVALID_SIGNALS) { /* non-comparable: Py_NotImplemented */ @@ -734,7 +745,8 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) static PyObject * signaldict_copy(PyObject *self, PyObject *args UNUSED) { - return flags_as_dict(SdFlags(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + return flags_as_dict(state, SdFlags(self)); } @@ -1020,8 +1032,8 @@ context_settraps_list(PyObject *self, PyObject *value) { mpd_context_t *ctx; uint32_t flags; - - flags = list_as_flags(value); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + flags = list_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1045,7 +1057,7 @@ context_settraps_dict(PyObject *self, PyObject *value) flags = SdFlags(value); } else { - flags = dict_as_flags(value); + flags = dict_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1085,8 +1097,9 @@ context_setstatus_list(PyObject *self, PyObject *value) { mpd_context_t *ctx; uint32_t flags; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); - flags = list_as_flags(value); + flags = list_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1110,7 +1123,7 @@ context_setstatus_dict(PyObject *self, PyObject *value) flags = SdFlags(value); } else { - flags = dict_as_flags(value); + flags = dict_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1528,14 +1541,15 @@ context_reduce(PyObject *self, PyObject *args UNUSED) PyObject *traps; PyObject *ret; mpd_context_t *ctx; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); ctx = CTX(self); - flags = signals_as_list(ctx->status); + flags = signals_as_list(state, ctx->status); if (flags == NULL) { return NULL; } - traps = signals_as_list(ctx->traps); + traps = signals_as_list(state, ctx->traps); if (traps == NULL) { Py_DECREF(flags); return NULL; @@ -4109,7 +4123,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ \ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ @@ -4129,7 +4143,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ \ if ((result = dec_alloc(state)) == NULL) { \ @@ -4161,7 +4176,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ @@ -4199,7 +4215,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ @@ -4232,7 +4249,7 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &third, &context)) { \ return NULL; \ } \ - decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ @@ -5159,7 +5176,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ uint32_t status = 0; \ \ CONVERT_OP_RAISE(&a, v, context); \ - decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ return NULL; \ @@ -5190,7 +5208,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -5225,7 +5244,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -5254,7 +5274,7 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ - decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ @@ -5894,6 +5914,7 @@ _decimal_exec(PyObject *m) } decimal_state *state = get_module_state(m); + signal_map_init(state); /* Init external C-API functions */ state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -5979,10 +6000,11 @@ _decimal_exec(PyObject *m) ASSIGN_PTR(state->SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); /* Add exceptions that correspond to IEEE signals */ + signal_map_init(state); for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) { PyObject *base; - cm = signal_map + i; + cm = state->signal_map + i; switch (cm->flag) { case MPD_Float_operation: @@ -5992,13 +6014,13 @@ _decimal_exec(PyObject *m) base = PyTuple_Pack(2, state->DecimalException, PyExc_ZeroDivisionError); break; case MPD_Overflow: - base = PyTuple_Pack(2, signal_map[INEXACT].ex, - signal_map[ROUNDED].ex); + base = PyTuple_Pack(2, state->signal_map[INEXACT].ex, + state->signal_map[ROUNDED].ex); break; case MPD_Underflow: - base = PyTuple_Pack(3, signal_map[INEXACT].ex, - signal_map[ROUNDED].ex, - signal_map[SUBNORMAL].ex); + base = PyTuple_Pack(3, state->signal_map[INEXACT].ex, + state->signal_map[ROUNDED].ex, + state->signal_map[SUBNORMAL].ex); break; default: base = PyTuple_Pack(1, state->DecimalException); @@ -6024,16 +6046,16 @@ _decimal_exec(PyObject *m) * several conditions, including InvalidOperation! Naming the * signal IEEEInvalidOperation would prevent the confusion. */ - cond_map[0].ex = signal_map[0].ex; + cond_map[0].ex = state->signal_map[0].ex; /* Add remaining exceptions, inherit from InvalidOperation */ for (cm = cond_map+1; cm->name != NULL; cm++) { PyObject *base; if (cm->flag == MPD_Division_undefined) { - base = PyTuple_Pack(2, signal_map[0].ex, PyExc_ZeroDivisionError); + base = PyTuple_Pack(2, state->signal_map[0].ex, PyExc_ZeroDivisionError); } else { - base = PyTuple_Pack(1, signal_map[0].ex); + base = PyTuple_Pack(1, state->signal_map[0].ex); } if (base == NULL) { goto error; /* GCOV_NOT_REACHED */ From b130f56bd978f1a4e8845a6705deb9fdbddb1b72 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Tue, 11 Apr 2023 15:18:55 +0800 Subject: [PATCH 23/27] solve warnings and remove redundant code --- Modules/_decimal/_decimal.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 9811b7a9f57f20..0dfce4ead54783 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -107,14 +107,6 @@ get_module_state(PyObject *mod) return state; } -static inline decimal_state * -get_module_state_by_cls(PyTypeObject *cls) -{ - decimal_state *state = (decimal_state *)PyType_GetModuleState(cls); - assert(state != NULL); - return state; -} - static struct PyModuleDef _decimal_module; static inline decimal_state * @@ -2797,7 +2789,7 @@ dec_from_float(PyObject *type, PyObject *pyfloat) PyObject *context; PyObject *result; - decimal_state *state = get_module_state_by_def((PyObject *)type); + decimal_state *state = get_module_state_by_def((PyTypeObject *)type); CURRENT_CONTEXT(state, context); result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); if (type != (PyObject *)state->PyDec_Type && result != NULL) { @@ -5914,7 +5906,6 @@ _decimal_exec(PyObject *m) } decimal_state *state = get_module_state(m); - signal_map_init(state); /* Init external C-API functions */ state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -6132,18 +6123,6 @@ _decimal_exec(PyObject *m) Py_CLEAR(collections); /* GCOV_NOT_REACHED */ Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ - Py_CLEAR(state->Rational); /* GCOV_NOT_REACHED */ - Py_CLEAR(state->SignalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ -#ifndef WITH_DECIMAL_CONTEXTVAR - Py_CLEAR(state->tls_context_key); /* GCOV_NOT_REACHED */ -#else - Py_CLEAR(state->current_context_var); /* GCOV_NOT_REACHED */ -#endif - Py_CLEAR(state->basic_context_template); /* GCOV_NOT_REACHED */ - Py_CLEAR(state->extended_context_template); /* GCOV_NOT_REACHED */ - Py_CLEAR(m); /* GCOV_NOT_REACHED */ return -1; /* GCOV_NOT_REACHED */ } From a81da377c43d8a868f0de5cf8407403b01d71f6b Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Thu, 20 Apr 2023 15:35:06 +0800 Subject: [PATCH 24/27] remove NDEBUG and static-local variables --- Modules/_decimal/_decimal.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index a5b72dd222d7f1..68a564a3fcc570 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -227,7 +227,7 @@ incr_false(void) static inline void signal_map_init(decimal_state *state) { - static DecCondMap signal_map[] = { + const DecCondMap signal_map[] = { {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, @@ -1422,10 +1422,8 @@ context_repr(PyDecContextObject *self) char traps[MPD_MAX_SIGNAL_LIST]; int n, mem; -#ifdef NDEBUG decimal_state *state = get_module_state_by_def(Py_TYPE(self)); assert(PyDecContext_Check(state, self)); -#endif ctx = CTX(self); mem = MPD_MAX_SIGNAL_LIST; @@ -2368,9 +2366,7 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, mpd_context_t maxctx; decimal_state *state = get_module_state_by_def(type); -#ifdef NDEBUG assert(PyType_IsSubtype(type, state->PyDec_Type)); -#endif if (PyLong_Check(v)) { return PyDecType_FromLongExact(type, v, context); @@ -4667,9 +4663,7 @@ dec_richcompare(PyObject *v, PyObject *w, int op) int r; decimal_state *state = find_state_left_or_right(v, w); -#ifdef NDEBUG assert(PyDec_Check(state, v)); -#endif CURRENT_CONTEXT(state, context); CONVERT_BINOP_CMP(&a, &b, v, w, op, context); @@ -5870,13 +5864,7 @@ _decimal_exec(PyObject *m) mpd_reallocfunc = PyMem_Realloc; mpd_callocfunc = mpd_callocfunc_em; mpd_free = PyMem_Free; - - static int minalloc_is_set = 0; - if (minalloc_is_set == 0) { - // FIXME: mpd_setminalloc may be used only once at program start. - mpd_setminalloc(_Py_DEC_MINALLOC); - minalloc_is_set = 1; - } + mpd_setminalloc(_Py_DEC_MINALLOC); decimal_state *state = get_module_state(m); From 6638ca7ab2d90ff7d71192bcc68c1ad98ce2af80 Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Fri, 21 Apr 2023 14:47:10 +0800 Subject: [PATCH 25/27] Add a NEWS entry. --- .../2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst new file mode 100644 index 00000000000000..6eed964bd3c92c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst @@ -0,0 +1,2 @@ +Adapt :mod:`decimal` to :pep:`687`. Patch by Erlend Aasland and Charlie +Zhao. From 68473a0356366a4c5811508bf5192f63e510a7ad Mon Sep 17 00:00:00 2001 From: CharlieZhao Date: Thu, 25 May 2023 10:52:10 +0800 Subject: [PATCH 26/27] Add Py_MOD_PER_INTERPRETER_GIL_SUPPORTED --- Modules/_decimal/_decimal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 68a564a3fcc570..fdfaa37264956f 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6150,6 +6150,7 @@ decimal_free(void *module) static struct PyModuleDef_Slot _decimal_slots[] = { {Py_mod_exec, _decimal_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL}, }; From 58f0049dee98eb53f8217163f298534bf7145ab3 Mon Sep 17 00:00:00 2001 From: Charlie Zhao Date: Sun, 28 May 2023 22:31:34 +0800 Subject: [PATCH 27/27] Update Modules/_decimal/_decimal.c Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> --- Modules/_decimal/_decimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index fdfaa37264956f..069b6d34336865 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -227,7 +227,7 @@ incr_false(void) static inline void signal_map_init(decimal_state *state) { - const DecCondMap signal_map[] = { + static const DecCondMap signal_map[] = { {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL},