From 00c0ef028c74c6ea6c3e97c1b730ca780f35d7ba Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 15:52:38 +0100 Subject: [PATCH 01/30] Consistency: use explicit initialiser for m_base --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index eda8c5610ba659..f846e1b11367e5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6864,7 +6864,7 @@ _datetime_exec(PyObject *module) } static struct PyModuleDef datetimemodule = { - PyModuleDef_HEAD_INIT, + .m_base = PyModuleDef_HEAD_INIT, .m_name = "_datetime", .m_doc = "Fast implementation of the datetime type.", .m_size = -1, From d1bbebb039a3ab93e172293e8e40aef91247b4dc Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 15:57:15 +0100 Subject: [PATCH 02/30] Add module state stub; establish global state on stack --- Modules/_datetimemodule.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index f846e1b11367e5..5dffbe6274a0a8 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -40,6 +40,13 @@ #define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType) +typedef struct { +} datetime_state; + +static datetime_state global_state; + +#define GLOBAL_STATE() (&global_state) + /*[clinic input] module datetime class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" From efeea77e8d1e1458976c403f88256132ca96c65e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 16:03:13 +0100 Subject: [PATCH 03/30] Put conversion factors in state struct --- Modules/_datetimemodule.c | 70 +++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 7 --- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 5dffbe6274a0a8..9013be164b2b6d 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -41,6 +41,14 @@ #define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType) typedef struct { + /* Conversion factors. */ + PyObject *us_per_ms; // 1000 + PyObject *us_per_second; // 1000000 + PyObject *us_per_minute; // 1e6 * 60 as Python int + PyObject *us_per_hour; // 1e6 * 3600 as Python int + PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int + PyObject *us_per_week; // 1e6*3600*24*7 as Python int + PyObject *seconds_per_day; // 3600*24 as Python int } datetime_state; static datetime_state global_state; @@ -1814,19 +1822,6 @@ cmperror(PyObject *a, PyObject *b) return NULL; } -/* --------------------------------------------------------------------------- - * Cached Python objects; these are set by the module init function. - */ - -/* Conversion factors. */ -static PyObject *us_per_ms = NULL; /* 1000 */ -static PyObject *us_per_second = NULL; /* 1000000 */ -static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */ -static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python int */ -static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python int */ -static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python int */ -static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */ - /* --------------------------------------------------------------------------- * Class implementations. */ @@ -1852,7 +1847,8 @@ delta_to_microseconds(PyDateTime_Delta *self) x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) goto Done; - x2 = PyNumber_Multiply(x1, seconds_per_day); /* days in seconds */ + datetime_state *st = GLOBAL_STATE(); + x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */ if (x2 == NULL) goto Done; Py_SETREF(x1, NULL); @@ -1869,7 +1865,7 @@ delta_to_microseconds(PyDateTime_Delta *self) /* x1 = */ x2 = NULL; /* x3 has days+seconds in seconds */ - x1 = PyNumber_Multiply(x3, us_per_second); /* us */ + x1 = PyNumber_Multiply(x3, st->us_per_second); /* us */ if (x1 == NULL) goto Done; Py_SETREF(x3, NULL); @@ -1924,7 +1920,8 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) PyObject *num = NULL; PyObject *result = NULL; - tuple = checked_divmod(pyus, us_per_second); + datetime_state *st = GLOBAL_STATE(); + tuple = checked_divmod(pyus, st->us_per_second); if (tuple == NULL) { goto Done; } @@ -1942,7 +1939,7 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) num = Py_NewRef(PyTuple_GET_ITEM(tuple, 0)); /* leftover seconds */ Py_DECREF(tuple); - tuple = checked_divmod(num, seconds_per_day); + tuple = checked_divmod(num, st->seconds_per_day); if (tuple == NULL) goto Done; Py_DECREF(num); @@ -2542,28 +2539,29 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us); CLEANUP; } + datetime_state *st = GLOBAL_STATE(); if (ms) { - y = accum("milliseconds", x, ms, us_per_ms, &leftover_us); + y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us); CLEANUP; } if (second) { - y = accum("seconds", x, second, us_per_second, &leftover_us); + y = accum("seconds", x, second, st->us_per_second, &leftover_us); CLEANUP; } if (minute) { - y = accum("minutes", x, minute, us_per_minute, &leftover_us); + y = accum("minutes", x, minute, st->us_per_minute, &leftover_us); CLEANUP; } if (hour) { - y = accum("hours", x, hour, us_per_hour, &leftover_us); + y = accum("hours", x, hour, st->us_per_hour, &leftover_us); CLEANUP; } if (day) { - y = accum("days", x, day, us_per_day, &leftover_us); + y = accum("days", x, day, st->us_per_day, &leftover_us); CLEANUP; } if (week) { - y = accum("weeks", x, week, us_per_week, &leftover_us); + y = accum("weeks", x, week, st->us_per_week, &leftover_us); CLEANUP; } if (leftover_us) { @@ -2718,7 +2716,8 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) if (total_microseconds == NULL) return NULL; - total_seconds = PyNumber_TrueDivide(total_microseconds, us_per_second); + datetime_state *st = GLOBAL_STATE(); + total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second); Py_DECREF(total_microseconds); return total_seconds; @@ -6849,22 +6848,25 @@ _datetime_exec(PyObject *module) static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y"); assert(DI100Y == days_before_year(100+1)); - us_per_ms = PyLong_FromLong(1000); - us_per_second = PyLong_FromLong(1000000); - us_per_minute = PyLong_FromLong(60000000); - seconds_per_day = PyLong_FromLong(24 * 3600); - if (us_per_ms == NULL || us_per_second == NULL || - us_per_minute == NULL || seconds_per_day == NULL) { + datetime_state *st = GLOBAL_STATE(); + st->us_per_ms = PyLong_FromLong(1000); + st->us_per_second = PyLong_FromLong(1000000); + st->us_per_minute = PyLong_FromLong(60000000); + st->seconds_per_day = PyLong_FromLong(24 * 3600); + if (st->us_per_ms == NULL || st->us_per_second == NULL || + st->us_per_minute == NULL || st->seconds_per_day == NULL) { return -1; } /* The rest are too big for 32-bit ints, but even * us_per_week fits in 40 bits, so doubles should be exact. */ - us_per_hour = PyLong_FromDouble(3600000000.0); - us_per_day = PyLong_FromDouble(86400000000.0); - us_per_week = PyLong_FromDouble(604800000000.0); - if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) { + st->us_per_hour = PyLong_FromDouble(3600000000.0); + st->us_per_day = PyLong_FromDouble(86400000000.0); + st->us_per_week = PyLong_FromDouble(604800000000.0); + if (st->us_per_hour == NULL || st->us_per_day == NULL || + st->us_per_week == NULL) + { return -1; } return 0; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 2e28c50c6ff69a..b4e015193ce755 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -443,13 +443,6 @@ Modules/_cursesmodule.c - ModDict - Modules/_datetimemodule.c datetime_strptime module - Modules/_datetimemodule.c - PyDateTime_TimeZone_UTC - Modules/_datetimemodule.c - PyDateTime_Epoch - -Modules/_datetimemodule.c - us_per_ms - -Modules/_datetimemodule.c - us_per_second - -Modules/_datetimemodule.c - us_per_minute - -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 - From ef4a4c2f82725ffc08fd3af14123937574cc9b37 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 17:00:07 +0100 Subject: [PATCH 04/30] Move PyDateTime_TimeZone_UTC to state --- Modules/_datetimemodule.c | 35 ++++++++++++--------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 9013be164b2b6d..f11bb9a5849db7 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -49,6 +49,9 @@ typedef struct { PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int PyObject *us_per_week; // 1e6*3600*24*7 as Python int PyObject *seconds_per_day; // 3600*24 as Python int + + /* The interned UTC timezone instance */ + PyObject *PyDateTime_TimeZone_UTC; } datetime_state; static datetime_state global_state; @@ -1154,8 +1157,6 @@ typedef struct PyObject *name; } PyDateTime_TimeZone; -/* The interned UTC timezone instance */ -static PyObject *PyDateTime_TimeZone_UTC; /* The interned Epoch datetime instance */ static PyObject *PyDateTime_Epoch; @@ -1192,7 +1193,8 @@ new_timezone(PyObject *offset, PyObject *name) assert(name == NULL || PyUnicode_Check(name)); if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { - return Py_NewRef(PyDateTime_TimeZone_UTC); + datetime_state *st = GLOBAL_STATE(); + return Py_NewRef(st->PyDateTime_TimeZone_UTC); } if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0 && @@ -1405,7 +1407,8 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) if (rv == 1) { // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { - return Py_NewRef(PyDateTime_TimeZone_UTC); + datetime_state *st = GLOBAL_STATE(); + return Py_NewRef(st->PyDateTime_TimeZone_UTC); } PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1); @@ -3950,7 +3953,8 @@ timezone_repr(PyDateTime_TimeZone *self) to use Py_TYPE(self)->tp_name here. */ const char *type_name = Py_TYPE(self)->tp_name; - if (((PyObject *)self) == PyDateTime_TimeZone_UTC) + datetime_state *st = GLOBAL_STATE(); + if (((PyObject *)self) == st->PyDateTime_TimeZone_UTC) return PyUnicode_FromFormat("%s.utc", type_name); if (self->name == NULL) @@ -3971,7 +3975,8 @@ timezone_str(PyDateTime_TimeZone *self) if (self->name != NULL) { return Py_NewRef(self->name); } - if ((PyObject *)self == PyDateTime_TimeZone_UTC || + datetime_state *st = GLOBAL_STATE(); + if ((PyObject *)self == st->PyDateTime_TimeZone_UTC || (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && GET_TD_MICROSECONDS(self->offset) == 0)) @@ -6229,6 +6234,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) if (result == NULL) return NULL; + datetime_state *st = GLOBAL_STATE(); /* Make sure result is aware and UTC. */ if (!HASTZINFO(result)) { temp = (PyObject *)result; @@ -6240,7 +6246,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) DATE_GET_MINUTE(result), DATE_GET_SECOND(result), DATE_GET_MICROSECOND(result), - PyDateTime_TimeZone_UTC, + st->PyDateTime_TimeZone_UTC, DATE_GET_FOLD(result), Py_TYPE(result)); Py_DECREF(temp); @@ -6249,7 +6255,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } else { /* Result is already aware - just replace tzinfo. */ - Py_SETREF(result->tzinfo, Py_NewRef(PyDateTime_TimeZone_UTC)); + Py_SETREF(result->tzinfo, Py_NewRef(st->PyDateTime_TimeZone_UTC)); } /* Attach new tzinfo and let fromutc() do the rest. */ @@ -6675,8 +6681,9 @@ get_datetime_capi(void) capi->Time_FromTimeAndFold = new_time_ex2; // Make sure this function is called after PyDateTime_TimeZone_UTC has // been initialized. - assert(PyDateTime_TimeZone_UTC != NULL); - capi->TimeZone_UTC = PyDateTime_TimeZone_UTC; // borrowed ref + datetime_state *st = GLOBAL_STATE(); + assert(st->PyDateTime_TimeZone_UTC != NULL); + capi->TimeZone_UTC = st->PyDateTime_TimeZone_UTC; // borrowed ref return capi; } @@ -6773,7 +6780,8 @@ _datetime_exec(PyObject *module) return -1; } - PyDateTime_TimeZone_UTC = x; + datetime_state *st = GLOBAL_STATE(); + st->PyDateTime_TimeZone_UTC = x; /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of @@ -6798,7 +6806,7 @@ _datetime_exec(PyObject *module) /* Epoch */ PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, - PyDateTime_TimeZone_UTC, 0); + st->PyDateTime_TimeZone_UTC, 0); if (PyDateTime_Epoch == NULL) { return -1; } @@ -6826,7 +6834,7 @@ _datetime_exec(PyObject *module) return -1; } - if (PyModule_AddObjectRef(module, "UTC", PyDateTime_TimeZone_UTC) < 0) { + if (PyModule_AddObjectRef(module, "UTC", st->PyDateTime_TimeZone_UTC) < 0) { return -1; } @@ -6848,7 +6856,6 @@ _datetime_exec(PyObject *module) static_assert(DI100Y == 25 * DI4Y - 1, "DI100Y"); assert(DI100Y == days_before_year(100+1)); - datetime_state *st = GLOBAL_STATE(); st->us_per_ms = PyLong_FromLong(1000); st->us_per_second = PyLong_FromLong(1000000); st->us_per_minute = PyLong_FromLong(60000000); diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index b4e015193ce755..b70749128fe406 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -441,7 +441,6 @@ Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - Modules/_datetimemodule.c datetime_strptime module - -Modules/_datetimemodule.c - PyDateTime_TimeZone_UTC - Modules/_datetimemodule.c - PyDateTime_Epoch - Modules/_decimal/_decimal.c - basic_context_template - Modules/_decimal/_decimal.c - current_context_var - From 9e3f693cc6c48733526d0bf99c599016074366aa Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 20:51:17 +0100 Subject: [PATCH 05/30] Move PyDateTime_Epoch to state struct --- Modules/_datetimemodule.c | 16 +++++++++------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index f11bb9a5849db7..de286d2b807917 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -52,6 +52,9 @@ typedef struct { /* The interned UTC timezone instance */ PyObject *PyDateTime_TimeZone_UTC; + + /* The interned Epoch datetime instance */ + PyObject *PyDateTime_Epoch; } datetime_state; static datetime_state global_state; @@ -1157,9 +1160,6 @@ typedef struct PyObject *name; } PyDateTime_TimeZone; -/* The interned Epoch datetime instance */ -static PyObject *PyDateTime_Epoch; - /* Create new timezone instance checking offset range. This function does not check the name argument. Caller must assure that offset is a timedelta instance and name is either NULL @@ -6136,7 +6136,8 @@ local_timezone(PyDateTime_DateTime *utc_time) PyObject *one_second; PyObject *seconds; - delta = datetime_subtract((PyObject *)utc_time, PyDateTime_Epoch); + datetime_state *st = GLOBAL_STATE(); + delta = datetime_subtract((PyObject *)utc_time, st->PyDateTime_Epoch); if (delta == NULL) return NULL; one_second = new_delta(0, 1, 0, 0); @@ -6359,8 +6360,9 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { + datetime_state *st = GLOBAL_STATE(); PyObject *delta; - delta = datetime_subtract((PyObject *)self, PyDateTime_Epoch); + delta = datetime_subtract((PyObject *)self, st->PyDateTime_Epoch); if (delta == NULL) return NULL; result = delta_total_seconds(delta, NULL); @@ -6805,9 +6807,9 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "max", x); /* Epoch */ - PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, + st->PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, st->PyDateTime_TimeZone_UTC, 0); - if (PyDateTime_Epoch == NULL) { + if (st->PyDateTime_Epoch == NULL) { return -1; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index b70749128fe406..dd4d79294a8e97 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -441,7 +441,6 @@ Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - Modules/_datetimemodule.c datetime_strptime module - -Modules/_datetimemodule.c - PyDateTime_Epoch - Modules/_decimal/_decimal.c - basic_context_template - Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - default_context_template - From 5bd60b2c47ca654eed5de4ebe5fe2621d530de3b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 20:52:25 +0100 Subject: [PATCH 06/30] Remove datetime_strptime globals entry --- 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 dd4d79294a8e97..5a92651f97323e 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -440,7 +440,6 @@ Modules/_ctypes/_ctypes.c CreateSwappedType suffix - Modules/_ctypes/_ctypes.c - _unpickle - Modules/_ctypes/_ctypes.c PyCArrayType_from_ctype cache - Modules/_cursesmodule.c - ModDict - -Modules/_datetimemodule.c datetime_strptime module - Modules/_decimal/_decimal.c - basic_context_template - Modules/_decimal/_decimal.c - current_context_var - Modules/_decimal/_decimal.c - default_context_template - From b5c051b41784eca27dff46b34183d3993cad8215 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 15 Feb 2023 21:10:32 +0100 Subject: [PATCH 07/30] Add heap type machinery --- Modules/_datetimemodule.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index de286d2b807917..139932abb35836 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -69,7 +69,9 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=81bec0fa19837f63]*/ +#define clinic_state() (GLOBAL_STATE()) #include "clinic/_datetimemodule.c.h" +#undef clinic_state /* We require that C int be at least 32 bits, and use int virtually * everywhere. In just a few cases we use a temp long, where a Python @@ -6699,6 +6701,18 @@ datetime_destructor(PyObject *op) static int _datetime_exec(PyObject *module) { +#define ADD_TYPE(mod, var, spec, base) \ + do { \ + var = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, \ + (PyObject *)base); \ + if (var == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(mod, var) < 0) { \ + return -1; \ + } \ + } while (0) + // `&...` is not a constant expression according to a strict reading // of C standards. Fill tp_base at run-time rather than statically. // See https://bugs.python.org/issue40777 @@ -6725,6 +6739,8 @@ _datetime_exec(PyObject *module) return -1; } +#undef ADD_TYPE + #define DATETIME_ADD_MACRO(dict, c, value_expr) \ do { \ PyObject *value = (value_expr); \ From 0b2393428d26c3de9d700e2a8e88789ae7620733 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 21:08:15 +0100 Subject: [PATCH 08/30] PyDateTime_DateTimeType --- Modules/_datetimemodule.c | 250 ++++++++++++-------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 147 insertions(+), 104 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 139932abb35836..82fe0bf533ffe6 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -26,8 +26,7 @@ #define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType) #define PyDate_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateType) -#define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType) -#define PyDateTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateTimeType) +#define PyDateTime_Check(st, op) PyObject_TypeCheck(op, st->PyDateTime_DateTimeType) #define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) #define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType) @@ -55,6 +54,9 @@ typedef struct { /* The interned Epoch datetime instance */ PyObject *PyDateTime_Epoch; + + /* Types */ + PyTypeObject *PyDateTime_DateTimeType; } datetime_state; static datetime_state global_state; @@ -63,11 +65,11 @@ static datetime_state global_state; /*[clinic input] module datetime -class datetime.datetime "PyDateTime_DateTime *" "&PyDateTime_DateTimeType" +class datetime.datetime "PyDateTime_DateTime *" "clinic_state()->PyDateTime_DateTimeType" class datetime.date "PyDateTime_Date *" "&PyDateTime_DateType" class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCalendarDateType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=81bec0fa19837f63]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=36a187caa1dda205]*/ #define clinic_state() (GLOBAL_STATE()) #include "clinic/_datetimemodule.c.h" @@ -154,7 +156,6 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa /* Forward declarations. */ static PyTypeObject PyDateTime_DateType; -static PyTypeObject PyDateTime_DateTimeType; static PyTypeObject PyDateTime_DeltaType; static PyTypeObject PyDateTime_IsoCalendarDateType; static PyTypeObject PyDateTime_TimeType; @@ -984,12 +985,13 @@ new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *); static PyObject * new_date_subclass_ex(int year, int month, int day, PyObject *cls) { + datetime_state *st = GLOBAL_STATE(); PyObject *result; // We have "fast path" constructors for two subclasses: date and datetime if ((PyTypeObject *)cls == &PyDateTime_DateType) { result = new_date_ex(year, month, day, (PyTypeObject *)cls); } - else if ((PyTypeObject *)cls == &PyDateTime_DateTimeType) { + else if ((PyTypeObject *)cls == st->PyDateTime_DateTimeType) { result = new_datetime_ex(year, month, day, 0, 0, 0, 0, Py_None, (PyTypeObject *)cls); } @@ -1042,18 +1044,19 @@ new_datetime_ex(int year, int month, int day, int hour, int minute, tzinfo, 0, type); } -#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo, fold) \ +#define new_datetime(st, y, m, d, hh, mm, ss, us, tzinfo, fold) \ new_datetime_ex2(y, m, d, hh, mm, ss, us, tzinfo, fold, \ - &PyDateTime_DateTimeType) + st->PyDateTime_DateTimeType) static PyObject * new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute, int second, int usecond, PyObject *tzinfo, int fold, PyObject *cls) { PyObject* dt; - if ((PyTypeObject*)cls == &PyDateTime_DateTimeType) { + datetime_state *st = GLOBAL_STATE(); + if ((PyTypeObject*)cls == st->PyDateTime_DateTimeType) { // Use the fast path constructor - dt = new_datetime(year, month, day, hour, minute, second, usecond, + dt = new_datetime(st, year, month, day, hour, minute, second, usecond, tzinfo, fold); } else { // Subclass @@ -1240,7 +1243,8 @@ get_tzinfo_member(PyObject *self) { PyObject *tzinfo = NULL; - if (PyDateTime_Check(self) && HASTZINFO(self)) + datetime_state *st = GLOBAL_STATE(); + if (PyDateTime_Check(st, self) && HASTZINFO(self)) tzinfo = ((PyDateTime_DateTime *)self)->tzinfo; else if (PyTime_Check(self) && HASTZINFO(self)) tzinfo = ((PyDateTime_Time *)self)->tzinfo; @@ -1577,10 +1581,11 @@ make_Zreplacement(PyObject *object, PyObject *tzinfoarg) static PyObject * make_freplacement(PyObject *object) { + datetime_state *st = GLOBAL_STATE(); char freplacement[64]; if (PyTime_Check(object)) sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object)); - else if (PyDateTime_Check(object)) + else if (PyDateTime_Check(st, object)) sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object)); else sprintf(freplacement, "%06d", 0); @@ -3159,7 +3164,8 @@ add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) static PyObject * date_add(PyObject *left, PyObject *right) { - if (PyDateTime_Check(left) || PyDateTime_Check(right)) + datetime_state *st = GLOBAL_STATE(); + if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; if (PyDate_Check(left)) { @@ -3186,7 +3192,8 @@ date_add(PyObject *left, PyObject *right) static PyObject * date_subtract(PyObject *left, PyObject *right) { - if (PyDateTime_Check(left) || PyDateTime_Check(right)) + datetime_state *st = GLOBAL_STATE(); + if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; if (PyDate_Check(left)) { @@ -3728,7 +3735,8 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) PyObject *off = NULL, *dst = NULL; PyDateTime_Delta *delta = NULL; - if (!PyDateTime_Check(dt)) { + datetime_state *st = GLOBAL_STATE(); + if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); return NULL; @@ -3941,7 +3949,8 @@ timezone_hash(PyDateTime_TimeZone *self) static int _timezone_check_argument(PyObject *dt, const char *meth) { - if (dt == Py_None || PyDateTime_Check(dt)) + datetime_state *st = GLOBAL_STATE(); + if (dt == Py_None || PyDateTime_Check(st, dt)) return 0; PyErr_Format(PyExc_TypeError, "%s(dt) argument must be a datetime instance" " or None, not %.200s", meth, Py_TYPE(dt)->tp_name); @@ -4042,7 +4051,8 @@ timezone_dst(PyObject *self, PyObject *dt) static PyObject * timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) { - if (!PyDateTime_Check(dt)) { + datetime_state *st = GLOBAL_STATE(); + if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); return NULL; @@ -5508,14 +5518,29 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) /* * Destructor. */ +static int +datetime_traverse(PyDateTime_DateTime *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->tzinfo); + return 0; +} + +static int +datetime_clear(PyDateTime_DateTime *self) +{ + Py_CLEAR(self->tzinfo); + return 0; +} static void datetime_dealloc(PyDateTime_DateTime *self) { - if (HASTZINFO(self)) { - Py_XDECREF(self->tzinfo); - } - Py_TYPE(self)->tp_free((PyObject *)self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)datetime_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } /* @@ -5576,7 +5601,8 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, static PyObject * datetime_add(PyObject *left, PyObject *right) { - if (PyDateTime_Check(left)) { + datetime_state *st = GLOBAL_STATE(); + if (PyDateTime_Check(st, left)) { /* datetime + ??? */ if (PyDelta_Check(right)) /* datetime + delta */ @@ -5598,10 +5624,10 @@ static PyObject * datetime_subtract(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - - if (PyDateTime_Check(left)) { + datetime_state *st = GLOBAL_STATE(); + if (PyDateTime_Check(st, left)) { /* datetime - ??? */ - if (PyDateTime_Check(right)) { + if (PyDateTime_Check(st, right)) { /* datetime - datetime */ PyObject *offset1, *offset2, *offdiff = NULL; int delta_d, delta_s, delta_us; @@ -5880,8 +5906,8 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) PyObject *result = NULL; PyObject *offset1, *offset2; int diff; - - if (! PyDateTime_Check(other)) { + datetime_state *st = GLOBAL_STATE(); + if (! PyDateTime_Check(st, other)) { if (PyDate_Check(other)) { /* Prevent invocation of date_richcompare. We want to return NotImplemented here to give the other object @@ -6089,7 +6115,9 @@ local_timezone_from_timestamp(time_t timestamp) char buf[100]; strftime(buf, sizeof(buf), "%Z", &local_time_tm); zone = buf; - local_time = new_datetime(local_time_tm.tm_year + 1900, + datetime_state *state = GLOBAL_STATE(); + local_time = new_datetime(state, + local_time_tm.tm_year + 1900, local_time_tm.tm_mon + 1, local_time_tm.tm_mday, local_time_tm.tm_hour, @@ -6100,7 +6128,8 @@ local_timezone_from_timestamp(time_t timestamp) } if (_PyTime_gmtime(timestamp, &utc_time_tm) != 0) return NULL; - utc_time = new_datetime(utc_time_tm.tm_year + 1900, + utc_time = new_datetime(state, + utc_time_tm.tm_year + 1900, utc_time_tm.tm_mon + 1, utc_time_tm.tm_mday, utc_time_tm.tm_hour, @@ -6594,60 +6623,34 @@ PyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzi The year, month and day arguments are required. tzinfo may be None, or an\n\ instance of a tzinfo subclass. The remaining arguments may be ints.\n"); -static PyNumberMethods datetime_as_number = { - datetime_add, /* nb_add */ - datetime_subtract, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - 0, /* nb_bool */ +static PyType_Slot datetime_slots[] = { + {Py_tp_dealloc, datetime_dealloc}, + {Py_tp_traverse, datetime_traverse}, + {Py_tp_clear, datetime_clear}, + {Py_tp_repr, datetime_repr}, + {Py_tp_hash, datetime_hash}, + {Py_tp_str, datetime_str}, + {Py_tp_doc, (void *)datetime_doc}, + {Py_tp_richcompare, datetime_richcompare}, + {Py_tp_methods, datetime_methods}, + {Py_tp_getset, datetime_getset}, + {Py_tp_alloc, datetime_alloc}, + {Py_tp_new, datetime_new}, + + // Number protocol + {Py_nb_add, datetime_add}, + {Py_nb_subtract, datetime_subtract}, + {0, NULL}, }; -static PyTypeObject PyDateTime_DateTimeType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.datetime", /* tp_name */ - sizeof(PyDateTime_DateTime), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)datetime_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)datetime_repr, /* tp_repr */ - &datetime_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)datetime_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)datetime_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - datetime_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - datetime_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - datetime_methods, /* tp_methods */ - 0, /* tp_members */ - datetime_getset, /* tp_getset */ - 0, /* tp_base; filled in - PyInit__datetime */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - datetime_alloc, /* tp_alloc */ - datetime_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec datetime_spec = { + .name = "datetime.datetime", /* tp_name */ + .basicsize = sizeof(PyDateTime_DateTime), /* tp_basicsize */ + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = datetime_slots, }; /* --------------------------------------------------------------------------- @@ -6662,7 +6665,7 @@ static PyMethodDef module_methods[] = { * Clients get at C API via PyDateTime_IMPORT, defined in datetime.h. */ static inline PyDateTime_CAPI * -get_datetime_capi(void) +get_datetime_capi(datetime_state *st) { PyDateTime_CAPI *capi = PyMem_Malloc(sizeof(PyDateTime_CAPI)); if (capi == NULL) { @@ -6670,7 +6673,7 @@ get_datetime_capi(void) return NULL; } capi->DateType = &PyDateTime_DateType; - capi->DateTimeType = &PyDateTime_DateTimeType; + capi->DateTimeType = st->PyDateTime_DateTimeType; capi->TimeType = &PyDateTime_TimeType; capi->DeltaType = &PyDateTime_DeltaType; capi->TZInfoType = &PyDateTime_TZInfoType; @@ -6685,7 +6688,6 @@ get_datetime_capi(void) capi->Time_FromTimeAndFold = new_time_ex2; // Make sure this function is called after PyDateTime_TimeZone_UTC has // been initialized. - datetime_state *st = GLOBAL_STATE(); assert(st->PyDateTime_TimeZone_UTC != NULL); capi->TimeZone_UTC = st->PyDateTime_TimeZone_UTC; // borrowed ref return capi; @@ -6701,6 +6703,8 @@ datetime_destructor(PyObject *op) static int _datetime_exec(PyObject *module) { + datetime_state *st = GLOBAL_STATE(); + #define ADD_TYPE(mod, var, spec, base) \ do { \ var = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, \ @@ -6718,11 +6722,9 @@ _datetime_exec(PyObject *module) // See https://bugs.python.org/issue40777 PyDateTime_IsoCalendarDateType.tp_base = &PyTuple_Type; PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType; - PyDateTime_DateTimeType.tp_base = &PyDateTime_DateType; PyTypeObject *types[] = { &PyDateTime_DateType, - &PyDateTime_DateTimeType, &PyDateTime_TimeType, &PyDateTime_DeltaType, &PyDateTime_TZInfoType, @@ -6739,6 +6741,9 @@ _datetime_exec(PyObject *module) return -1; } + ADD_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, + &PyDateTime_DateType); + #undef ADD_TYPE #define DATETIME_ADD_MACRO(dict, c, value_expr) \ @@ -6774,10 +6779,10 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); /* datetime values */ - d = PyDateTime_DateTimeType.tp_dict; + d = st->PyDateTime_DateTimeType->tp_dict; DATETIME_ADD_MACRO(d, "min", - new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None, 0)); - DATETIME_ADD_MACRO(d, "max", new_datetime(MAXYEAR, 12, 31, 23, 59, 59, + new_datetime(st, 1, 1, 1, 0, 0, 0, 0, Py_None, 0)); + DATETIME_ADD_MACRO(d, "max", new_datetime(st, MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None, 0)); DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); @@ -6798,7 +6803,6 @@ _datetime_exec(PyObject *module) return -1; } - datetime_state *st = GLOBAL_STATE(); st->PyDateTime_TimeZone_UTC = x; /* bpo-37642: These attributes are rounded to the nearest minute for backwards @@ -6823,7 +6827,7 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "max", x); /* Epoch */ - st->PyDateTime_Epoch = new_datetime(1970, 1, 1, 0, 0, 0, 0, + st->PyDateTime_Epoch = new_datetime(st, 1970, 1, 1, 0, 0, 0, 0, st->PyDateTime_TimeZone_UTC, 0); if (st->PyDateTime_Epoch == NULL) { return -1; @@ -6837,7 +6841,7 @@ _datetime_exec(PyObject *module) return -1; } - PyDateTime_CAPI *capi = get_datetime_capi(); + PyDateTime_CAPI *capi = get_datetime_capi(st); if (capi == NULL) { return -1; } @@ -6897,27 +6901,67 @@ _datetime_exec(PyObject *module) return 0; } +static int +module_traverse(PyObject *module, visitproc visit, void *arg) +{ + datetime_state *state = GLOBAL_STATE(); + Py_VISIT(state->us_per_ms); + Py_VISIT(state->us_per_second); + Py_VISIT(state->us_per_minute); + Py_VISIT(state->us_per_hour); + Py_VISIT(state->us_per_day); + Py_VISIT(state->us_per_week); + Py_VISIT(state->seconds_per_day); + Py_VISIT(state->PyDateTime_TimeZone_UTC); + Py_VISIT(state->PyDateTime_Epoch); + Py_VISIT(state->PyDateTime_DateTimeType); + return 0; +} + +static int +module_clear(PyObject *module) +{ + datetime_state *state = GLOBAL_STATE(); + Py_CLEAR(state->us_per_ms); + Py_CLEAR(state->us_per_second); + Py_CLEAR(state->us_per_minute); + Py_CLEAR(state->us_per_hour); + Py_CLEAR(state->us_per_day); + Py_CLEAR(state->us_per_week); + Py_CLEAR(state->seconds_per_day); + Py_CLEAR(state->PyDateTime_TimeZone_UTC); + Py_CLEAR(state->PyDateTime_Epoch); + Py_CLEAR(state->PyDateTime_DateTimeType); + return 0; +} + +static void +module_free(void *module) +{ + (void)module_clear((PyObject *)module); +} + +static struct PyModuleDef_Slot module_slots[] = { + {Py_mod_exec, _datetime_exec}, + {0, NULL}, +}; + static struct PyModuleDef datetimemodule = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "_datetime", .m_doc = "Fast implementation of the datetime type.", - .m_size = -1, + .m_size = sizeof(datetime_state), .m_methods = module_methods, + .m_slots = module_slots, + .m_traverse = module_traverse, + .m_clear = module_clear, + .m_free = module_free, }; PyMODINIT_FUNC PyInit__datetime(void) { - PyObject *mod = PyModule_Create(&datetimemodule); - if (mod == NULL) - return NULL; - - if (_datetime_exec(mod) < 0) { - Py_DECREF(mod); - return NULL; - } - - return mod; + return PyModuleDef_Init(&datetimemodule); } /* --------------------------------------------------------------------------- diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 5a92651f97323e..b3bb82d2c180b5 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -379,7 +379,6 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -Modules/_datetimemodule.c - PyDateTime_DateTimeType - Modules/_datetimemodule.c - PyDateTime_DateType - Modules/_datetimemodule.c - PyDateTime_DeltaType - Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - From 9184c37e9b5bf63f4e61e04671d3c8e19bfd067b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 22:15:22 +0100 Subject: [PATCH 09/30] PyDateTime_DateType --- Modules/_datetimemodule.c | 137 +++++++++----------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 64 insertions(+), 74 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 82fe0bf533ffe6..c65a6f7b762967 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -23,10 +23,8 @@ # include /* struct timeval */ #endif -#define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType) -#define PyDate_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DateType) - -#define PyDateTime_Check(st, op) PyObject_TypeCheck(op, st->PyDateTime_DateTimeType) +#define PyDate_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateType) +#define PyDateTime_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateTimeType) #define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) #define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType) @@ -57,6 +55,7 @@ typedef struct { /* Types */ PyTypeObject *PyDateTime_DateTimeType; + PyTypeObject *PyDateTime_DateType; } datetime_state; static datetime_state global_state; @@ -66,7 +65,7 @@ static datetime_state global_state; /*[clinic input] module datetime class datetime.datetime "PyDateTime_DateTime *" "clinic_state()->PyDateTime_DateTimeType" -class datetime.date "PyDateTime_Date *" "&PyDateTime_DateType" +class datetime.date "PyDateTime_Date *" "clinic_state()->PyDateTime_DateType" class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCalendarDateType" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=36a187caa1dda205]*/ @@ -155,7 +154,6 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) /* Forward declarations. */ -static PyTypeObject PyDateTime_DateType; static PyTypeObject PyDateTime_DeltaType; static PyTypeObject PyDateTime_IsoCalendarDateType; static PyTypeObject PyDateTime_TimeType; @@ -974,8 +972,8 @@ new_date_ex(int year, int month, int day, PyTypeObject *type) return (PyObject *)self; } -#define new_date(year, month, day) \ - new_date_ex(year, month, day, &PyDateTime_DateType) +#define new_date(st, year, month, day) \ + new_date_ex(year, month, day, st->PyDateTime_DateType) // Forward declaration static PyObject * @@ -988,7 +986,7 @@ new_date_subclass_ex(int year, int month, int day, PyObject *cls) datetime_state *st = GLOBAL_STATE(); PyObject *result; // We have "fast path" constructors for two subclasses: date and datetime - if ((PyTypeObject *)cls == &PyDateTime_DateType) { + if ((PyTypeObject *)cls == st->PyDateTime_DateType) { result = new_date_ex(year, month, day, (PyTypeObject *)cls); } else if ((PyTypeObject *)cls == st->PyDateTime_DateTimeType) { @@ -3168,7 +3166,7 @@ date_add(PyObject *left, PyObject *right) if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - if (PyDate_Check(left)) { + if (PyDate_Check(st, left)) { /* date + ??? */ if (PyDelta_Check(right)) /* date + delta */ @@ -3196,8 +3194,8 @@ date_subtract(PyObject *left, PyObject *right) if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - if (PyDate_Check(left)) { - if (PyDate_Check(right)) { + if (PyDate_Check(st, left)) { + if (PyDate_Check(st, right)) { /* date - date */ int left_ord = ymd_to_ord(GET_YEAR(left), GET_MONTH(left), @@ -3459,7 +3457,8 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) static PyObject * date_richcompare(PyObject *self, PyObject *other, int op) { - if (PyDate_Check(other)) { + datetime_state *st = GLOBAL_STATE(); + if (PyDate_Check(st, other)) { int diff = memcmp(((PyDateTime_Date *)self)->data, ((PyDateTime_Date *)other)->data, _PyDateTime_DATE_DATASIZE); @@ -3551,6 +3550,22 @@ date_reduce(PyDateTime_Date *self, PyObject *arg) return Py_BuildValue("(ON)", Py_TYPE(self), date_getstate(self)); } +static int +date_traverse(PyDateTime_Date *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +date_dealloc(PyDateTime_Date *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + static PyMethodDef date_methods[] = { /* Class methods: */ @@ -3620,59 +3635,32 @@ static PyMethodDef date_methods[] = { static const char date_doc[] = PyDoc_STR("date(year, month, day) --> date object"); -static PyNumberMethods date_as_number = { - date_add, /* nb_add */ - date_subtract, /* nb_subtract */ - 0, /* nb_multiply */ - 0, /* nb_remainder */ - 0, /* nb_divmod */ - 0, /* nb_power */ - 0, /* nb_negative */ - 0, /* nb_positive */ - 0, /* nb_absolute */ - 0, /* nb_bool */ +static PyType_Slot date_slots[] = { + {Py_tp_repr, date_repr}, + {Py_tp_hash, date_hash}, + {Py_tp_str, date_str}, + {Py_tp_doc, (void *)date_doc}, + {Py_tp_richcompare, date_richcompare}, + {Py_tp_methods, date_methods}, + {Py_tp_getset, date_getset}, + {Py_tp_new, date_new}, + {Py_tp_traverse, date_traverse}, + {Py_tp_dealloc, date_dealloc}, + + // Number protocol + {Py_nb_add, date_add}, + {Py_nb_subtract, date_subtract}, + {0, NULL}, }; -static PyTypeObject PyDateTime_DateType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.date", /* tp_name */ - sizeof(PyDateTime_Date), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)date_repr, /* tp_repr */ - &date_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)date_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)date_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - date_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - date_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - date_methods, /* tp_methods */ - 0, /* tp_members */ - date_getset, /* 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 */ - date_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec date_spec = { + .name = "datetime.date", /* tp_name */ + .basicsize = sizeof(PyDateTime_Date), /* tp_basicsize */ + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = date_slots, }; /* @@ -5241,8 +5229,9 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) PyObject *tzinfo = NULL; PyObject *result = NULL; + datetime_state *st = GLOBAL_STATE(); if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords, - &PyDateTime_DateType, &date, + st->PyDateTime_DateType, &date, &PyDateTime_TimeType, &time, &tzinfo)) { if (tzinfo == NULL) { if (HASTZINFO(time)) @@ -5908,7 +5897,7 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) int diff; datetime_state *st = GLOBAL_STATE(); if (! PyDateTime_Check(st, other)) { - if (PyDate_Check(other)) { + if (PyDate_Check(st, other)) { /* Prevent invocation of date_richcompare. We want to return NotImplemented here to give the other object a chance. But since DateTime is a subclass of @@ -6419,7 +6408,9 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - return new_date(GET_YEAR(self), + datetime_state *state = GLOBAL_STATE(); + return new_date(state, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); } @@ -6672,7 +6663,7 @@ get_datetime_capi(datetime_state *st) PyErr_NoMemory(); return NULL; } - capi->DateType = &PyDateTime_DateType; + capi->DateType = st->PyDateTime_DateType; capi->DateTimeType = st->PyDateTime_DateTimeType; capi->TimeType = &PyDateTime_TimeType; capi->DeltaType = &PyDateTime_DeltaType; @@ -6724,7 +6715,6 @@ _datetime_exec(PyObject *module) PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType; PyTypeObject *types[] = { - &PyDateTime_DateType, &PyDateTime_TimeType, &PyDateTime_DeltaType, &PyDateTime_TZInfoType, @@ -6741,8 +6731,9 @@ _datetime_exec(PyObject *module) return -1; } + ADD_TYPE(module, st->PyDateTime_DateType, &date_spec, NULL); ADD_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, - &PyDateTime_DateType); + st->PyDateTime_DateType); #undef ADD_TYPE @@ -6767,9 +6758,9 @@ _datetime_exec(PyObject *module) new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0)); /* date values */ - d = PyDateTime_DateType.tp_dict; - DATETIME_ADD_MACRO(d, "min", new_date(1, 1, 1)); - DATETIME_ADD_MACRO(d, "max", new_date(MAXYEAR, 12, 31)); + d = st->PyDateTime_DateType->tp_dict; + DATETIME_ADD_MACRO(d, "min", new_date(st, 1, 1, 1)); + DATETIME_ADD_MACRO(d, "max", new_date(st, MAXYEAR, 12, 31)); DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0)); /* time values */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index b3bb82d2c180b5..7c10f93149af97 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -379,7 +379,6 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -Modules/_datetimemodule.c - PyDateTime_DateType - Modules/_datetimemodule.c - PyDateTime_DeltaType - Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - From d89001323d395a713147a72857e0f11fbf390d38 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 22:33:51 +0100 Subject: [PATCH 10/30] PyDateTime_DeltaType --- Modules/_datetimemodule.c | 290 ++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 146 insertions(+), 145 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c65a6f7b762967..c8cf0666cf46ba 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -29,8 +29,7 @@ #define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) #define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType) -#define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType) -#define PyDelta_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_DeltaType) +#define PyDelta_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DeltaType) #define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType) #define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TZInfoType) @@ -56,6 +55,7 @@ typedef struct { /* Types */ PyTypeObject *PyDateTime_DateTimeType; PyTypeObject *PyDateTime_DateType; + PyTypeObject *PyDateTime_DeltaType; } datetime_state; static datetime_state global_state; @@ -154,7 +154,6 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) /* Forward declarations. */ -static PyTypeObject PyDateTime_DeltaType; static PyTypeObject PyDateTime_IsoCalendarDateType; static PyTypeObject PyDateTime_TimeType; static PyTypeObject PyDateTime_TZInfoType; @@ -1152,8 +1151,8 @@ new_delta_ex(int days, int seconds, int microseconds, int normalize, return (PyObject *) self; } -#define new_delta(d, s, us, normalize) \ - new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType) +#define new_delta(st, d, s, us, normalize) \ + new_delta_ex(d, s, us, normalize, st->PyDateTime_DeltaType) typedef struct @@ -1172,9 +1171,9 @@ create_timezone(PyObject *offset, PyObject *name) { PyDateTime_TimeZone *self; PyTypeObject *type = &PyDateTime_TimeZoneType; - + datetime_state *st = GLOBAL_STATE(); assert(offset != NULL); - assert(PyDelta_Check(offset)); + assert(PyDelta_Check(st, offset)); assert(name == NULL || PyUnicode_Check(name)); self = (PyDateTime_TimeZone *)(type->tp_alloc(type, 0)); @@ -1191,8 +1190,9 @@ static int delta_bool(PyDateTime_Delta *self); static PyObject * new_timezone(PyObject *offset, PyObject *name) { + datetime_state *st = GLOBAL_STATE(); assert(offset != NULL); - assert(PyDelta_Check(offset)); + assert(PyDelta_Check(st, offset)); assert(name == NULL || PyUnicode_Check(name)); if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { @@ -1271,7 +1271,8 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) offset = PyObject_CallMethod(tzinfo, name, "O", tzinfoarg); if (offset == Py_None || offset == NULL) return offset; - if (PyDelta_Check(offset)) { + datetime_state *st = GLOBAL_STATE(); + if (PyDelta_Check(st, offset)) { if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0 && GET_TD_MICROSECONDS(offset) < 1) || @@ -1409,13 +1410,14 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) { PyObject *tzinfo; if (rv == 1) { + datetime_state *st = GLOBAL_STATE(); + // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { - datetime_state *st = GLOBAL_STATE(); return Py_NewRef(st->PyDateTime_TimeZone_UTC); } - PyObject *delta = new_delta(0, tzoffset, tz_useconds, 1); + PyObject *delta = new_delta(st, 0, tzoffset, tz_useconds, 1); if (delta == NULL) { return NULL; } @@ -1918,7 +1920,8 @@ checked_divmod(PyObject *a, PyObject *b) /* Convert a number of us (as a Python int) to a timedelta. */ static PyObject * -microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) +microseconds_to_delta_ex(datetime_state *st, PyObject *pyus, + PyTypeObject *type) { int us; int s; @@ -1928,7 +1931,6 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) PyObject *num = NULL; PyObject *result = NULL; - datetime_state *st = GLOBAL_STATE(); tuple = checked_divmod(pyus, st->us_per_second); if (tuple == NULL) { goto Done; @@ -1980,8 +1982,8 @@ microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) goto Done; } -#define microseconds_to_delta(pymicros) \ - microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType) +#define microseconds_to_delta(st, pymicros) \ + microseconds_to_delta_ex(st, pymicros, (st)->PyDateTime_DeltaType) static PyObject * multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) @@ -1999,7 +2001,8 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) if (pyus_out == NULL) return NULL; - result = microseconds_to_delta(pyus_out); + datetime_state *st = GLOBAL_STATE(); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; } @@ -2054,7 +2057,9 @@ multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, Py_DECREF(temp); if (pyus_out == NULL) goto error; - result = microseconds_to_delta(pyus_out); + + datetime_state *st = GLOBAL_STATE(); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); error: Py_XDECREF(pyus_in); @@ -2079,7 +2084,8 @@ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) if (pyus_out == NULL) return NULL; - result = microseconds_to_delta(pyus_out); + datetime_state *st = GLOBAL_STATE(); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; } @@ -2142,7 +2148,9 @@ truedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i) Py_DECREF(pyus_in); if (pyus_out == NULL) return NULL; - result = microseconds_to_delta(pyus_out); + + datetime_state *st = GLOBAL_STATE(); + result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; @@ -2152,8 +2160,9 @@ static PyObject * delta_add(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = GLOBAL_STATE(); - if (PyDelta_Check(left) && PyDelta_Check(right)) { + if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta + delta */ /* The C-level additions can't overflow because of the * invariant bounds. @@ -2162,7 +2171,7 @@ delta_add(PyObject *left, PyObject *right) int seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right); int microseconds = GET_TD_MICROSECONDS(left) + GET_TD_MICROSECONDS(right); - result = new_delta(days, seconds, microseconds, 1); + result = new_delta(st, days, seconds, microseconds, 1); } if (result == Py_NotImplemented) @@ -2173,7 +2182,9 @@ delta_add(PyObject *left, PyObject *right) static PyObject * delta_negative(PyDateTime_Delta *self) { - return new_delta(-GET_TD_DAYS(self), + datetime_state *state = GLOBAL_STATE(); + return new_delta(state, + -GET_TD_DAYS(self), -GET_TD_SECONDS(self), -GET_TD_MICROSECONDS(self), 1); @@ -2185,7 +2196,9 @@ delta_positive(PyDateTime_Delta *self) /* Could optimize this (by returning self) if this isn't a * subclass -- but who uses unary + ? Approximately nobody. */ - return new_delta(GET_TD_DAYS(self), + datetime_state *state = GLOBAL_STATE(); + return new_delta(state, + GET_TD_DAYS(self), GET_TD_SECONDS(self), GET_TD_MICROSECONDS(self), 0); @@ -2211,8 +2224,9 @@ static PyObject * delta_subtract(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = GLOBAL_STATE(); - if (PyDelta_Check(left) && PyDelta_Check(right)) { + if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta - delta */ /* The C-level additions can't overflow because of the * invariant bounds. @@ -2221,7 +2235,7 @@ delta_subtract(PyObject *left, PyObject *right) int seconds = GET_TD_SECONDS(left) - GET_TD_SECONDS(right); int microseconds = GET_TD_MICROSECONDS(left) - GET_TD_MICROSECONDS(right); - result = new_delta(days, seconds, microseconds, 1); + result = new_delta(st, days, seconds, microseconds, 1); } if (result == Py_NotImplemented) @@ -2245,7 +2259,8 @@ delta_cmp(PyObject *self, PyObject *other) static PyObject * delta_richcompare(PyObject *self, PyObject *other, int op) { - if (PyDelta_Check(other)) { + datetime_state *st = GLOBAL_STATE(); + if (PyDelta_Check(st, other)) { int diff = delta_cmp(self, other); return diff_to_bool(diff, op); } @@ -2273,8 +2288,9 @@ static PyObject * delta_multiply(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = GLOBAL_STATE(); - if (PyDelta_Check(left)) { + if (PyDelta_Check(st, left)) { /* delta * ??? */ if (PyLong_Check(right)) result = multiply_int_timedelta(right, @@ -2299,14 +2315,15 @@ static PyObject * delta_divide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = GLOBAL_STATE(); - if (PyDelta_Check(left)) { + if (PyDelta_Check(st, left)) { /* delta * ??? */ if (PyLong_Check(right)) result = divide_timedelta_int( (PyDateTime_Delta *)left, right); - else if (PyDelta_Check(right)) + else if (PyDelta_Check(st, right)) result = divide_timedelta_timedelta( (PyDateTime_Delta *)left, (PyDateTime_Delta *)right); @@ -2321,9 +2338,10 @@ static PyObject * delta_truedivide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; + datetime_state *st = GLOBAL_STATE(); - if (PyDelta_Check(left)) { - if (PyDelta_Check(right)) + if (PyDelta_Check(st, left)) { + if (PyDelta_Check(st, right)) result = truedivide_timedelta_timedelta( (PyDateTime_Delta *)left, (PyDateTime_Delta *)right); @@ -2347,8 +2365,9 @@ delta_remainder(PyObject *left, PyObject *right) PyObject *pyus_right; PyObject *pyus_remainder; PyObject *remainder; + datetime_state *st = GLOBAL_STATE(); - if (!PyDelta_Check(left) || !PyDelta_Check(right)) + if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; pyus_left = delta_to_microseconds((PyDateTime_Delta *)left); @@ -2367,7 +2386,7 @@ delta_remainder(PyObject *left, PyObject *right) if (pyus_remainder == NULL) return NULL; - remainder = microseconds_to_delta(pyus_remainder); + remainder = microseconds_to_delta(st, pyus_remainder); Py_DECREF(pyus_remainder); if (remainder == NULL) return NULL; @@ -2383,8 +2402,9 @@ delta_divmod(PyObject *left, PyObject *right) PyObject *divmod; PyObject *delta; PyObject *result; + datetime_state *st = GLOBAL_STATE(); - if (!PyDelta_Check(left) || !PyDelta_Check(right)) + if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; pyus_left = delta_to_microseconds((PyDateTime_Delta *)left); @@ -2403,7 +2423,7 @@ delta_divmod(PyObject *left, PyObject *right) if (divmod == NULL) return NULL; - delta = microseconds_to_delta(PyTuple_GET_ITEM(divmod, 1)); + delta = microseconds_to_delta(st, PyTuple_GET_ITEM(divmod, 1)); if (delta == NULL) { Py_DECREF(divmod); return NULL; @@ -2609,7 +2629,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) CLEANUP; } - self = microseconds_to_delta_ex(x, type); + self = microseconds_to_delta_ex(st, x, type); Py_DECREF(x); Done: return self; @@ -2737,6 +2757,22 @@ delta_reduce(PyDateTime_Delta* self, PyObject *Py_UNUSED(ignored)) return Py_BuildValue("ON", Py_TYPE(self), delta_getstate(self)); } +static int +delta_traverse(PyDateTime_Delta *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +delta_dealloc(PyDateTime_Delta *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + #define OFFSET(field) offsetof(PyDateTime_Delta, field) static PyMemberDef delta_members[] = { @@ -2769,82 +2805,41 @@ PyDoc_STR("Difference between two datetime values.\n\n" "All arguments are optional and default to 0.\n" "Arguments may be integers or floats, and may be positive or negative."); -static PyNumberMethods delta_as_number = { - delta_add, /* nb_add */ - delta_subtract, /* nb_subtract */ - delta_multiply, /* nb_multiply */ - delta_remainder, /* nb_remainder */ - delta_divmod, /* nb_divmod */ - 0, /* nb_power */ - (unaryfunc)delta_negative, /* nb_negative */ - (unaryfunc)delta_positive, /* nb_positive */ - (unaryfunc)delta_abs, /* nb_absolute */ - (inquiry)delta_bool, /* nb_bool */ - 0, /*nb_invert*/ - 0, /*nb_lshift*/ - 0, /*nb_rshift*/ - 0, /*nb_and*/ - 0, /*nb_xor*/ - 0, /*nb_or*/ - 0, /*nb_int*/ - 0, /*nb_reserved*/ - 0, /*nb_float*/ - 0, /*nb_inplace_add*/ - 0, /*nb_inplace_subtract*/ - 0, /*nb_inplace_multiply*/ - 0, /*nb_inplace_remainder*/ - 0, /*nb_inplace_power*/ - 0, /*nb_inplace_lshift*/ - 0, /*nb_inplace_rshift*/ - 0, /*nb_inplace_and*/ - 0, /*nb_inplace_xor*/ - 0, /*nb_inplace_or*/ - delta_divide, /* nb_floor_divide */ - delta_truedivide, /* nb_true_divide */ - 0, /* nb_inplace_floor_divide */ - 0, /* nb_inplace_true_divide */ +static PyType_Slot delta_slots[] = { + {Py_tp_repr, delta_repr}, + {Py_tp_hash, delta_hash}, + {Py_tp_str, delta_str}, + {Py_tp_doc, (void *)delta_doc}, + {Py_tp_richcompare, delta_richcompare}, + {Py_tp_methods, delta_methods}, + {Py_tp_members, delta_members}, + {Py_tp_new, delta_new}, + {Py_tp_traverse, delta_traverse}, + {Py_tp_dealloc, delta_dealloc}, + + // Number protocol + {Py_nb_add, delta_add}, + {Py_nb_subtract, delta_subtract}, + {Py_nb_multiply, delta_multiply}, + {Py_nb_remainder, delta_remainder}, + {Py_nb_divmod, delta_divmod}, + {Py_nb_negative, delta_negative}, + {Py_nb_positive, delta_positive}, + {Py_nb_absolute, delta_abs}, + {Py_nb_bool, delta_bool}, + {Py_nb_floor_divide, delta_divide}, + {Py_nb_true_divide, delta_truedivide}, + {0, NULL}, }; -static PyTypeObject PyDateTime_DeltaType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.timedelta", /* tp_name */ - sizeof(PyDateTime_Delta), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)delta_repr, /* tp_repr */ - &delta_as_number, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)delta_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)delta_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - delta_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - delta_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - delta_methods, /* tp_methods */ - delta_members, /* tp_members */ - 0, /* 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 */ - delta_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Spec delta_spec = { + .name = "datetime.timedelta", + .basicsize = sizeof(PyDateTime_Delta), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = delta_slots, }; /* @@ -3168,7 +3163,7 @@ date_add(PyObject *left, PyObject *right) if (PyDate_Check(st, left)) { /* date + ??? */ - if (PyDelta_Check(right)) + if (PyDelta_Check(st, right)) /* date + delta */ return add_date_timedelta((PyDateTime_Date *) left, (PyDateTime_Delta *) right, @@ -3178,7 +3173,7 @@ date_add(PyObject *left, PyObject *right) /* ??? + date * 'right' must be one of us, or we wouldn't have been called */ - if (PyDelta_Check(left)) + if (PyDelta_Check(st, left)) /* delta + date */ return add_date_timedelta((PyDateTime_Date *) right, (PyDateTime_Delta *) left, @@ -3203,9 +3198,9 @@ date_subtract(PyObject *left, PyObject *right) int right_ord = ymd_to_ord(GET_YEAR(right), GET_MONTH(right), GET_DAY(right)); - return new_delta(left_ord - right_ord, 0, 0, 0); + return new_delta(st, left_ord - right_ord, 0, 0, 0); } - if (PyDelta_Check(right)) { + if (PyDelta_Check(st, right)) { /* date - delta */ return add_date_timedelta((PyDateTime_Date *) left, (PyDateTime_Delta *) right, @@ -3654,8 +3649,8 @@ static PyType_Slot date_slots[] = { }; static PyType_Spec date_spec = { - .name = "datetime.date", /* tp_name */ - .basicsize = sizeof(PyDateTime_Date), /* tp_basicsize */ + .name = "datetime.date", + .basicsize = sizeof(PyDateTime_Date), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -3897,8 +3892,9 @@ timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw) { PyObject *offset; PyObject *name = NULL; + datetime_state *st = GLOBAL_STATE(); if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws, - &PyDateTime_DeltaType, &offset, &name)) + st->PyDateTime_DeltaType, &offset, &name)) return new_timezone(offset, name); return NULL; @@ -4474,8 +4470,9 @@ time_richcompare(PyObject *self, PyObject *other, int op) * we get off cheap. Note that if they're both naive, offset1 == * offset2 == Py_None at this point. */ + datetime_state *st = GLOBAL_STATE(); if ((offset1 == offset2) || - (PyDelta_Check(offset1) && PyDelta_Check(offset2) && + (PyDelta_Check(st, offset1) && PyDelta_Check(st, offset2) && delta_cmp(offset1, offset2) == 0)) { diff = memcmp(((PyDateTime_Time *)self)->data, ((PyDateTime_Time *)other)->data, @@ -4555,7 +4552,9 @@ time_hash(PyDateTime_Time *self) TIME_GET_MINUTE(self) * 60 + TIME_GET_SECOND(self); microseconds = TIME_GET_MICROSECOND(self); - temp1 = new_delta(0, seconds, microseconds, 1); + + datetime_state *st = GLOBAL_STATE(); + temp1 = new_delta(st, 0, seconds, microseconds, 1); if (temp1 == NULL) { Py_DECREF(offset); return -1; @@ -5593,14 +5592,14 @@ datetime_add(PyObject *left, PyObject *right) datetime_state *st = GLOBAL_STATE(); if (PyDateTime_Check(st, left)) { /* datetime + ??? */ - if (PyDelta_Check(right)) + if (PyDelta_Check(st, right)) /* datetime + delta */ return add_datetime_timedelta( (PyDateTime_DateTime *)left, (PyDateTime_Delta *)right, 1); } - else if (PyDelta_Check(left)) { + else if (PyDelta_Check(st, left)) { /* delta + datetime */ return add_datetime_timedelta((PyDateTime_DateTime *) right, (PyDateTime_Delta *) left, @@ -5672,7 +5671,7 @@ datetime_subtract(PyObject *left, PyObject *right) DATE_GET_SECOND(right)); delta_us = DATE_GET_MICROSECOND(left) - DATE_GET_MICROSECOND(right); - result = new_delta(delta_d, delta_s, delta_us, 1); + result = new_delta(st, delta_d, delta_s, delta_us, 1); if (result == NULL) return NULL; @@ -5681,7 +5680,7 @@ datetime_subtract(PyObject *left, PyObject *right) Py_DECREF(offdiff); } } - else if (PyDelta_Check(right)) { + else if (PyDelta_Check(st, right)) { /* datetime - delta */ result = add_datetime_timedelta( (PyDateTime_DateTime *)left, @@ -5931,7 +5930,7 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) * offset2 == Py_None at this point. */ if ((offset1 == offset2) || - (PyDelta_Check(offset1) && PyDelta_Check(offset2) && + (PyDelta_Check(st, offset1) && PyDelta_Check(st, offset2) && delta_cmp(offset1, offset2) == 0)) { diff = memcmp(((PyDateTime_DateTime *)self)->data, ((PyDateTime_DateTime *)other)->data, @@ -6026,7 +6025,9 @@ datetime_hash(PyDateTime_DateTime *self) seconds = DATE_GET_HOUR(self) * 3600 + DATE_GET_MINUTE(self) * 60 + DATE_GET_SECOND(self); - temp1 = new_delta(days, seconds, + + datetime_state *st = GLOBAL_STATE(); + temp1 = new_delta(st, days, seconds, DATE_GET_MICROSECOND(self), 1); if (temp1 == NULL) { @@ -6094,9 +6095,11 @@ local_timezone_from_timestamp(time_t timestamp) if (_PyTime_localtime(timestamp, &local_time_tm) != 0) return NULL; + + datetime_state *state = GLOBAL_STATE(); #ifdef HAVE_STRUCT_TM_TM_ZONE zone = local_time_tm.tm_zone; - delta = new_delta(0, local_time_tm.tm_gmtoff, 0, 1); + delta = new_delta(state, 0, local_time_tm.tm_gmtoff, 0, 1); #else /* HAVE_STRUCT_TM_TM_ZONE */ { PyObject *local_time, *utc_time; @@ -6104,7 +6107,6 @@ local_timezone_from_timestamp(time_t timestamp) char buf[100]; strftime(buf, sizeof(buf), "%Z", &local_time_tm); zone = buf; - datetime_state *state = GLOBAL_STATE(); local_time = new_datetime(state, local_time_tm.tm_year + 1900, local_time_tm.tm_mon + 1, @@ -6160,7 +6162,7 @@ local_timezone(PyDateTime_DateTime *utc_time) delta = datetime_subtract((PyObject *)utc_time, st->PyDateTime_Epoch); if (delta == NULL) return NULL; - one_second = new_delta(0, 1, 0, 0); + one_second = new_delta(st, 0, 1, 0, 0); if (one_second == NULL) { Py_DECREF(delta); return NULL; @@ -6233,6 +6235,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) return (PyDateTime_DateTime*)Py_NewRef(self); } + datetime_state *st = GLOBAL_STATE(); /* Convert self to UTC. */ offset = call_utcoffset(self_tzinfo, (PyObject *)self); Py_DECREF(self_tzinfo); @@ -6242,7 +6245,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) Py_DECREF(offset); goto naive; } - else if (!PyDelta_Check(offset)) { + else if (!PyDelta_Check(st, offset)) { Py_DECREF(offset); PyErr_Format(PyExc_TypeError, "utcoffset() returned %.200s," " expected timedelta or None", Py_TYPE(offset)->tp_name); @@ -6255,7 +6258,6 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) if (result == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); /* Make sure result is aware and UTC. */ if (!HASTZINFO(result)) { temp = (PyObject *)result; @@ -6635,8 +6637,8 @@ static PyType_Slot datetime_slots[] = { }; static PyType_Spec datetime_spec = { - .name = "datetime.datetime", /* tp_name */ - .basicsize = sizeof(PyDateTime_DateTime), /* tp_basicsize */ + .name = "datetime.datetime", + .basicsize = sizeof(PyDateTime_DateTime), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | @@ -6666,7 +6668,7 @@ get_datetime_capi(datetime_state *st) capi->DateType = st->PyDateTime_DateType; capi->DateTimeType = st->PyDateTime_DateTimeType; capi->TimeType = &PyDateTime_TimeType; - capi->DeltaType = &PyDateTime_DeltaType; + capi->DeltaType = st->PyDateTime_DeltaType; capi->TZInfoType = &PyDateTime_TZInfoType; capi->Date_FromDate = new_date_ex; capi->DateTime_FromDateAndTime = new_datetime_ex; @@ -6716,7 +6718,6 @@ _datetime_exec(PyObject *module) PyTypeObject *types[] = { &PyDateTime_TimeType, - &PyDateTime_DeltaType, &PyDateTime_TZInfoType, &PyDateTime_TimeZoneType, }; @@ -6731,6 +6732,7 @@ _datetime_exec(PyObject *module) return -1; } + ADD_TYPE(module, st->PyDateTime_DeltaType, &delta_spec, NULL); ADD_TYPE(module, st->PyDateTime_DateType, &date_spec, NULL); ADD_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, st->PyDateTime_DateType); @@ -6751,23 +6753,23 @@ _datetime_exec(PyObject *module) } while(0) /* timedelta values */ - PyObject *d = PyDateTime_DeltaType.tp_dict; - DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); - DATETIME_ADD_MACRO(d, "min", new_delta(-MAX_DELTA_DAYS, 0, 0, 0)); + PyObject *d = st->PyDateTime_DeltaType->tp_dict; + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); + DATETIME_ADD_MACRO(d, "min", new_delta(st, -MAX_DELTA_DAYS, 0, 0, 0)); DATETIME_ADD_MACRO(d, "max", - new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0)); + new_delta(st, MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0)); /* date values */ d = st->PyDateTime_DateType->tp_dict; DATETIME_ADD_MACRO(d, "min", new_date(st, 1, 1, 1)); DATETIME_ADD_MACRO(d, "max", new_date(st, MAXYEAR, 12, 31)); - DATETIME_ADD_MACRO(d, "resolution", new_delta(1, 0, 0, 0)); + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 1, 0, 0, 0)); /* time values */ d = PyDateTime_TimeType.tp_dict; DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0)); DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0)); - DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); /* datetime values */ d = st->PyDateTime_DateTimeType->tp_dict; @@ -6775,11 +6777,11 @@ _datetime_exec(PyObject *module) new_datetime(st, 1, 1, 1, 0, 0, 0, 0, Py_None, 0)); DATETIME_ADD_MACRO(d, "max", new_datetime(st, MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None, 0)); - DATETIME_ADD_MACRO(d, "resolution", new_delta(0, 0, 1, 0)); + DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); /* timezone values */ d = PyDateTime_TimeZoneType.tp_dict; - PyObject *delta = new_delta(0, 0, 0, 0); + PyObject *delta = new_delta(st, 0, 0, 0, 0); if (delta == NULL) { return -1; } @@ -6799,7 +6801,7 @@ _datetime_exec(PyObject *module) /* bpo-37642: These attributes are rounded to the nearest minute for backwards * compatibility, even though the constructor will accept a wider range of * values. This may change in the future.*/ - delta = new_delta(-1, 60, 0, 1); /* -23:59 */ + delta = new_delta(st, -1, 60, 0, 1); /* -23:59 */ if (delta == NULL) { return -1; } @@ -6808,7 +6810,7 @@ _datetime_exec(PyObject *module) Py_DECREF(delta); DATETIME_ADD_MACRO(d, "min", x); - delta = new_delta(0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */ + delta = new_delta(st, 0, (23 * 60 + 59) * 60, 0, 0); /* +23:59 */ if (delta == NULL) { return -1; } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 7c10f93149af97..ba8375027b4602 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -379,7 +379,6 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -Modules/_datetimemodule.c - PyDateTime_DeltaType - Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - From 780f261587c262facf091f90d4df2faabe835520 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 22:40:21 +0100 Subject: [PATCH 11/30] PyDateTime_IsoCalendarDateType --- Modules/_datetimemodule.c | 60 ++++++++++++++------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index c8cf0666cf46ba..bb28f3c6796dff 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -56,6 +56,7 @@ typedef struct { PyTypeObject *PyDateTime_DateTimeType; PyTypeObject *PyDateTime_DateType; PyTypeObject *PyDateTime_DeltaType; + PyTypeObject *PyDateTime_IsoCalendarDateType; } datetime_state; static datetime_state global_state; @@ -66,7 +67,7 @@ static datetime_state global_state; module datetime class datetime.datetime "PyDateTime_DateTime *" "clinic_state()->PyDateTime_DateTimeType" class datetime.date "PyDateTime_Date *" "clinic_state()->PyDateTime_DateType" -class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCalendarDateType" +class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->PyDateTime_IsoCalendarDateType" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=36a187caa1dda205]*/ @@ -154,7 +155,6 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "&PyDateTime_IsoCa #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) /* Forward declarations. */ -static PyTypeObject PyDateTime_IsoCalendarDateType; static PyTypeObject PyDateTime_TimeType; static PyTypeObject PyDateTime_TZInfoType; static PyTypeObject PyDateTime_TimeZoneType; @@ -3366,6 +3366,23 @@ iso_calendar_date_weekday(PyDateTime_IsoCalendarDate *self, void *unused) return Py_NewRef(weekday); } +static int +iso_calendar_date_traverse(PyDateTime_IsoCalendarDate *self, visitproc visit, + void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +iso_calendar_date_dealloc(PyDateTime_IsoCalendarDate *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); +} + static PyGetSetDef iso_calendar_date_getset[] = { {"year", (getter)iso_calendar_date_year}, {"week", (getter)iso_calendar_date_week}, @@ -3379,17 +3396,24 @@ static PyMethodDef iso_calendar_date_methods[] = { {NULL, NULL}, }; -static PyTypeObject PyDateTime_IsoCalendarDateType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "datetime.IsoCalendarDate", - .tp_basicsize = sizeof(PyDateTime_IsoCalendarDate), - .tp_repr = (reprfunc) iso_calendar_date_repr, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = iso_calendar_date__doc__, - .tp_methods = iso_calendar_date_methods, - .tp_getset = iso_calendar_date_getset, - // .tp_base = &PyTuple_Type, // filled in PyInit__datetime - .tp_new = iso_calendar_date_new, +static PyType_Slot isocal_slots[] = { + {Py_tp_repr, iso_calendar_date_repr}, + {Py_tp_doc, (void *)iso_calendar_date__doc__}, + {Py_tp_methods, iso_calendar_date_methods}, + {Py_tp_getset, iso_calendar_date_getset}, + {Py_tp_new, iso_calendar_date_new}, + {Py_tp_dealloc, iso_calendar_date_dealloc}, + {Py_tp_traverse, iso_calendar_date_traverse}, + {0, NULL}, +}; + +static PyType_Spec isocal_spec = { + .name = "datetime.IsoCalendarDate", + .basicsize = sizeof(PyDateTime_IsoCalendarDate), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = isocal_slots, }; /*[clinic input] @@ -3439,7 +3463,8 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) week = 0; } - PyObject* v = iso_calendar_date_new_impl(&PyDateTime_IsoCalendarDateType, + datetime_state *st = GLOBAL_STATE(); + PyObject* v = iso_calendar_date_new_impl(st->PyDateTime_IsoCalendarDateType, year, week + 1, day + 1); if (v == NULL) { return NULL; @@ -6713,7 +6738,6 @@ _datetime_exec(PyObject *module) // `&...` is not a constant expression according to a strict reading // of C standards. Fill tp_base at run-time rather than statically. // See https://bugs.python.org/issue40777 - PyDateTime_IsoCalendarDateType.tp_base = &PyTuple_Type; PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType; PyTypeObject *types[] = { @@ -6728,10 +6752,8 @@ _datetime_exec(PyObject *module) } } - if (PyType_Ready(&PyDateTime_IsoCalendarDateType) < 0) { - return -1; - } - + ADD_TYPE(module, st->PyDateTime_IsoCalendarDateType, &isocal_spec, + &PyTuple_Type); ADD_TYPE(module, st->PyDateTime_DeltaType, &delta_spec, NULL); ADD_TYPE(module, st->PyDateTime_DateType, &date_spec, NULL); ADD_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index ba8375027b4602..9c2136df9ba591 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -379,7 +379,6 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - From 2d16589f4a1a85c7c3b8f7a68d65e952ff9f2ac5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 22:40:34 +0100 Subject: [PATCH 12/30] Regen clinic --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index bb28f3c6796dff..31cd50e25e1cce 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -69,7 +69,7 @@ class datetime.datetime "PyDateTime_DateTime *" "clinic_state()->PyDateTime_Date class datetime.date "PyDateTime_Date *" "clinic_state()->PyDateTime_DateType" class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->PyDateTime_IsoCalendarDateType" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=36a187caa1dda205]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8a333fc5cbf6a146]*/ #define clinic_state() (GLOBAL_STATE()) #include "clinic/_datetimemodule.c.h" From 5566ce5871fc06d2937ae8a8c738a2846bf10c78 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 22:54:26 +0100 Subject: [PATCH 13/30] PyDateTime_TZInfoType and PyDateTime_TimeZoneType --- Modules/_datetimemodule.c | 189 ++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 - 2 files changed, 91 insertions(+), 100 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 31cd50e25e1cce..10557aa85bfbd5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -30,11 +30,9 @@ #define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType) #define PyDelta_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DeltaType) +#define PyTZInfo_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TZInfoType) -#define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType) -#define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TZInfoType) - -#define PyTimezone_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeZoneType) +#define PyTimezone_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TimeZoneType) typedef struct { /* Conversion factors. */ @@ -57,6 +55,8 @@ typedef struct { PyTypeObject *PyDateTime_DateType; PyTypeObject *PyDateTime_DeltaType; PyTypeObject *PyDateTime_IsoCalendarDateType; + PyTypeObject *PyDateTime_TZInfoType; + PyTypeObject *PyDateTime_TimeZoneType; } datetime_state; static datetime_state global_state; @@ -156,8 +156,6 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->P /* Forward declarations. */ static PyTypeObject PyDateTime_TimeType; -static PyTypeObject PyDateTime_TZInfoType; -static PyTypeObject PyDateTime_TimeZoneType; static int check_tzinfo_subclass(PyObject *p); @@ -1169,9 +1167,9 @@ typedef struct static PyObject * create_timezone(PyObject *offset, PyObject *name) { - PyDateTime_TimeZone *self; - PyTypeObject *type = &PyDateTime_TimeZoneType; datetime_state *st = GLOBAL_STATE(); + PyDateTime_TimeZone *self; + PyTypeObject *type = st->PyDateTime_TimeZoneType; assert(offset != NULL); assert(PyDelta_Check(st, offset)); assert(name == NULL || PyUnicode_Check(name)); @@ -1223,7 +1221,8 @@ new_timezone(PyObject *offset, PyObject *name) static int check_tzinfo_subclass(PyObject *p) { - if (p == Py_None || PyTZInfo_Check(p)) + datetime_state *st = GLOBAL_STATE(); + if (p == Py_None || PyTZInfo_Check(st, p)) return 0; PyErr_Format(PyExc_TypeError, "tzinfo argument must be None or of a tzinfo subclass, " @@ -1262,8 +1261,9 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) { PyObject *offset; + datetime_state *st = GLOBAL_STATE(); assert(tzinfo != NULL); - assert(PyTZInfo_Check(tzinfo) || tzinfo == Py_None); + assert(PyTZInfo_Check(st, tzinfo) || tzinfo == Py_None); assert(tzinfoarg != NULL); if (tzinfo == Py_None) @@ -1271,7 +1271,6 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) offset = PyObject_CallMethod(tzinfo, name, "O", tzinfoarg); if (offset == Py_None || offset == NULL) return offset; - datetime_state *st = GLOBAL_STATE(); if (PyDelta_Check(st, offset)) { if ((GET_TD_DAYS(offset) == -1 && GET_TD_SECONDS(offset) == 0 && @@ -3844,6 +3843,22 @@ tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) return Py_BuildValue("(ONN)", Py_TYPE(self), args, state); } +static int +tzinfo_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +tzinfo_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + static PyMethodDef tzinfo_methods[] = { {"tzname", (PyCFunction)tzinfo_tzname, METH_O, @@ -3868,46 +3883,22 @@ static PyMethodDef tzinfo_methods[] = { static const char tzinfo_doc[] = PyDoc_STR("Abstract base class for time zone info objects."); -static PyTypeObject PyDateTime_TZInfoType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.tzinfo", /* tp_name */ - sizeof(PyDateTime_TZInfo), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - tzinfo_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - tzinfo_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 */ - 0, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot tzinfo_slots[] = { + {Py_tp_doc, (void *)tzinfo_doc}, + {Py_tp_methods, tzinfo_methods}, + {Py_tp_dealloc, tzinfo_dealloc}, + {Py_tp_traverse, tzinfo_traverse}, + {0, NULL}, +}; + +static PyType_Spec tzinfo_spec = { + .name = "datetime.tzinfo", + .basicsize = sizeof(PyDateTime_TZInfo), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = tzinfo_slots, }; static char *timezone_kws[] = {"offset", "name", NULL}; @@ -3925,12 +3916,31 @@ timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw) return NULL; } -static void -timezone_dealloc(PyDateTime_TimeZone *self) +static int +timezone_traverse(PyDateTime_TimeZone *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->offset); + Py_VISIT(self->name); + return 0; +} + +static int +timezone_clear(PyDateTime_TimeZone *self) { Py_CLEAR(self->offset); Py_CLEAR(self->name); + return 0; +} + +static void +timezone_dealloc(PyDateTime_TimeZone *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)timezone_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -3939,7 +3949,8 @@ timezone_richcompare(PyDateTime_TimeZone *self, { if (op != Py_EQ && op != Py_NE) Py_RETURN_NOTIMPLEMENTED; - if (!PyTimezone_Check(other)) { + datetime_state *st = GLOBAL_STATE(); + if (!PyTimezone_Check(st, other)) { Py_RETURN_NOTIMPLEMENTED; } return delta_richcompare(self->offset, other->offset, op); @@ -4106,45 +4117,27 @@ static PyMethodDef timezone_methods[] = { static const char timezone_doc[] = PyDoc_STR("Fixed offset from UTC implementation of tzinfo."); -static PyTypeObject PyDateTime_TimeZoneType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.timezone", /* tp_name */ - sizeof(PyDateTime_TimeZone), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)timezone_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)timezone_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)timezone_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)timezone_str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - timezone_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)timezone_richcompare,/* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - timezone_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base; filled in PyInit__datetime */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - timezone_new, /* tp_new */ +static PyType_Slot timezone_slots[] = { + {Py_tp_dealloc, timezone_dealloc}, + {Py_tp_traverse, timezone_traverse}, + {Py_tp_clear, timezone_clear}, + {Py_tp_repr, timezone_repr}, + {Py_tp_hash, timezone_hash}, + {Py_tp_str, timezone_str}, + {Py_tp_doc, (void *)timezone_doc}, + {Py_tp_richcompare, timezone_richcompare}, + {Py_tp_methods, timezone_methods}, + {Py_tp_new, timezone_new}, + {0, NULL}, +}; + +static PyType_Spec timezone_spec = { + .name = "datetime.timezone", + .basicsize = sizeof(PyDateTime_TimeZone), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = timezone_slots, }; /* @@ -6694,7 +6687,7 @@ get_datetime_capi(datetime_state *st) capi->DateTimeType = st->PyDateTime_DateTimeType; capi->TimeType = &PyDateTime_TimeType; capi->DeltaType = st->PyDateTime_DeltaType; - capi->TZInfoType = &PyDateTime_TZInfoType; + capi->TZInfoType = st->PyDateTime_TZInfoType; capi->Date_FromDate = new_date_ex; capi->DateTime_FromDateAndTime = new_datetime_ex; capi->Time_FromTime = new_time_ex; @@ -6738,12 +6731,9 @@ _datetime_exec(PyObject *module) // `&...` is not a constant expression according to a strict reading // of C standards. Fill tp_base at run-time rather than statically. // See https://bugs.python.org/issue40777 - PyDateTime_TimeZoneType.tp_base = &PyDateTime_TZInfoType; PyTypeObject *types[] = { &PyDateTime_TimeType, - &PyDateTime_TZInfoType, - &PyDateTime_TimeZoneType, }; for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) { @@ -6752,6 +6742,9 @@ _datetime_exec(PyObject *module) } } + ADD_TYPE(module, st->PyDateTime_TZInfoType, &tzinfo_spec, NULL); + ADD_TYPE(module, st->PyDateTime_TimeZoneType, &timezone_spec, + st->PyDateTime_TZInfoType); ADD_TYPE(module, st->PyDateTime_IsoCalendarDateType, &isocal_spec, &PyTuple_Type); ADD_TYPE(module, st->PyDateTime_DeltaType, &delta_spec, NULL); @@ -6802,7 +6795,7 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); /* timezone values */ - d = PyDateTime_TimeZoneType.tp_dict; + d = st->PyDateTime_TimeZoneType->tp_dict; PyObject *delta = new_delta(st, 0, 0, 0, 0); if (delta == NULL) { return -1; diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 9c2136df9ba591..badf63d736f38c 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -379,9 +379,7 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -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 - From 89775f3adca618ce67f97f47cb59606ad07aeee7 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 23:04:30 +0100 Subject: [PATCH 14/30] PyDateTime_TimeType --- Modules/_datetimemodule.c | 162 ++++++++++---------- Tools/c-analyzer/cpython/globals-to-fix.tsv | 1 - 2 files changed, 77 insertions(+), 86 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 10557aa85bfbd5..244246dfc3dfda 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -23,15 +23,11 @@ # include /* struct timeval */ #endif -#define PyDate_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateType) #define PyDateTime_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateTimeType) - -#define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) -#define PyTime_CheckExact(op) Py_IS_TYPE(op, &PyDateTime_TimeType) - +#define PyDate_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DateType) #define PyDelta_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_DeltaType) #define PyTZInfo_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TZInfoType) - +#define PyTime_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TimeType) #define PyTimezone_Check(st, op) PyObject_TypeCheck(op, (st)->PyDateTime_TimeZoneType) typedef struct { @@ -56,6 +52,7 @@ typedef struct { PyTypeObject *PyDateTime_DeltaType; PyTypeObject *PyDateTime_IsoCalendarDateType; PyTypeObject *PyDateTime_TZInfoType; + PyTypeObject *PyDateTime_TimeType; PyTypeObject *PyDateTime_TimeZoneType; } datetime_state; @@ -154,9 +151,6 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->P */ #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) -/* Forward declarations. */ -static PyTypeObject PyDateTime_TimeType; - static int check_tzinfo_subclass(PyObject *p); @@ -1116,8 +1110,8 @@ new_time_ex(int hour, int minute, int second, int usecond, return new_time_ex2(hour, minute, second, usecond, tzinfo, 0, type); } -#define new_time(hh, mm, ss, us, tzinfo, fold) \ - new_time_ex2(hh, mm, ss, us, tzinfo, fold, &PyDateTime_TimeType) +#define new_time(st, hh, mm, ss, us, tzinfo, fold) \ + new_time_ex2(hh, mm, ss, us, tzinfo, fold, st->PyDateTime_TimeType) /* Create a timedelta instance. Normalize the members iff normalize is * true. Passing false is a speed optimization, if you know for sure @@ -1241,10 +1235,12 @@ get_tzinfo_member(PyObject *self) PyObject *tzinfo = NULL; datetime_state *st = GLOBAL_STATE(); - if (PyDateTime_Check(st, self) && HASTZINFO(self)) + if (PyDateTime_Check(st, self) && HASTZINFO(self)) { tzinfo = ((PyDateTime_DateTime *)self)->tzinfo; - else if (PyTime_Check(self) && HASTZINFO(self)) + } + else if (PyTime_Check(st, self) && HASTZINFO(self)) { tzinfo = ((PyDateTime_Time *)self)->tzinfo; + } return tzinfo; } @@ -1582,12 +1578,15 @@ make_freplacement(PyObject *object) { datetime_state *st = GLOBAL_STATE(); char freplacement[64]; - if (PyTime_Check(object)) + if (PyTime_Check(st, object)) { sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object)); - else if (PyDateTime_Check(st, object)) + } + else if (PyDateTime_Check(st, object)) { sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object)); - else + } + else { sprintf(freplacement, "%06d", 0); + } return PyBytes_FromStringAndSize(freplacement, strlen(freplacement)); } @@ -4293,6 +4292,21 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) return self; } +static int +time_traverse(PyDateTime_Time *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->tzinfo); + return 0; +} + +static int +time_clear(PyDateTime_Time *self) +{ + Py_CLEAR(self->tzinfo); + return 0; +} + /* * Destructor. */ @@ -4300,10 +4314,11 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) static void time_dealloc(PyDateTime_Time *self) { - if (HASTZINFO(self)) { - Py_XDECREF(self->tzinfo); - } - Py_TYPE(self)->tp_free((PyObject *)self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)time_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } /* @@ -4469,8 +4484,10 @@ time_richcompare(PyObject *self, PyObject *other, int op) PyObject *offset1, *offset2; int diff; - if (! PyTime_Check(other)) + datetime_state *st = GLOBAL_STATE(); + if (!PyTime_Check(st, other)) { Py_RETURN_NOTIMPLEMENTED; + } if (GET_TIME_TZINFO(self) == GET_TIME_TZINFO(other)) { diff = memcmp(((PyDateTime_Time *)self)->data, @@ -4488,7 +4505,6 @@ time_richcompare(PyObject *self, PyObject *other, int op) * we get off cheap. Note that if they're both naive, offset1 == * offset2 == Py_None at this point. */ - datetime_state *st = GLOBAL_STATE(); if ((offset1 == offset2) || (PyDelta_Check(st, offset1) && PyDelta_Check(st, offset2) && delta_cmp(offset1, offset2) == 0)) { @@ -4664,9 +4680,10 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { return NULL; } + datetime_state *st = GLOBAL_STATE(); PyObject *t; - if ( (PyTypeObject *)cls == &PyDateTime_TimeType ) { - t = new_time(hour, minute, second, microsecond, tzinfo, 0); + if ( (PyTypeObject *)cls == st->PyDateTime_TimeType ) { + t = new_time(st, hour, minute, second, microsecond, tzinfo, 0); } else { t = PyObject_CallFunction(cls, "iiiiO", hour, minute, second, microsecond, tzinfo); @@ -4771,46 +4788,30 @@ PyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time All arguments are optional. tzinfo may be None, or an instance of\n\ a tzinfo subclass. The remaining arguments may be ints.\n"); -static PyTypeObject PyDateTime_TimeType = { - PyVarObject_HEAD_INIT(NULL, 0) - "datetime.time", /* tp_name */ - sizeof(PyDateTime_Time), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)time_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)time_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)time_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)time_str, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - time_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - time_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - time_methods, /* tp_methods */ - 0, /* tp_members */ - time_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - time_alloc, /* tp_alloc */ - time_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot time_slots[] = { + {Py_tp_dealloc, time_dealloc}, + {Py_tp_traverse, time_traverse}, + {Py_tp_clear, time_clear}, + {Py_tp_repr, time_repr}, + {Py_tp_hash, time_hash}, + {Py_tp_str, time_str}, + {Py_tp_doc, (void *)time_doc}, + {Py_tp_richcompare, time_richcompare}, + {Py_tp_methods, time_methods}, + {Py_tp_getset, time_getset}, + {Py_tp_alloc, time_alloc}, + {Py_tp_new, time_new}, + {0, NULL}, +}; + +static PyType_Spec time_spec = { + .name = "datetime.time", + .basicsize = sizeof(PyDateTime_Time), + .flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = time_slots, }; /* @@ -5249,7 +5250,7 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) datetime_state *st = GLOBAL_STATE(); if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords, st->PyDateTime_DateType, &date, - &PyDateTime_TimeType, &time, &tzinfo)) { + st->PyDateTime_TimeType, &time, &tzinfo)) { if (tzinfo == NULL) { if (HASTZINFO(time)) tzinfo = ((PyDateTime_Time *)time)->tzinfo; @@ -6438,7 +6439,9 @@ datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - return new_time(DATE_GET_HOUR(self), + datetime_state *state = GLOBAL_STATE(); + return new_time(state, + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self), DATE_GET_MICROSECOND(self), @@ -6449,7 +6452,9 @@ datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - return new_time(DATE_GET_HOUR(self), + datetime_state *state = GLOBAL_STATE(); + return new_time(state, + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self), DATE_GET_MICROSECOND(self), @@ -6685,7 +6690,7 @@ get_datetime_capi(datetime_state *st) } capi->DateType = st->PyDateTime_DateType; capi->DateTimeType = st->PyDateTime_DateTimeType; - capi->TimeType = &PyDateTime_TimeType; + capi->TimeType = st->PyDateTime_TimeType; capi->DeltaType = st->PyDateTime_DeltaType; capi->TZInfoType = st->PyDateTime_TZInfoType; capi->Date_FromDate = new_date_ex; @@ -6728,20 +6733,7 @@ _datetime_exec(PyObject *module) } \ } while (0) - // `&...` is not a constant expression according to a strict reading - // of C standards. Fill tp_base at run-time rather than statically. - // See https://bugs.python.org/issue40777 - - PyTypeObject *types[] = { - &PyDateTime_TimeType, - }; - - for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) { - if (PyModule_AddType(module, types[i]) < 0) { - return -1; - } - } - + ADD_TYPE(module, st->PyDateTime_TimeType, &time_spec, NULL); ADD_TYPE(module, st->PyDateTime_TZInfoType, &tzinfo_spec, NULL); ADD_TYPE(module, st->PyDateTime_TimeZoneType, &timezone_spec, st->PyDateTime_TZInfoType); @@ -6781,9 +6773,9 @@ _datetime_exec(PyObject *module) DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 1, 0, 0, 0)); /* time values */ - d = PyDateTime_TimeType.tp_dict; - DATETIME_ADD_MACRO(d, "min", new_time(0, 0, 0, 0, Py_None, 0)); - DATETIME_ADD_MACRO(d, "max", new_time(23, 59, 59, 999999, Py_None, 0)); + d = st->PyDateTime_TimeType->tp_dict; + DATETIME_ADD_MACRO(d, "min", new_time(st, 0, 0, 0, 0, Py_None, 0)); + DATETIME_ADD_MACRO(d, "max", new_time(st, 23, 59, 59, 999999, Py_None, 0)); DATETIME_ADD_MACRO(d, "resolution", new_delta(st, 0, 0, 1, 0)); /* datetime values */ diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index badf63d736f38c..7c06783efe23ec 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -379,7 +379,6 @@ Modules/_ctypes/ctypes.h - _ctypes_ptrtype_cache - Modules/_ctypes/ctypes.h - basespec_string - Modules/_ctypes/stgdict.c - PyCStgDict_Type - Modules/_cursesmodule.c - PyCursesWindow_Type - -Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_decimal/_decimal.c - PyDecContextManager_Type - Modules/_decimal/_decimal.c - PyDecContext_Type - Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - From e798939d4cc28f5c54df4be68ba15427a7ffd1a5 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 23:05:22 +0100 Subject: [PATCH 15/30] Visit and clear all types --- Modules/_datetimemodule.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 244246dfc3dfda..2b72c7d906e51e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6915,6 +6915,12 @@ module_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->PyDateTime_TimeZone_UTC); Py_VISIT(state->PyDateTime_Epoch); Py_VISIT(state->PyDateTime_DateTimeType); + Py_VISIT(state->PyDateTime_DateType); + Py_VISIT(state->PyDateTime_DeltaType); + Py_VISIT(state->PyDateTime_IsoCalendarDateType); + Py_VISIT(state->PyDateTime_TZInfoType); + Py_VISIT(state->PyDateTime_TimeType); + Py_VISIT(state->PyDateTime_TimeZoneType); return 0; } @@ -6932,6 +6938,12 @@ module_clear(PyObject *module) Py_CLEAR(state->PyDateTime_TimeZone_UTC); Py_CLEAR(state->PyDateTime_Epoch); Py_CLEAR(state->PyDateTime_DateTimeType); + Py_CLEAR(state->PyDateTime_DateType); + Py_CLEAR(state->PyDateTime_DeltaType); + Py_CLEAR(state->PyDateTime_IsoCalendarDateType); + Py_CLEAR(state->PyDateTime_TZInfoType); + Py_CLEAR(state->PyDateTime_TimeType); + Py_CLEAR(state->PyDateTime_TimeZoneType); return 0; } From 78e00234f356fb94a2be85df4d1f321184ecff20 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 21 Feb 2023 23:36:52 +0100 Subject: [PATCH 16/30] Get rid of GLOBAL_STATE --- Modules/_datetimemodule.c | 212 ++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 88 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 2b72c7d906e51e..1ab6b114601c98 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -56,9 +56,33 @@ typedef struct { PyTypeObject *PyDateTime_TimeZoneType; } datetime_state; -static datetime_state global_state; +static inline datetime_state * +get_module_state(PyObject *mod) +{ + void *state = PyModule_GetState(mod); + assert(state != NULL); + return (datetime_state *)state; +} + +static inline datetime_state * +get_module_state_by_cls(PyTypeObject *defining_class) +{ + void *state = PyType_GetModuleState(defining_class); + assert(state != NULL); + return (datetime_state *)state; +} + +static struct PyModuleDef datetimemodule; + +static inline datetime_state * +find_module_state_by_def(PyTypeObject *type) +{ + PyObject *mod = PyType_GetModuleByDef(type, &datetimemodule); + assert(mod != NULL); + return get_module_state(mod); +} -#define GLOBAL_STATE() (&global_state) +#define find_module_state_by_def(obj) find_module_state_by_def((PyTypeObject *)(obj)) /*[clinic input] module datetime @@ -68,7 +92,7 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->P [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=8a333fc5cbf6a146]*/ -#define clinic_state() (GLOBAL_STATE()) +#define clinic_state() (fixme()) #include "clinic/_datetimemodule.c.h" #undef clinic_state @@ -151,7 +175,7 @@ class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->P */ #define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) -static int check_tzinfo_subclass(PyObject *p); +static int check_tzinfo_subclass(datetime_state *st, PyObject *p); /* --------------------------------------------------------------------------- @@ -974,7 +998,7 @@ new_datetime_ex(int, int, int, int, int, int, int, PyObject *, PyTypeObject *); static PyObject * new_date_subclass_ex(int year, int month, int day, PyObject *cls) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(cls); PyObject *result; // We have "fast path" constructors for two subclasses: date and datetime if ((PyTypeObject *)cls == st->PyDateTime_DateType) { @@ -1005,7 +1029,8 @@ new_datetime_ex2(int year, int month, int day, int hour, int minute, if (check_time_args(hour, minute, second, usecond, fold) < 0) { return NULL; } - if (check_tzinfo_subclass(tzinfo) < 0) { + datetime_state *st = find_module_state_by_def(type); + if (check_tzinfo_subclass(st, tzinfo) < 0) { return NULL; } @@ -1042,7 +1067,7 @@ new_datetime_subclass_fold_ex(int year, int month, int day, int hour, int minute int second, int usecond, PyObject *tzinfo, int fold, PyObject *cls) { PyObject* dt; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(cls); if ((PyTypeObject*)cls == st->PyDateTime_DateTimeType) { // Use the fast path constructor dt = new_datetime(st, year, month, day, hour, minute, second, usecond, @@ -1083,7 +1108,8 @@ new_time_ex2(int hour, int minute, int second, int usecond, if (check_time_args(hour, minute, second, usecond, fold) < 0) { return NULL; } - if (check_tzinfo_subclass(tzinfo) < 0) { + datetime_state *st = find_module_state_by_def(type); + if (check_tzinfo_subclass(st, tzinfo) < 0) { return NULL; } @@ -1159,9 +1185,8 @@ typedef struct that offset is a timedelta instance and name is either NULL or a unicode object. */ static PyObject * -create_timezone(PyObject *offset, PyObject *name) +create_timezone(datetime_state *st, PyObject *offset, PyObject *name) { - datetime_state *st = GLOBAL_STATE(); PyDateTime_TimeZone *self; PyTypeObject *type = st->PyDateTime_TimeZoneType; assert(offset != NULL); @@ -1182,13 +1207,12 @@ static int delta_bool(PyDateTime_Delta *self); static PyObject * new_timezone(PyObject *offset, PyObject *name) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(offset)); assert(offset != NULL); assert(PyDelta_Check(st, offset)); assert(name == NULL || PyUnicode_Check(name)); if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { - datetime_state *st = GLOBAL_STATE(); return Py_NewRef(st->PyDateTime_TimeZone_UTC); } if ((GET_TD_DAYS(offset) == -1 && @@ -1202,7 +1226,7 @@ new_timezone(PyObject *offset, PyObject *name) return NULL; } - return create_timezone(offset, name); + return create_timezone(st, offset, name); } /* --------------------------------------------------------------------------- @@ -1213,9 +1237,8 @@ new_timezone(PyObject *offset, PyObject *name) * raise TypeError and return -1. */ static int -check_tzinfo_subclass(PyObject *p) +check_tzinfo_subclass(datetime_state *st, PyObject *p) { - datetime_state *st = GLOBAL_STATE(); if (p == Py_None || PyTZInfo_Check(st, p)) return 0; PyErr_Format(PyExc_TypeError, @@ -1234,7 +1257,7 @@ get_tzinfo_member(PyObject *self) { PyObject *tzinfo = NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (PyDateTime_Check(st, self) && HASTZINFO(self)) { tzinfo = ((PyDateTime_DateTime *)self)->tzinfo; } @@ -1253,11 +1276,11 @@ get_tzinfo_member(PyObject *self) * this returns NULL. Else result is returned. */ static PyObject * -call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) +call_tzinfo_method(datetime_state *st, PyObject *tzinfo, const char *name, + PyObject *tzinfoarg) { PyObject *offset; - datetime_state *st = GLOBAL_STATE(); assert(tzinfo != NULL); assert(PyTZInfo_Check(st, tzinfo) || tzinfo == Py_None); assert(tzinfoarg != NULL); @@ -1302,7 +1325,8 @@ call_tzinfo_method(PyObject *tzinfo, const char *name, PyObject *tzinfoarg) static PyObject * call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg) { - return call_tzinfo_method(tzinfo, "utcoffset", tzinfoarg); + datetime_state *st = find_module_state_by_def(Py_TYPE(tzinfo)); + return call_tzinfo_method(st, tzinfo, "utcoffset", tzinfoarg); } /* Call tzinfo.dst(tzinfoarg), and extract an integer from the @@ -1316,7 +1340,8 @@ call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg) static PyObject * call_dst(PyObject *tzinfo, PyObject *tzinfoarg) { - return call_tzinfo_method(tzinfo, "dst", tzinfoarg); + datetime_state *st = find_module_state_by_def(Py_TYPE(tzinfo)); + return call_tzinfo_method(st, tzinfo, "dst", tzinfoarg); } /* Call tzinfo.tzname(tzinfoarg), and return the result. tzinfo must be @@ -1328,9 +1353,10 @@ call_dst(PyObject *tzinfo, PyObject *tzinfoarg) static PyObject * call_tzname(PyObject *tzinfo, PyObject *tzinfoarg) { + datetime_state *st = find_module_state_by_def(Py_TYPE(tzinfo)); PyObject *result; assert(tzinfo != NULL); - assert(check_tzinfo_subclass(tzinfo) >= 0); + assert(check_tzinfo_subclass(st, tzinfo) >= 0); assert(tzinfoarg != NULL); if (tzinfo == Py_None) @@ -1401,12 +1427,11 @@ append_keyword_fold(PyObject *repr, int fold) } static inline PyObject * -tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) +tzinfo_from_isoformat_results(datetime_state *st, int rv, int tzoffset, + int tz_useconds) { PyObject *tzinfo; if (rv == 1) { - datetime_state *st = GLOBAL_STATE(); - // Create a timezone from offset in seconds (0 returns UTC) if (tzoffset == 0) { return Py_NewRef(st->PyDateTime_TimeZone_UTC); @@ -1576,7 +1601,7 @@ make_Zreplacement(PyObject *object, PyObject *tzinfoarg) static PyObject * make_freplacement(PyObject *object) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(object)); char freplacement[64]; if (PyTime_Check(st, object)) { sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object)); @@ -1855,7 +1880,7 @@ delta_to_microseconds(PyDateTime_Delta *self) x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) goto Done; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */ if (x2 == NULL) goto Done; @@ -1999,7 +2024,7 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) if (pyus_out == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; @@ -2056,7 +2081,7 @@ multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, if (pyus_out == NULL) goto error; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); error: @@ -2082,7 +2107,7 @@ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) if (pyus_out == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; @@ -2147,7 +2172,7 @@ truedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i) if (pyus_out == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); @@ -2158,7 +2183,7 @@ static PyObject * delta_add(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta + delta */ @@ -2180,7 +2205,7 @@ delta_add(PyObject *left, PyObject *right) static PyObject * delta_negative(PyDateTime_Delta *self) { - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = find_module_state_by_def(Py_TYPE(self)); return new_delta(state, -GET_TD_DAYS(self), -GET_TD_SECONDS(self), @@ -2194,7 +2219,7 @@ delta_positive(PyDateTime_Delta *self) /* Could optimize this (by returning self) if this isn't a * subclass -- but who uses unary + ? Approximately nobody. */ - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = find_module_state_by_def(Py_TYPE(self)); return new_delta(state, GET_TD_DAYS(self), GET_TD_SECONDS(self), @@ -2222,7 +2247,7 @@ static PyObject * delta_subtract(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta - delta */ @@ -2257,7 +2282,7 @@ delta_cmp(PyObject *self, PyObject *other) static PyObject * delta_richcompare(PyObject *self, PyObject *other, int op) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (PyDelta_Check(st, other)) { int diff = delta_cmp(self, other); return diff_to_bool(diff, op); @@ -2286,7 +2311,7 @@ static PyObject * delta_multiply(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDelta_Check(st, left)) { /* delta * ??? */ @@ -2313,7 +2338,7 @@ static PyObject * delta_divide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDelta_Check(st, left)) { /* delta * ??? */ @@ -2336,7 +2361,7 @@ static PyObject * delta_truedivide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDelta_Check(st, left)) { if (PyDelta_Check(st, right)) @@ -2363,7 +2388,7 @@ delta_remainder(PyObject *left, PyObject *right) PyObject *pyus_right; PyObject *pyus_remainder; PyObject *remainder; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; @@ -2400,7 +2425,7 @@ delta_divmod(PyObject *left, PyObject *right) PyObject *divmod; PyObject *delta; PyObject *result; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; @@ -2565,7 +2590,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) y = accum("microseconds", x, us, _PyLong_GetOne(), &leftover_us); CLEANUP; } - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(type); if (ms) { y = accum("milliseconds", x, ms, st->us_per_ms, &leftover_us); CLEANUP; @@ -2742,7 +2767,7 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) if (total_microseconds == NULL) return NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second); Py_DECREF(total_microseconds); @@ -3155,7 +3180,7 @@ add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) static PyObject * date_add(PyObject *left, PyObject *right) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; @@ -3183,7 +3208,7 @@ date_add(PyObject *left, PyObject *right) static PyObject * date_subtract(PyObject *left, PyObject *right) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; @@ -3461,7 +3486,7 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) week = 0; } - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); PyObject* v = iso_calendar_date_new_impl(st->PyDateTime_IsoCalendarDateType, year, week + 1, day + 1); if (v == NULL) { @@ -3475,7 +3500,7 @@ date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) static PyObject * date_richcompare(PyObject *self, PyObject *other, int op) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (PyDate_Check(st, other)) { int diff = memcmp(((PyDateTime_Date *)self)->data, ((PyDateTime_Date *)other)->data, @@ -3741,7 +3766,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) PyObject *off = NULL, *dst = NULL; PyDateTime_Delta *delta = NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); @@ -3907,7 +3932,7 @@ timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw) { PyObject *offset; PyObject *name = NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(type); if (PyArg_ParseTupleAndKeywords(args, kw, "O!|U:timezone", timezone_kws, st->PyDateTime_DeltaType, &offset, &name)) return new_timezone(offset, name); @@ -3948,7 +3973,7 @@ timezone_richcompare(PyDateTime_TimeZone *self, { if (op != Py_EQ && op != Py_NE) Py_RETURN_NOTIMPLEMENTED; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (!PyTimezone_Check(st, other)) { Py_RETURN_NOTIMPLEMENTED; } @@ -3966,9 +3991,8 @@ timezone_hash(PyDateTime_TimeZone *self) otherwise. */ static int -_timezone_check_argument(PyObject *dt, const char *meth) +_timezone_check_argument(datetime_state *st, PyObject *dt, const char *meth) { - datetime_state *st = GLOBAL_STATE(); if (dt == Py_None || PyDateTime_Check(st, dt)) return 0; PyErr_Format(PyExc_TypeError, "%s(dt) argument must be a datetime instance" @@ -3983,7 +4007,7 @@ timezone_repr(PyDateTime_TimeZone *self) to use Py_TYPE(self)->tp_name here. */ const char *type_name = Py_TYPE(self)->tp_name; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (((PyObject *)self) == st->PyDateTime_TimeZone_UTC) return PyUnicode_FromFormat("%s.utc", type_name); @@ -4005,7 +4029,7 @@ timezone_str(PyDateTime_TimeZone *self) if (self->name != NULL) { return Py_NewRef(self->name); } - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if ((PyObject *)self == st->PyDateTime_TimeZone_UTC || (GET_TD_DAYS(self->offset) == 0 && GET_TD_SECONDS(self->offset) == 0 && @@ -4043,8 +4067,10 @@ timezone_str(PyDateTime_TimeZone *self) static PyObject * timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt) { - if (_timezone_check_argument(dt, "tzname") == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (_timezone_check_argument(st, dt, "tzname") == -1) { return NULL; + } return timezone_str(self); } @@ -4052,8 +4078,10 @@ timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt) static PyObject * timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt) { - if (_timezone_check_argument(dt, "utcoffset") == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (_timezone_check_argument(st, dt, "utcoffset") == -1) { return NULL; + } return Py_NewRef(self->offset); } @@ -4061,8 +4089,10 @@ timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt) static PyObject * timezone_dst(PyObject *self, PyObject *dt) { - if (_timezone_check_argument(dt, "dst") == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (_timezone_check_argument(st, dt, "dst") == -1) { return NULL; + } Py_RETURN_NONE; } @@ -4070,7 +4100,7 @@ timezone_dst(PyObject *self, PyObject *dt) static PyObject * timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (!PyDateTime_Check(st, dt)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); @@ -4204,10 +4234,11 @@ static char *time_kws[] = {"hour", "minute", "second", "microsecond", static PyObject * time_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) { + datetime_state *st = find_module_state_by_def(type); PyDateTime_Time *me; char aware = (char)(tzinfo != Py_None); - if (aware && check_tzinfo_subclass(tzinfo) < 0) { + if (aware && check_tzinfo_subclass(st, tzinfo) < 0) { PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg"); return NULL; } @@ -4484,7 +4515,7 @@ time_richcompare(PyObject *self, PyObject *other, int op) PyObject *offset1, *offset2; int diff; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (!PyTime_Check(st, other)) { Py_RETURN_NOTIMPLEMENTED; } @@ -4587,7 +4618,7 @@ time_hash(PyDateTime_Time *self) TIME_GET_SECOND(self); microseconds = TIME_GET_MICROSECOND(self); - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); temp1 = new_delta(st, 0, seconds, microseconds, 1); if (temp1 == NULL) { Py_DECREF(offset); @@ -4673,14 +4704,14 @@ time_fromisoformat(PyObject *cls, PyObject *tstr) { goto invalid_string_error; } - PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, + datetime_state *st = find_module_state_by_def(cls); + PyObject *tzinfo = tzinfo_from_isoformat_results(st, rv, tzoffset, tzimicrosecond); if (tzinfo == NULL) { return NULL; } - datetime_state *st = GLOBAL_STATE(); PyObject *t; if ( (PyTypeObject *)cls == st->PyDateTime_TimeType ) { t = new_time(st, hour, minute, second, microsecond, tzinfo, 0); @@ -4881,10 +4912,11 @@ static char *datetime_kws[] = { static PyObject * datetime_from_pickle(PyTypeObject *type, PyObject *state, PyObject *tzinfo) { + datetime_state *st = find_module_state_by_def(type); PyDateTime_DateTime *me; char aware = (char)(tzinfo != Py_None); - if (aware && check_tzinfo_subclass(tzinfo) < 0) { + if (aware && check_tzinfo_subclass(st, tzinfo) < 0) { PyErr_SetString(PyExc_TypeError, "bad tzinfo state arg"); return NULL; } @@ -5151,7 +5183,8 @@ datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) /* Return best possible local time -- this isn't constrained by the * precision of a timestamp. */ - if (check_tzinfo_subclass(tz) < 0) + datetime_state *st = find_module_state_by_def(type); + if (check_tzinfo_subclass(st, tz) < 0) return NULL; self = datetime_best_possible((PyObject *)type, @@ -5188,7 +5221,8 @@ datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) if (! PyArg_ParseTupleAndKeywords(args, kw, "O|O:fromtimestamp", keywords, ×tamp, &tzinfo)) return NULL; - if (check_tzinfo_subclass(tzinfo) < 0) + datetime_state *st = find_module_state_by_def(cls); + if (check_tzinfo_subclass(st, tzinfo) < 0) return NULL; self = datetime_from_timestamp(cls, @@ -5247,7 +5281,7 @@ datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) PyObject *tzinfo = NULL; PyObject *result = NULL; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(cls); if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!|O:combine", keywords, st->PyDateTime_DateType, &date, st->PyDateTime_TimeType, &time, &tzinfo)) { @@ -5501,7 +5535,8 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) goto invalid_string_error; } - PyObject *tzinfo = tzinfo_from_isoformat_results(rv, tzoffset, tzusec); + datetime_state *st = find_module_state_by_def(cls); + PyObject *tzinfo = tzinfo_from_isoformat_results(st, rv, tzoffset, tzusec); if (tzinfo == NULL) { goto error; } @@ -5608,7 +5643,7 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, static PyObject * datetime_add(PyObject *left, PyObject *right) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDateTime_Check(st, left)) { /* datetime + ??? */ if (PyDelta_Check(st, right)) @@ -5631,7 +5666,7 @@ static PyObject * datetime_subtract(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(left)); if (PyDateTime_Check(st, left)) { /* datetime - ??? */ if (PyDateTime_Check(st, right)) { @@ -5913,7 +5948,7 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) PyObject *result = NULL; PyObject *offset1, *offset2; int diff; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); if (! PyDateTime_Check(st, other)) { if (PyDate_Check(st, other)) { /* Prevent invocation of date_richcompare. We want to @@ -6045,7 +6080,7 @@ datetime_hash(PyDateTime_DateTime *self) DATE_GET_MINUTE(self) * 60 + DATE_GET_SECOND(self); - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); temp1 = new_delta(st, days, seconds, DATE_GET_MICROSECOND(self), 1); @@ -6104,7 +6139,7 @@ datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } static PyObject * -local_timezone_from_timestamp(time_t timestamp) +local_timezone_from_timestamp(datetime_state *state, time_t timestamp) { PyObject *result = NULL; PyObject *delta; @@ -6115,7 +6150,6 @@ local_timezone_from_timestamp(time_t timestamp) if (_PyTime_localtime(timestamp, &local_time_tm) != 0) return NULL; - datetime_state *state = GLOBAL_STATE(); #ifdef HAVE_STRUCT_TM_TM_ZONE zone = local_time_tm.tm_zone; delta = new_delta(state, 0, local_time_tm.tm_gmtoff, 0, 1); @@ -6177,7 +6211,7 @@ local_timezone(PyDateTime_DateTime *utc_time) PyObject *one_second; PyObject *seconds; - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(utc_time)); delta = datetime_subtract((PyObject *)utc_time, st->PyDateTime_Epoch); if (delta == NULL) return NULL; @@ -6196,7 +6230,7 @@ local_timezone(PyDateTime_DateTime *utc_time) Py_DECREF(seconds); if (timestamp == -1 && PyErr_Occurred()) return NULL; - return local_timezone_from_timestamp(timestamp); + return local_timezone_from_timestamp(st, timestamp); } static long long @@ -6217,9 +6251,11 @@ local_timezone_from_local(PyDateTime_DateTime *local_dt) DATE_GET_FOLD(local_dt)); if (seconds == -1) return NULL; + + datetime_state *st = find_module_state_by_def(Py_TYPE(local_dt)); /* XXX: add bounds check */ timestamp = seconds - epoch; - return local_timezone_from_timestamp(timestamp); + return local_timezone_from_timestamp(st, timestamp); } static PyDateTime_DateTime * @@ -6236,7 +6272,8 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) &tzinfo)) return NULL; - if (check_tzinfo_subclass(tzinfo) == -1) + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (check_tzinfo_subclass(st, tzinfo) == -1) return NULL; if (!HASTZINFO(self) || self->tzinfo == Py_None) { @@ -6254,7 +6291,6 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) return (PyDateTime_DateTime*)Py_NewRef(self); } - datetime_state *st = GLOBAL_STATE(); /* Convert self to UTC. */ offset = call_utcoffset(self_tzinfo, (PyObject *)self); Py_DECREF(self_tzinfo); @@ -6401,7 +6437,7 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); PyObject *delta; delta = datetime_subtract((PyObject *)self, st->PyDateTime_Epoch); if (delta == NULL) @@ -6429,7 +6465,7 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = find_module_state_by_def(Py_TYPE(self)); return new_date(state, GET_YEAR(self), GET_MONTH(self), @@ -6439,7 +6475,7 @@ datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = find_module_state_by_def(Py_TYPE(self)); return new_time(state, DATE_GET_HOUR(self), DATE_GET_MINUTE(self), @@ -6452,7 +6488,7 @@ datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) static PyObject * datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) { - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = find_module_state_by_def(Py_TYPE(self)); return new_time(state, DATE_GET_HOUR(self), DATE_GET_MINUTE(self), @@ -6719,7 +6755,7 @@ datetime_destructor(PyObject *op) static int _datetime_exec(PyObject *module) { - datetime_state *st = GLOBAL_STATE(); + datetime_state *st = get_module_state(module); #define ADD_TYPE(mod, var, spec, base) \ do { \ @@ -6793,7 +6829,7 @@ _datetime_exec(PyObject *module) return -1; } - PyObject *x = create_timezone(delta, NULL); + PyObject *x = create_timezone(st, delta, NULL); Py_DECREF(delta); if (x == NULL) { return -1; @@ -6813,7 +6849,7 @@ _datetime_exec(PyObject *module) return -1; } - x = create_timezone(delta, NULL); + x = create_timezone(st, delta, NULL); Py_DECREF(delta); DATETIME_ADD_MACRO(d, "min", x); @@ -6822,7 +6858,7 @@ _datetime_exec(PyObject *module) return -1; } - x = create_timezone(delta, NULL); + x = create_timezone(st, delta, NULL); Py_DECREF(delta); DATETIME_ADD_MACRO(d, "max", x); @@ -6904,7 +6940,7 @@ _datetime_exec(PyObject *module) static int module_traverse(PyObject *module, visitproc visit, void *arg) { - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = get_module_state(module); Py_VISIT(state->us_per_ms); Py_VISIT(state->us_per_second); Py_VISIT(state->us_per_minute); @@ -6927,7 +6963,7 @@ module_traverse(PyObject *module, visitproc visit, void *arg) static int module_clear(PyObject *module) { - datetime_state *state = GLOBAL_STATE(); + datetime_state *state = get_module_state(module); Py_CLEAR(state->us_per_ms); Py_CLEAR(state->us_per_second); Py_CLEAR(state->us_per_minute); From d392c1a891d2bb657845a68a6afe1ae2bd575b43 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 25 Feb 2023 22:44:58 +0100 Subject: [PATCH 17/30] Fix binary ops --- Modules/_datetimemodule.c | 192 ++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 80 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 1ab6b114601c98..8801b4bb77cddc 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -82,6 +82,18 @@ find_module_state_by_def(PyTypeObject *type) return get_module_state(mod); } +static inline datetime_state * +find_state_left_or_right(PyObject *left, PyObject *right) +{ + PyObject *mod = PyType_GetModuleByDef(Py_TYPE(left), &datetimemodule); + if (mod == NULL) { + PyErr_Clear(); + mod = PyType_GetModuleByDef(Py_TYPE(right), &datetimemodule); + } + assert(mod != NULL); + return get_module_state(mod); +} + #define find_module_state_by_def(obj) find_module_state_by_def((PyTypeObject *)(obj)) /*[clinic input] @@ -1323,9 +1335,8 @@ call_tzinfo_method(datetime_state *st, PyObject *tzinfo, const char *name, * set to 0 and the offset is returned (as timedelta, positive east of UTC). */ static PyObject * -call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg) +call_utcoffset(datetime_state *st, PyObject *tzinfo, PyObject *tzinfoarg) { - datetime_state *st = find_module_state_by_def(Py_TYPE(tzinfo)); return call_tzinfo_method(st, tzinfo, "utcoffset", tzinfoarg); } @@ -1338,9 +1349,8 @@ call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg) * the offset is returned (as timedelta, positive east of UTC). */ static PyObject * -call_dst(PyObject *tzinfo, PyObject *tzinfoarg) +call_dst(datetime_state *st, PyObject *tzinfo, PyObject *tzinfoarg) { - datetime_state *st = find_module_state_by_def(Py_TYPE(tzinfo)); return call_tzinfo_method(st, tzinfo, "dst", tzinfoarg); } @@ -1351,9 +1361,8 @@ call_dst(PyObject *tzinfo, PyObject *tzinfoarg) * string. */ static PyObject * -call_tzname(PyObject *tzinfo, PyObject *tzinfoarg) +call_tzname(datetime_state *st, PyObject *tzinfo, PyObject *tzinfoarg) { - datetime_state *st = find_module_state_by_def(Py_TYPE(tzinfo)); PyObject *result; assert(tzinfo != NULL); assert(check_tzinfo_subclass(st, tzinfo) >= 0); @@ -1487,7 +1496,7 @@ static PyObject *delta_negative(PyDateTime_Delta *self); * bogus, an appropriate exception is set and -1 is returned. */ static int -format_utcoffset(char *buf, size_t buflen, const char *sep, +format_utcoffset(datetime_state *st, char *buf, size_t buflen, const char *sep, PyObject *tzinfo, PyObject *tzinfoarg) { PyObject *offset; @@ -1496,7 +1505,7 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, assert(buflen >= 1); - offset = call_utcoffset(tzinfo, tzinfoarg); + offset = call_utcoffset(st, tzinfo, tzinfoarg); if (offset == NULL) return -1; if (offset == Py_None) { @@ -1535,7 +1544,8 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, } static PyObject * -make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) +make_somezreplacement(datetime_state *st, PyObject *object, char *sep, + PyObject *tzinfoarg) { char buf[100]; PyObject *tzinfo = get_tzinfo_member(object); @@ -1545,7 +1555,7 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) } assert(tzinfoarg != NULL); - if (format_utcoffset(buf, + if (format_utcoffset(st, buf, sizeof(buf), sep, tzinfo, @@ -1556,7 +1566,8 @@ make_somezreplacement(PyObject *object, char *sep, PyObject *tzinfoarg) } static PyObject * -make_Zreplacement(PyObject *object, PyObject *tzinfoarg) +make_Zreplacement(datetime_state *st, PyObject *object, + PyObject *tzinfoarg) { PyObject *temp; PyObject *tzinfo = get_tzinfo_member(object); @@ -1568,7 +1579,7 @@ make_Zreplacement(PyObject *object, PyObject *tzinfoarg) return Zreplacement; assert(tzinfoarg != NULL); - temp = call_tzname(tzinfo, tzinfoarg); + temp = call_tzname(st, tzinfo, tzinfoarg); if (temp == NULL) goto Error; if (temp == Py_None) { @@ -1687,7 +1698,8 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == 'z') { /* %z -> +HHMM */ if (zreplacement == NULL) { - zreplacement = make_somezreplacement(object, "", tzinfoarg); + datetime_state *st = find_module_state_by_def(Py_TYPE(object)); + zreplacement = make_somezreplacement(st, object, "", tzinfoarg); if (zreplacement == NULL) goto Done; } @@ -1699,7 +1711,8 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == ':' && *pin == 'z' && pin++) { /* %:z -> +HH:MM */ if (colonzreplacement == NULL) { - colonzreplacement = make_somezreplacement(object, ":", tzinfoarg); + datetime_state *st = find_module_state_by_def(Py_TYPE(object)); + colonzreplacement = make_somezreplacement(st, object, ":", tzinfoarg); if (colonzreplacement == NULL) goto Done; } @@ -1711,7 +1724,8 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, else if (ch == 'Z') { /* format tzname */ if (Zreplacement == NULL) { - Zreplacement = make_Zreplacement(object, + datetime_state *st = find_module_state_by_def(Py_TYPE(object)); + Zreplacement = make_Zreplacement(st, object, tzinfoarg); if (Zreplacement == NULL) goto Done; @@ -1870,7 +1884,7 @@ cmperror(PyObject *a, PyObject *b) * due to ubiquitous overflow possibilities. */ static PyObject * -delta_to_microseconds(PyDateTime_Delta *self) +delta_to_microseconds(datetime_state *st, PyDateTime_Delta *self) { PyObject *x1 = NULL; PyObject *x2 = NULL; @@ -1880,7 +1894,6 @@ delta_to_microseconds(PyDateTime_Delta *self) x1 = PyLong_FromLong(GET_TD_DAYS(self)); if (x1 == NULL) goto Done; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); x2 = PyNumber_Multiply(x1, st->seconds_per_day); /* days in seconds */ if (x2 == NULL) goto Done; @@ -2009,13 +2022,14 @@ microseconds_to_delta_ex(datetime_state *st, PyObject *pyus, microseconds_to_delta_ex(st, pymicros, (st)->PyDateTime_DeltaType) static PyObject * -multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) +multiply_int_timedelta(datetime_state *st, PyObject *intobj, + PyDateTime_Delta *delta) { PyObject *pyus_in; PyObject *pyus_out; PyObject *result; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; @@ -2024,7 +2038,6 @@ multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) if (pyus_out == NULL) return NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; @@ -2059,13 +2072,15 @@ get_float_as_integer_ratio(PyObject *floatobj) /* op is 0 for multiplication, 1 for division */ static PyObject * -multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, int op) +multiply_truedivide_timedelta_float(datetime_state *st, + PyDateTime_Delta *delta, + PyObject *floatobj, int op) { PyObject *result = NULL; PyObject *pyus_in = NULL, *temp, *pyus_out; PyObject *ratio = NULL; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; ratio = get_float_as_integer_ratio(floatobj); @@ -2081,7 +2096,6 @@ multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, if (pyus_out == NULL) goto error; - datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); error: @@ -2092,13 +2106,14 @@ multiply_truedivide_timedelta_float(PyDateTime_Delta *delta, PyObject *floatobj, } static PyObject * -divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) +divide_timedelta_int(datetime_state *st, PyDateTime_Delta *delta, + PyObject *intobj) { PyObject *pyus_in; PyObject *pyus_out; PyObject *result; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; @@ -2107,24 +2122,24 @@ divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) if (pyus_out == NULL) return NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); return result; } static PyObject * -divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) +divide_timedelta_timedelta(datetime_state *st, PyDateTime_Delta *left, + PyDateTime_Delta *right) { PyObject *pyus_left; PyObject *pyus_right; PyObject *result; - pyus_left = delta_to_microseconds(left); + pyus_left = delta_to_microseconds(st, left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds(right); + pyus_right = delta_to_microseconds(st, right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2137,17 +2152,18 @@ divide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) } static PyObject * -truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) +truedivide_timedelta_timedelta(datetime_state *st, PyDateTime_Delta *left, + PyDateTime_Delta *right) { PyObject *pyus_left; PyObject *pyus_right; PyObject *result; - pyus_left = delta_to_microseconds(left); + pyus_left = delta_to_microseconds(st, left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds(right); + pyus_right = delta_to_microseconds(st, right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2160,11 +2176,12 @@ truedivide_timedelta_timedelta(PyDateTime_Delta *left, PyDateTime_Delta *right) } static PyObject * -truedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i) +truedivide_timedelta_int(datetime_state *st, PyDateTime_Delta *delta, + PyObject *i) { PyObject *result; PyObject *pyus_in, *pyus_out; - pyus_in = delta_to_microseconds(delta); + pyus_in = delta_to_microseconds(st, delta); if (pyus_in == NULL) return NULL; pyus_out = divide_nearest(pyus_in, i); @@ -2172,7 +2189,6 @@ truedivide_timedelta_int(PyDateTime_Delta *delta, PyObject *i) if (pyus_out == NULL) return NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(delta)); result = microseconds_to_delta(st, pyus_out); Py_DECREF(pyus_out); @@ -2183,7 +2199,7 @@ static PyObject * delta_add(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta + delta */ @@ -2247,7 +2263,7 @@ static PyObject * delta_subtract(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDelta_Check(st, left) && PyDelta_Check(st, right)) { /* delta - delta */ @@ -2311,23 +2327,23 @@ static PyObject * delta_multiply(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDelta_Check(st, left)) { /* delta * ??? */ if (PyLong_Check(right)) - result = multiply_int_timedelta(right, + result = multiply_int_timedelta(st, right, (PyDateTime_Delta *) left); else if (PyFloat_Check(right)) result = multiply_truedivide_timedelta_float( - (PyDateTime_Delta *) left, right, 0); + st, (PyDateTime_Delta *) left, right, 0); } else if (PyLong_Check(left)) - result = multiply_int_timedelta(left, + result = multiply_int_timedelta(st, left, (PyDateTime_Delta *) right); else if (PyFloat_Check(left)) result = multiply_truedivide_timedelta_float( - (PyDateTime_Delta *) right, left, 0); + st, (PyDateTime_Delta *) right, left, 0); if (result == Py_NotImplemented) Py_INCREF(result); @@ -2338,16 +2354,16 @@ static PyObject * delta_divide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDelta_Check(st, left)) { /* delta * ??? */ if (PyLong_Check(right)) - result = divide_timedelta_int( + result = divide_timedelta_int(st, (PyDateTime_Delta *)left, right); else if (PyDelta_Check(st, right)) - result = divide_timedelta_timedelta( + result = divide_timedelta_timedelta(st, (PyDateTime_Delta *)left, (PyDateTime_Delta *)right); } @@ -2361,18 +2377,18 @@ static PyObject * delta_truedivide(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDelta_Check(st, left)) { if (PyDelta_Check(st, right)) - result = truedivide_timedelta_timedelta( + result = truedivide_timedelta_timedelta(st, (PyDateTime_Delta *)left, (PyDateTime_Delta *)right); else if (PyFloat_Check(right)) result = multiply_truedivide_timedelta_float( - (PyDateTime_Delta *)left, right, 1); + st, (PyDateTime_Delta *)left, right, 1); else if (PyLong_Check(right)) - result = truedivide_timedelta_int( + result = truedivide_timedelta_int(st, (PyDateTime_Delta *)left, right); } @@ -2393,11 +2409,11 @@ delta_remainder(PyObject *left, PyObject *right) if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - pyus_left = delta_to_microseconds((PyDateTime_Delta *)left); + pyus_left = delta_to_microseconds(st, (PyDateTime_Delta *)left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds((PyDateTime_Delta *)right); + pyus_right = delta_to_microseconds(st, (PyDateTime_Delta *)right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2430,11 +2446,11 @@ delta_divmod(PyObject *left, PyObject *right) if (!PyDelta_Check(st, left) || !PyDelta_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; - pyus_left = delta_to_microseconds((PyDateTime_Delta *)left); + pyus_left = delta_to_microseconds(st, (PyDateTime_Delta *)left); if (pyus_left == NULL) return NULL; - pyus_right = delta_to_microseconds((PyDateTime_Delta *)right); + pyus_right = delta_to_microseconds(st, (PyDateTime_Delta *)right); if (pyus_right == NULL) { Py_DECREF(pyus_left); return NULL; @@ -2763,11 +2779,11 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) PyObject *total_seconds; PyObject *total_microseconds; - total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + total_microseconds = delta_to_microseconds(st, (PyDateTime_Delta *)self); if (total_microseconds == NULL) return NULL; - datetime_state *st = find_module_state_by_def(Py_TYPE(self)); total_seconds = PyNumber_TrueDivide(total_microseconds, st->us_per_second); Py_DECREF(total_microseconds); @@ -3180,7 +3196,7 @@ add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) static PyObject * date_add(PyObject *left, PyObject *right) { - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; @@ -3208,7 +3224,7 @@ date_add(PyObject *left, PyObject *right) static PyObject * date_subtract(PyObject *left, PyObject *right) { - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDateTime_Check(st, left) || PyDateTime_Check(st, right)) Py_RETURN_NOTIMPLEMENTED; @@ -3804,7 +3820,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) goto Fail; Py_DECREF(dst); - dst = call_dst(GET_DT_TZINFO(dt), result); + dst = call_dst(st, GET_DT_TZINFO(dt), result); if (dst == NULL) goto Fail; if (dst == Py_None) @@ -4358,18 +4374,24 @@ time_dealloc(PyDateTime_Time *self) /* These are all METH_NOARGS, so don't need to check the arglist. */ static PyObject * -time_utcoffset(PyObject *self, PyObject *unused) { - return call_utcoffset(GET_TIME_TZINFO(self), Py_None); +time_utcoffset(PyObject *self, PyObject *unused) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_utcoffset(st, GET_TIME_TZINFO(self), Py_None); } static PyObject * -time_dst(PyObject *self, PyObject *unused) { - return call_dst(GET_TIME_TZINFO(self), Py_None); +time_dst(PyObject *self, PyObject *unused) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_dst(st, GET_TIME_TZINFO(self), Py_None); } static PyObject * -time_tzname(PyDateTime_Time *self, PyObject *unused) { - return call_tzname(GET_TIME_TZINFO(self), Py_None); +time_tzname(PyDateTime_Time *self, PyObject *unused) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_tzname(st, GET_TIME_TZINFO(self), Py_None); } /* @@ -4464,7 +4486,8 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (format_utcoffset(st, buf, sizeof(buf), ":", self->tzinfo, Py_None) < 0) { Py_DECREF(result); return NULL; @@ -4830,7 +4853,7 @@ static PyType_Slot time_slots[] = { {Py_tp_richcompare, time_richcompare}, {Py_tp_methods, time_methods}, {Py_tp_getset, time_getset}, - {Py_tp_alloc, time_alloc}, + // {Py_tp_alloc, time_alloc}, FIXME {Py_tp_new, time_new}, {0, NULL}, }; @@ -5591,18 +5614,24 @@ datetime_dealloc(PyDateTime_DateTime *self) /* These are all METH_NOARGS, so don't need to check the arglist. */ static PyObject * -datetime_utcoffset(PyObject *self, PyObject *unused) { - return call_utcoffset(GET_DT_TZINFO(self), self); +datetime_utcoffset(PyObject *self, PyObject *unused) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_utcoffset(st, GET_DT_TZINFO(self), self); } static PyObject * -datetime_dst(PyObject *self, PyObject *unused) { - return call_dst(GET_DT_TZINFO(self), self); +datetime_dst(PyObject *self, PyObject *unused) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_dst(st, GET_DT_TZINFO(self), self); } static PyObject * -datetime_tzname(PyObject *self, PyObject *unused) { - return call_tzname(GET_DT_TZINFO(self), self); +datetime_tzname(PyObject *self, PyObject *unused) +{ + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + return call_tzname(st, GET_DT_TZINFO(self), self); } /* @@ -5643,7 +5672,7 @@ add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, static PyObject * datetime_add(PyObject *left, PyObject *right) { - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDateTime_Check(st, left)) { /* datetime + ??? */ if (PyDelta_Check(st, right)) @@ -5666,7 +5695,7 @@ static PyObject * datetime_subtract(PyObject *left, PyObject *right) { PyObject *result = Py_NotImplemented; - datetime_state *st = find_module_state_by_def(Py_TYPE(left)); + datetime_state *st = find_state_left_or_right(left, right); if (PyDateTime_Check(st, left)) { /* datetime - ??? */ if (PyDateTime_Check(st, right)) { @@ -5858,7 +5887,8 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + if (format_utcoffset(st, buffer, sizeof(buffer), ":", self->tzinfo, (PyObject *)self) < 0) { Py_DECREF(result); return NULL; @@ -6220,7 +6250,7 @@ local_timezone(PyDateTime_DateTime *utc_time) Py_DECREF(delta); return NULL; } - seconds = divide_timedelta_timedelta((PyDateTime_Delta *)delta, + seconds = divide_timedelta_timedelta(st, (PyDateTime_Delta *)delta, (PyDateTime_Delta *)one_second); Py_DECREF(one_second); Py_DECREF(delta); @@ -6292,7 +6322,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } /* Convert self to UTC. */ - offset = call_utcoffset(self_tzinfo, (PyObject *)self); + offset = call_utcoffset(st, self_tzinfo, (PyObject *)self); Py_DECREF(self_tzinfo); if (offset == NULL) return NULL; @@ -6364,7 +6394,8 @@ datetime_timetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) if (HASTZINFO(self) && self->tzinfo != Py_None) { PyObject * dst; - dst = call_dst(self->tzinfo, (PyObject *)self); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + dst = call_dst(st, self->tzinfo, (PyObject *)self); if (dst == NULL) return NULL; @@ -6511,7 +6542,8 @@ datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) } else { PyObject *offset; - offset = call_utcoffset(tzinfo, (PyObject *)self); + datetime_state *st = find_module_state_by_def(Py_TYPE(self)); + offset = call_utcoffset(st, tzinfo, (PyObject *)self); if (offset == NULL) return NULL; if (offset == Py_None) { @@ -6686,7 +6718,7 @@ static PyType_Slot datetime_slots[] = { {Py_tp_richcompare, datetime_richcompare}, {Py_tp_methods, datetime_methods}, {Py_tp_getset, datetime_getset}, - {Py_tp_alloc, datetime_alloc}, + //{Py_tp_alloc, datetime_alloc}, FIXME {Py_tp_new, datetime_new}, // Number protocol From 7aaf57f764039c0b7ce025d5c54c954edcc332a9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 25 Feb 2023 22:51:23 +0100 Subject: [PATCH 18/30] Unexpose IsoCalendarType --- Modules/_datetimemodule.c | 44 +++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 8801b4bb77cddc..4232cdce14a1de 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6789,30 +6789,42 @@ _datetime_exec(PyObject *module) { datetime_state *st = get_module_state(module); -#define ADD_TYPE(mod, var, spec, base) \ +#define CREATE_TYPE(mod, var, spec, base) \ do { \ var = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, \ (PyObject *)base); \ if (var == NULL) { \ return -1; \ } \ - if (PyModule_AddType(mod, var) < 0) { \ - return -1; \ - } \ } while (0) - ADD_TYPE(module, st->PyDateTime_TimeType, &time_spec, NULL); - ADD_TYPE(module, st->PyDateTime_TZInfoType, &tzinfo_spec, NULL); - ADD_TYPE(module, st->PyDateTime_TimeZoneType, &timezone_spec, - st->PyDateTime_TZInfoType); - ADD_TYPE(module, st->PyDateTime_IsoCalendarDateType, &isocal_spec, - &PyTuple_Type); - ADD_TYPE(module, st->PyDateTime_DeltaType, &delta_spec, NULL); - ADD_TYPE(module, st->PyDateTime_DateType, &date_spec, NULL); - ADD_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, - st->PyDateTime_DateType); - -#undef ADD_TYPE + CREATE_TYPE(module, st->PyDateTime_TimeType, &time_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_TZInfoType, &tzinfo_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_TimeZoneType, &timezone_spec, + st->PyDateTime_TZInfoType); + CREATE_TYPE(module, st->PyDateTime_IsoCalendarDateType, &isocal_spec, + &PyTuple_Type); + CREATE_TYPE(module, st->PyDateTime_DeltaType, &delta_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_DateType, &date_spec, NULL); + CREATE_TYPE(module, st->PyDateTime_DateTimeType, &datetime_spec, + st->PyDateTime_DateType); + +#undef CREATE_TYPE + + PyTypeObject *types[] = { + st->PyDateTime_DateType, + st->PyDateTime_DateTimeType, + st->PyDateTime_TimeType, + st->PyDateTime_DeltaType, + st->PyDateTime_TZInfoType, + st->PyDateTime_TimeZoneType, + }; + + for (size_t i = 0; i < Py_ARRAY_LENGTH(types); i++) { + if (PyModule_AddType(module, types[i]) < 0) { + return -1; + } + } #define DATETIME_ADD_MACRO(dict, c, value_expr) \ do { \ From 206cdcc596252e8fb85b0e198d5531e55e6cce1d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Sat, 25 Feb 2023 23:04:46 +0100 Subject: [PATCH 19/30] _PyType_GetModuleState --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 4232cdce14a1de..04062a07d7e70d 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -67,7 +67,7 @@ get_module_state(PyObject *mod) static inline datetime_state * get_module_state_by_cls(PyTypeObject *defining_class) { - void *state = PyType_GetModuleState(defining_class); + void *state = _PyType_GetModuleState(defining_class); assert(state != NULL); return (datetime_state *)state; } From 8c53fa170100436b400eaa668c53af5b60b7ea35 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 24 Mar 2023 10:20:15 +0100 Subject: [PATCH 20/30] Remove time/datetime memory optimisation --- Modules/_datetimemodule.c | 47 --------------------------------------- 1 file changed, 47 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 04062a07d7e70d..cee1c11d17a6a0 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -692,51 +692,6 @@ normalize_datetime(int *year, int *month, int *day, return normalize_date(year, month, day); } -/* --------------------------------------------------------------------------- - * Basic object allocation: tp_alloc implementations. These allocate - * Python objects of the right size and type, and do the Python object- - * initialization bit. If there's not enough memory, they return NULL after - * setting MemoryError. All data members remain uninitialized trash. - * - * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo - * member is needed. This is ugly, imprecise, and possibly insecure. - * tp_basicsize for the time and datetime types is set to the size of the - * struct that has room for the tzinfo member, so subclasses in Python will - * allocate enough space for a tzinfo member whether or not one is actually - * needed. That's the "ugly and imprecise" parts. The "possibly insecure" - * part is that PyType_GenericAlloc() (which subclasses in Python end up - * using) just happens today to effectively ignore the nitems argument - * when tp_itemsize is 0, which it is for these type objects. If that - * changes, perhaps the callers of tp_alloc slots in this file should - * be changed to force a 0 nitems argument unless the type being allocated - * is a base type implemented in this file (so that tp_alloc is time_alloc - * or datetime_alloc below, which know about the nitems abuse). - */ - -static PyObject * -time_alloc(PyTypeObject *type, Py_ssize_t aware) -{ - size_t size = aware ? sizeof(PyDateTime_Time) : sizeof(_PyDateTime_BaseTime); - PyObject *self = (PyObject *)PyObject_Malloc(size); - if (self == NULL) { - return PyErr_NoMemory(); - } - _PyObject_Init(self, type); - return self; -} - -static PyObject * -datetime_alloc(PyTypeObject *type, Py_ssize_t aware) -{ - size_t size = aware ? sizeof(PyDateTime_DateTime) : sizeof(_PyDateTime_BaseDateTime); - PyObject *self = (PyObject *)PyObject_Malloc(size); - if (self == NULL) { - return PyErr_NoMemory(); - } - _PyObject_Init(self, type); - return self; -} - /* --------------------------------------------------------------------------- * Helpers for setting object fields. These work on pointers to the * appropriate base class. @@ -4853,7 +4808,6 @@ static PyType_Slot time_slots[] = { {Py_tp_richcompare, time_richcompare}, {Py_tp_methods, time_methods}, {Py_tp_getset, time_getset}, - // {Py_tp_alloc, time_alloc}, FIXME {Py_tp_new, time_new}, {0, NULL}, }; @@ -6718,7 +6672,6 @@ static PyType_Slot datetime_slots[] = { {Py_tp_richcompare, datetime_richcompare}, {Py_tp_methods, datetime_methods}, {Py_tp_getset, datetime_getset}, - //{Py_tp_alloc, datetime_alloc}, FIXME {Py_tp_new, datetime_new}, // Number protocol From b583954c6dfedcb7bf69896174f15d889eb4e75a Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 24 Mar 2023 10:20:50 +0100 Subject: [PATCH 21/30] Remove unused get_module_state_by_cls() helper --- Modules/_datetimemodule.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index cee1c11d17a6a0..31e2849d74a6d5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -64,14 +64,6 @@ get_module_state(PyObject *mod) return (datetime_state *)state; } -static inline datetime_state * -get_module_state_by_cls(PyTypeObject *defining_class) -{ - void *state = _PyType_GetModuleState(defining_class); - assert(state != NULL); - return (datetime_state *)state; -} - static struct PyModuleDef datetimemodule; static inline datetime_state * From 32211b893d96c21cb11cd8c5d1c9e58343e33f74 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 24 Mar 2023 10:43:54 +0100 Subject: [PATCH 22/30] Move _strptime import to state --- Modules/_datetimemodule.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 31e2849d74a6d5..ac0608bbd61d68 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -46,6 +46,9 @@ typedef struct { /* The interned Epoch datetime instance */ PyObject *PyDateTime_Epoch; + /* strptime import */ + PyObject *strptime; + /* Types */ PyTypeObject *PyDateTime_DateTimeType; PyTypeObject *PyDateTime_DateType; @@ -5225,19 +5228,21 @@ datetime_utcfromtimestamp(PyObject *cls, PyObject *args) static PyObject * datetime_strptime(PyObject *cls, PyObject *args) { - static PyObject *module = NULL; PyObject *string, *format; if (!PyArg_ParseTuple(args, "UU:strptime", &string, &format)) return NULL; - if (module == NULL) { - module = PyImport_ImportModule("_strptime"); - if (module == NULL) + datetime_state *st = find_module_state_by_def(cls); + if (st->strptime == NULL) { + st->strptime = PyImport_ImportModule("_strptime"); + if (st->strptime == NULL) { return NULL; + } } - return PyObject_CallMethodObjArgs(module, &_Py_ID(_strptime_datetime), - cls, string, format, NULL); + return PyObject_CallMethodObjArgs(st->strptime, + &_Py_ID(_strptime_datetime), + cls, string, format, NULL); } /* Return new datetime from date/datetime and time arguments. */ @@ -6937,6 +6942,7 @@ module_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->us_per_day); Py_VISIT(state->us_per_week); Py_VISIT(state->seconds_per_day); + Py_VISIT(state->strptime); Py_VISIT(state->PyDateTime_TimeZone_UTC); Py_VISIT(state->PyDateTime_Epoch); Py_VISIT(state->PyDateTime_DateTimeType); @@ -6960,6 +6966,7 @@ module_clear(PyObject *module) Py_CLEAR(state->us_per_day); Py_CLEAR(state->us_per_week); Py_CLEAR(state->seconds_per_day); + Py_CLEAR(state->strptime); Py_CLEAR(state->PyDateTime_TimeZone_UTC); Py_CLEAR(state->PyDateTime_Epoch); Py_CLEAR(state->PyDateTime_DateTimeType); From 47862e83b269f2ce8cacd963b422ec1d3b721b3e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 24 Mar 2023 11:10:21 +0100 Subject: [PATCH 23/30] Add NEWS --- .../next/Library/2023-03-24-11-10-16.gh-issue-71587.q4ueXs.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-71587.q4ueXs.rst diff --git a/Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-71587.q4ueXs.rst b/Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-71587.q4ueXs.rst new file mode 100644 index 00000000000000..843e44d0b78cb8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-24-11-10-16.gh-issue-71587.q4ueXs.rst @@ -0,0 +1 @@ +Apply :pep:`687` to :mod:`datetime`. Patch by Erlend Aasland. From d97dfb0215ddb9e05c6a1dcca54984ece0628c92 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 11:28:51 +0200 Subject: [PATCH 24/30] Fix merge --- Modules/_datetimemodule.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 11dbcc85af426b..73aeb7aa4602bc 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6969,13 +6969,13 @@ _datetime_exec(PyObject *module) return 0; error: - Py_XDECREF(us_per_ms); - Py_XDECREF(us_per_second); - Py_XDECREF(us_per_minute); - Py_XDECREF(us_per_hour); - Py_XDECREF(us_per_day); - Py_XDECREF(us_per_week); - Py_XDECREF(seconds_per_day); + Py_XDECREF(st->us_per_ms); + Py_XDECREF(st->us_per_second); + Py_XDECREF(st->us_per_minute); + Py_XDECREF(st->us_per_hour); + Py_XDECREF(st->us_per_day); + Py_XDECREF(st->us_per_week); + Py_XDECREF(st->seconds_per_day); return -1; } From f024817ab300834f4f326d2e8a5f07123b58e2a8 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 12:16:18 +0200 Subject: [PATCH 25/30] Apply suggestions from code review Co-authored-by: Victor Stinner --- Modules/_datetimemodule.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 73aeb7aa4602bc..58d70c24c0db1e 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -32,13 +32,13 @@ typedef struct { /* Conversion factors. */ - PyObject *us_per_ms; // 1000 - PyObject *us_per_second; // 1000000 + PyObject *us_per_ms; // 1_000 + PyObject *us_per_second; // 1_000_000 PyObject *us_per_minute; // 1e6 * 60 as Python int PyObject *us_per_hour; // 1e6 * 3600 as Python int PyObject *us_per_day; // 1e6 * 3600 * 24 as Python int - PyObject *us_per_week; // 1e6*3600*24*7 as Python int - PyObject *seconds_per_day; // 3600*24 as Python int + PyObject *us_per_week; // 1e6 * 3600 * 24 * 7 as Python int + PyObject *seconds_per_day; // 3600 * 24 as Python int /* The interned UTC timezone instance */ PyObject *PyDateTime_TimeZone_UTC; @@ -46,7 +46,7 @@ typedef struct { /* The interned Epoch datetime instance */ PyObject *PyDateTime_Epoch; - /* strptime import */ + /* _strptime module */ PyObject *strptime; /* Types */ From c23dd20bfbe53a626f35e2e574e626fa8f321660 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 12:24:44 +0200 Subject: [PATCH 26/30] Address review: remove unused clinic_state() macro --- Modules/_datetimemodule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 58d70c24c0db1e..a123139ad41ce5 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -93,11 +93,12 @@ find_state_left_or_right(PyObject *left, PyObject *right) /*[clinic input] module datetime -class datetime.datetime "PyDateTime_DateTime *" "clinic_state()->PyDateTime_DateTimeType" -class datetime.date "PyDateTime_Date *" "clinic_state()->PyDateTime_DateType" -class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "clinic_state()->PyDateTime_IsoCalendarDateType" +# Note: module state is (currently) unused in clinic. +class datetime.datetime "PyDateTime_DateTime *" "" +class datetime.date "PyDateTime_Date *" "" +class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8a333fc5cbf6a146]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a2651510d22a8c6c]*/ #define clinic_state() (fixme()) #include "clinic/_datetimemodule.c.h" From a30bfdb7d0e18470b9f3f8ffed9a565aae1f7365 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 12:28:28 +0200 Subject: [PATCH 27/30] Improve CREATE_TYPE macro --- Modules/_datetimemodule.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index a123139ad41ce5..16f0f1115f0ca6 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6766,14 +6766,13 @@ _datetime_exec(PyObject *module) { datetime_state *st = get_module_state(module); -#define CREATE_TYPE(mod, var, spec, base) \ - do { \ - var = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, \ - (PyObject *)base); \ - if (var == NULL) { \ - return -1; \ - } \ - } while (0) +#define CREATE_TYPE(MOD, VAR, SPEC, BASE) do { \ + PyObject *tp = PyType_FromModuleAndSpec(MOD, SPEC, (PyObject *)BASE); \ + if (tp == NULL) { \ + return -1; \ + } \ + VAR = (PyTypeObject *)tp; \ +} while (0) CREATE_TYPE(module, st->PyDateTime_TimeType, &time_spec, NULL); CREATE_TYPE(module, st->PyDateTime_TZInfoType, &tzinfo_spec, NULL); From d152b4c14179c67f7bf7ed48387ec09fb43a8aca Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 12:29:27 +0200 Subject: [PATCH 28/30] Address review: Py_CLEAR state --- Modules/_datetimemodule.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 16f0f1115f0ca6..0981bdcf8388fd 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6969,13 +6969,13 @@ _datetime_exec(PyObject *module) return 0; error: - Py_XDECREF(st->us_per_ms); - Py_XDECREF(st->us_per_second); - Py_XDECREF(st->us_per_minute); - Py_XDECREF(st->us_per_hour); - Py_XDECREF(st->us_per_day); - Py_XDECREF(st->us_per_week); - Py_XDECREF(st->seconds_per_day); + Py_CLEAR(st->us_per_ms); + Py_CLEAR(st->us_per_second); + Py_CLEAR(st->us_per_minute); + Py_CLEAR(st->us_per_hour); + Py_CLEAR(st->us_per_day); + Py_CLEAR(st->us_per_week); + Py_CLEAR(st->seconds_per_day); return -1; } From 18b9007a32173f6418a070583f9832a7a811f7ce Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 12:31:13 +0200 Subject: [PATCH 29/30] Address review: visit and clear module state in member order --- Modules/_datetimemodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 0981bdcf8388fd..aad29a07f15191 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6990,9 +6990,9 @@ module_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->us_per_day); Py_VISIT(state->us_per_week); Py_VISIT(state->seconds_per_day); - Py_VISIT(state->strptime); Py_VISIT(state->PyDateTime_TimeZone_UTC); Py_VISIT(state->PyDateTime_Epoch); + Py_VISIT(state->strptime); Py_VISIT(state->PyDateTime_DateTimeType); Py_VISIT(state->PyDateTime_DateType); Py_VISIT(state->PyDateTime_DeltaType); @@ -7014,9 +7014,9 @@ module_clear(PyObject *module) Py_CLEAR(state->us_per_day); Py_CLEAR(state->us_per_week); Py_CLEAR(state->seconds_per_day); - Py_CLEAR(state->strptime); Py_CLEAR(state->PyDateTime_TimeZone_UTC); Py_CLEAR(state->PyDateTime_Epoch); + Py_CLEAR(state->strptime); Py_CLEAR(state->PyDateTime_DateTimeType); Py_CLEAR(state->PyDateTime_DateType); Py_CLEAR(state->PyDateTime_DeltaType); From 0ee2374d27b56c3397d0de1375139ce16275b0ff Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Fri, 6 Oct 2023 13:08:50 +0200 Subject: [PATCH 30/30] Regen clinic --- Modules/_datetimemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index aad29a07f15191..9322132d4d41c4 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -98,7 +98,7 @@ class datetime.datetime "PyDateTime_DateTime *" "" class datetime.date "PyDateTime_Date *" "" class datetime.IsoCalendarDate "PyDateTime_IsoCalendarDate *" "" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a2651510d22a8c6c]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e62dff5ae4ce49eb]*/ #define clinic_state() (fixme()) #include "clinic/_datetimemodule.c.h"