bpo-1635741: Convert _sre types to heap types and establish module state (PEP 384) (GH-23393)

diff --git a/Modules/_sre.c b/Modules/_sre.c
index fbabeb7..0a5ca60 100644
--- a/Modules/_sre.c
+++ b/Modules/_sre.c
@@ -248,22 +248,36 @@ data_stack_grow(SRE_STATE* state, Py_ssize_t size)
 /* -------------------------------------------------------------------- */
 /* factories and destructors */
 
-/* see sre.h for object declarations */
-static PyObject*pattern_new_match(PatternObject*, SRE_STATE*, Py_ssize_t);
-static PyObject *pattern_scanner(PatternObject *, PyObject *, Py_ssize_t, Py_ssize_t);
+/* module state */
+typedef struct {
+    PyTypeObject *Pattern_Type;
+    PyTypeObject *Match_Type;
+    PyTypeObject *Scanner_Type;
+} _sremodulestate;
 
+static _sremodulestate *
+get_sre_module_state(PyObject *m)
+{
+    _sremodulestate *state = (_sremodulestate *)PyModule_GetState(m);
+    assert(state);
+    return state;
+}
+
+static struct PyModuleDef sremodule;
+#define get_sre_module_state_by_class(cls) \
+    (get_sre_module_state(PyType_GetModule(cls)))
+
+/* see sre.h for object declarations */
+static PyObject*pattern_new_match(_sremodulestate *, PatternObject*, SRE_STATE*, Py_ssize_t);
+static PyObject *pattern_scanner(_sremodulestate *, PatternObject *, PyObject *, Py_ssize_t, Py_ssize_t);
 
 /*[clinic input]
 module _sre
-class _sre.SRE_Pattern "PatternObject *" "&Pattern_Type"
-class _sre.SRE_Match "MatchObject *" "&Match_Type"
-class _sre.SRE_Scanner "ScannerObject *" "&Scanner_Type"
+class _sre.SRE_Pattern "PatternObject *" "get_sre_module_state_by_class(tp)->Pattern_Type"
+class _sre.SRE_Match "MatchObject *" "get_sre_module_state_by_class(tp)->Match_Type"
+class _sre.SRE_Scanner "ScannerObject *" "get_sre_module_state_by_class(tp)->Scanner_Type"
 [clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=b0230ec19a0deac8]*/
-
-static PyTypeObject Pattern_Type;
-static PyTypeObject Match_Type;
-static PyTypeObject Scanner_Type;
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=fe2966e32b66a231]*/
 
 /*[clinic input]
 _sre.getcodesize -> int
@@ -550,12 +564,15 @@ pattern_error(Py_ssize_t status)
 static void
 pattern_dealloc(PatternObject* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
+
     if (self->weakreflist != NULL)
         PyObject_ClearWeakRefs((PyObject *) self);
     Py_XDECREF(self->pattern);
     Py_XDECREF(self->groupindex);
     Py_XDECREF(self->indexgroup);
     PyObject_DEL(self);
+    Py_DECREF(tp);
 }
 
 LOCAL(Py_ssize_t)
@@ -583,6 +600,8 @@ sre_search(SRE_STATE* state, SRE_CODE* pattern)
 /*[clinic input]
 _sre.SRE_Pattern.match
 
+    cls: defining_class
+    /
     string: object
     pos: Py_ssize_t = 0
     endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize
@@ -591,10 +610,12 @@ Matches zero or more characters at the beginning of the string.
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_match_impl(PatternObject *self, PyObject *string,
-                            Py_ssize_t pos, Py_ssize_t endpos)
-/*[clinic end generated code: output=ea2d838888510661 input=a2ba191647abebe5]*/
+_sre_SRE_Pattern_match_impl(PatternObject *self, PyTypeObject *cls,
+                            PyObject *string, Py_ssize_t pos,
+                            Py_ssize_t endpos)
+/*[clinic end generated code: output=ec6208ea58a0cca0 input=4bdb9c3e564d13ac]*/
 {
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
     SRE_STATE state;
     Py_ssize_t status;
     PyObject *match;
@@ -614,7 +635,7 @@ _sre_SRE_Pattern_match_impl(PatternObject *self, PyObject *string,
         return NULL;
     }
 
-    match = pattern_new_match(self, &state, status);
+    match = pattern_new_match(module_state, self, &state, status);
     state_fini(&state);
     return match;
 }
@@ -622,6 +643,8 @@ _sre_SRE_Pattern_match_impl(PatternObject *self, PyObject *string,
 /*[clinic input]
 _sre.SRE_Pattern.fullmatch
 
+    cls: defining_class
+    /
     string: object
     pos: Py_ssize_t = 0
     endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize
@@ -630,10 +653,12 @@ Matches against all of the string.
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_fullmatch_impl(PatternObject *self, PyObject *string,
-                                Py_ssize_t pos, Py_ssize_t endpos)
-/*[clinic end generated code: output=5833c47782a35f4a input=d9fb03a7625b5828]*/
+_sre_SRE_Pattern_fullmatch_impl(PatternObject *self, PyTypeObject *cls,
+                                PyObject *string, Py_ssize_t pos,
+                                Py_ssize_t endpos)
+/*[clinic end generated code: output=625b75b027ef94da input=50981172ab0fcfdd]*/
 {
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
     SRE_STATE state;
     Py_ssize_t status;
     PyObject *match;
@@ -654,7 +679,7 @@ _sre_SRE_Pattern_fullmatch_impl(PatternObject *self, PyObject *string,
         return NULL;
     }
 
-    match = pattern_new_match(self, &state, status);
+    match = pattern_new_match(module_state, self, &state, status);
     state_fini(&state);
     return match;
 }
@@ -662,6 +687,8 @@ _sre_SRE_Pattern_fullmatch_impl(PatternObject *self, PyObject *string,
 /*[clinic input]
 _sre.SRE_Pattern.search
 
+    cls: defining_class
+    /
     string: object
     pos: Py_ssize_t = 0
     endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize
@@ -672,10 +699,12 @@ Return None if no position in the string matches.
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_search_impl(PatternObject *self, PyObject *string,
-                             Py_ssize_t pos, Py_ssize_t endpos)
-/*[clinic end generated code: output=25f302a644e951e8 input=4ae5cb7dc38fed1b]*/
+_sre_SRE_Pattern_search_impl(PatternObject *self, PyTypeObject *cls,
+                             PyObject *string, Py_ssize_t pos,
+                             Py_ssize_t endpos)
+/*[clinic end generated code: output=bd7f2d9d583e1463 input=afa9afb66a74a4b3]*/
 {
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
     SRE_STATE state;
     Py_ssize_t status;
     PyObject *match;
@@ -694,7 +723,7 @@ _sre_SRE_Pattern_search_impl(PatternObject *self, PyObject *string,
         return NULL;
     }
 
-    match = pattern_new_match(self, &state, status);
+    match = pattern_new_match(module_state, self, &state, status);
     state_fini(&state);
     return match;
 }
@@ -826,6 +855,8 @@ _sre_SRE_Pattern_findall_impl(PatternObject *self, PyObject *string,
 /*[clinic input]
 _sre.SRE_Pattern.finditer
 
+    cls: defining_class
+    /
     string: object
     pos: Py_ssize_t = 0
     endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize
@@ -836,15 +867,17 @@ For each match, the iterator returns a match object.
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_finditer_impl(PatternObject *self, PyObject *string,
-                               Py_ssize_t pos, Py_ssize_t endpos)
-/*[clinic end generated code: output=0bbb1a0aeb38bb14 input=612aab69e9fe08e4]*/
+_sre_SRE_Pattern_finditer_impl(PatternObject *self, PyTypeObject *cls,
+                               PyObject *string, Py_ssize_t pos,
+                               Py_ssize_t endpos)
+/*[clinic end generated code: output=1791dbf3618ade56 input=812e332a4848cbaf]*/
 {
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
     PyObject* scanner;
     PyObject* search;
     PyObject* iterator;
 
-    scanner = pattern_scanner(self, string, pos, endpos);
+    scanner = pattern_scanner(module_state, self, string, pos, endpos);
     if (!scanner)
         return NULL;
 
@@ -862,6 +895,8 @@ _sre_SRE_Pattern_finditer_impl(PatternObject *self, PyObject *string,
 /*[clinic input]
 _sre.SRE_Pattern.scanner
 
+    cls: defining_class
+    /
     string: object
     pos: Py_ssize_t = 0
     endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize
@@ -869,11 +904,14 @@ _sre.SRE_Pattern.scanner
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_scanner_impl(PatternObject *self, PyObject *string,
-                              Py_ssize_t pos, Py_ssize_t endpos)
-/*[clinic end generated code: output=54ea548aed33890b input=3aacdbde77a3a637]*/
+_sre_SRE_Pattern_scanner_impl(PatternObject *self, PyTypeObject *cls,
+                              PyObject *string, Py_ssize_t pos,
+                              Py_ssize_t endpos)
+/*[clinic end generated code: output=f70cd506112f1bd9 input=2e487e5151bcee4c]*/
 {
-    return pattern_scanner(self, string, pos, endpos);
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
+
+    return pattern_scanner(module_state, self, string, pos, endpos);
 }
 
 /*[clinic input]
@@ -980,8 +1018,12 @@ _sre_SRE_Pattern_split_impl(PatternObject *self, PyObject *string,
 }
 
 static PyObject*
-pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string,
-             Py_ssize_t count, Py_ssize_t subn)
+pattern_subx(_sremodulestate* module_state,
+             PatternObject* self,
+             PyObject* ptemplate,
+             PyObject* string,
+             Py_ssize_t count,
+             Py_ssize_t subn)
 {
     SRE_STATE state;
     PyObject* list;
@@ -1083,7 +1125,7 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string,
 
         if (filter_is_callable) {
             /* pass match object through filter */
-            match = pattern_new_match(self, &state, 1);
+            match = pattern_new_match(module_state, self, &state, 1);
             if (!match)
                 goto error;
             item = PyObject_CallOneArg(filter, match);
@@ -1163,6 +1205,8 @@ pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string,
 /*[clinic input]
 _sre.SRE_Pattern.sub
 
+    cls: defining_class
+    /
     repl: object
     string: object
     count: Py_ssize_t = 0
@@ -1171,16 +1215,20 @@ Return the string obtained by replacing the leftmost non-overlapping occurrences
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_sub_impl(PatternObject *self, PyObject *repl,
-                          PyObject *string, Py_ssize_t count)
-/*[clinic end generated code: output=1dbf2ec3479cba00 input=c53d70be0b3caf86]*/
+_sre_SRE_Pattern_sub_impl(PatternObject *self, PyTypeObject *cls,
+                          PyObject *repl, PyObject *string, Py_ssize_t count)
+/*[clinic end generated code: output=4be141ab04bca60d input=d8d1d4ac2311a07c]*/
 {
-    return pattern_subx(self, repl, string, count, 0);
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
+
+    return pattern_subx(module_state, self, repl, string, count, 0);
 }
 
 /*[clinic input]
 _sre.SRE_Pattern.subn
 
+    cls: defining_class
+    /
     repl: object
     string: object
     count: Py_ssize_t = 0
@@ -1189,11 +1237,14 @@ Return the tuple (new_string, number_of_subs_made) found by replacing the leftmo
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Pattern_subn_impl(PatternObject *self, PyObject *repl,
-                           PyObject *string, Py_ssize_t count)
-/*[clinic end generated code: output=0d9522cd529e9728 input=e7342d7ce6083577]*/
+_sre_SRE_Pattern_subn_impl(PatternObject *self, PyTypeObject *cls,
+                           PyObject *repl, PyObject *string,
+                           Py_ssize_t count)
+/*[clinic end generated code: output=da02fd85258b1e1f input=8b78a65b8302e58d]*/
 {
-    return pattern_subx(self, repl, string, count, 1);
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
+
+    return pattern_subx(module_state, self, repl, string, count, 1);
 }
 
 /*[clinic input]
@@ -1338,12 +1389,13 @@ _sre_compile_impl(PyObject *module, PyObject *pattern, int flags,
 {
     /* "compile" pattern descriptor to pattern object */
 
+    _sremodulestate *module_state = get_sre_module_state(module);
     PatternObject* self;
     Py_ssize_t i, n;
 
     n = PyList_GET_SIZE(code);
     /* coverity[ampersand_in_size] */
-    self = PyObject_NewVar(PatternObject, &Pattern_Type, n);
+    self = PyObject_NewVar(PatternObject, module_state->Pattern_Type, n);
     if (!self)
         return NULL;
     self->weakreflist = NULL;
@@ -1887,10 +1939,13 @@ _validate(PatternObject *self)
 static void
 match_dealloc(MatchObject* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
+
     Py_XDECREF(self->regs);
     Py_XDECREF(self->string);
     Py_DECREF(self->pattern);
     PyObject_DEL(self);
+    Py_DECREF(tp);
 }
 
 static PyObject*
@@ -2319,7 +2374,10 @@ match_repr(MatchObject *self)
 
 
 static PyObject*
-pattern_new_match(PatternObject* pattern, SRE_STATE* state, Py_ssize_t status)
+pattern_new_match(_sremodulestate* module_state,
+                  PatternObject* pattern,
+                  SRE_STATE* state,
+                  Py_ssize_t status)
 {
     /* create match object (from state object) */
 
@@ -2332,7 +2390,8 @@ pattern_new_match(PatternObject* pattern, SRE_STATE* state, Py_ssize_t status)
 
         /* create match object (with room for extra group marks) */
         /* coverity[ampersand_in_size] */
-        match = PyObject_NewVar(MatchObject, &Match_Type,
+        match = PyObject_NewVar(MatchObject,
+                                module_state->Match_Type,
                                 2*(pattern->groups+1));
         if (!match)
             return NULL;
@@ -2387,20 +2446,27 @@ pattern_new_match(PatternObject* pattern, SRE_STATE* state, Py_ssize_t status)
 static void
 scanner_dealloc(ScannerObject* self)
 {
+    PyTypeObject *tp = Py_TYPE(self);
+
     state_fini(&self->state);
     Py_XDECREF(self->pattern);
     PyObject_DEL(self);
+    Py_DECREF(tp);
 }
 
 /*[clinic input]
 _sre.SRE_Scanner.match
 
+    cls: defining_class
+    /
+
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Scanner_match_impl(ScannerObject *self)
-/*[clinic end generated code: output=936b30c63d4b81eb input=881a0154f8c13d9a]*/
+_sre_SRE_Scanner_match_impl(ScannerObject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=6e22c149dc0f0325 input=b5146e1f30278cb7]*/
 {
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
     SRE_STATE* state = &self->state;
     PyObject* match;
     Py_ssize_t status;
@@ -2416,8 +2482,8 @@ _sre_SRE_Scanner_match_impl(ScannerObject *self)
     if (PyErr_Occurred())
         return NULL;
 
-    match = pattern_new_match((PatternObject*) self->pattern,
-                               state, status);
+    match = pattern_new_match(module_state, (PatternObject*) self->pattern,
+                              state, status);
 
     if (status == 0)
         state->start = NULL;
@@ -2433,12 +2499,16 @@ _sre_SRE_Scanner_match_impl(ScannerObject *self)
 /*[clinic input]
 _sre.SRE_Scanner.search
 
+    cls: defining_class
+    /
+
 [clinic start generated code]*/
 
 static PyObject *
-_sre_SRE_Scanner_search_impl(ScannerObject *self)
-/*[clinic end generated code: output=7dc211986088f025 input=161223ee92ef9270]*/
+_sre_SRE_Scanner_search_impl(ScannerObject *self, PyTypeObject *cls)
+/*[clinic end generated code: output=23e8fc78013f9161 input=056c2d37171d0bf2]*/
 {
+    _sremodulestate *module_state = get_sre_module_state_by_class(cls);
     SRE_STATE* state = &self->state;
     PyObject* match;
     Py_ssize_t status;
@@ -2454,8 +2524,8 @@ _sre_SRE_Scanner_search_impl(ScannerObject *self)
     if (PyErr_Occurred())
         return NULL;
 
-    match = pattern_new_match((PatternObject*) self->pattern,
-                               state, status);
+    match = pattern_new_match(module_state, (PatternObject*) self->pattern,
+                              state, status);
 
     if (status == 0)
         state->start = NULL;
@@ -2468,12 +2538,16 @@ _sre_SRE_Scanner_search_impl(ScannerObject *self)
 }
 
 static PyObject *
-pattern_scanner(PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos)
+pattern_scanner(_sremodulestate *module_state,
+                PatternObject *self,
+                PyObject *string,
+                Py_ssize_t pos,
+                Py_ssize_t endpos)
 {
     ScannerObject* scanner;
 
     /* create scanner object */
-    scanner = PyObject_New(ScannerObject, &Scanner_Type);
+    scanner = PyObject_New(ScannerObject, module_state->Scanner_Type);
     if (!scanner)
         return NULL;
     scanner->pattern = NULL;
@@ -2516,6 +2590,8 @@ pattern_hash(PatternObject *self)
 static PyObject*
 pattern_richcompare(PyObject *lefto, PyObject *righto, int op)
 {
+    PyTypeObject *tp = Py_TYPE(lefto);
+    _sremodulestate *module_state = get_sre_module_state_by_class(tp);
     PatternObject *left, *right;
     int cmp;
 
@@ -2523,7 +2599,8 @@ pattern_richcompare(PyObject *lefto, PyObject *righto, int op)
         Py_RETURN_NOTIMPLEMENTED;
     }
 
-    if (!Py_IS_TYPE(lefto, &Pattern_Type) || !Py_IS_TYPE(righto, &Pattern_Type)) {
+    if (!Py_IS_TYPE(righto, module_state->Pattern_Type))
+    {
         Py_RETURN_NOTIMPLEMENTED;
     }
 
@@ -2592,47 +2669,28 @@ static PyMemberDef pattern_members[] = {
      "The regex matching flags."},
     {"groups",     T_PYSSIZET,  PAT_OFF(groups),        READONLY,
      "The number of capturing groups in the pattern."},
+    {"__weaklistoffset__", T_PYSSIZET, offsetof(PatternObject, weakreflist), READONLY},
     {NULL}  /* Sentinel */
 };
 
-static PyTypeObject Pattern_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "re.Pattern",
-    sizeof(PatternObject), sizeof(SRE_CODE),
-    (destructor)pattern_dealloc,        /* tp_dealloc */
-    0,                                  /* tp_vectorcall_offset */
-    0,                                  /* tp_getattr */
-    0,                                  /* tp_setattr */
-    0,                                  /* tp_as_async */
-    (reprfunc)pattern_repr,             /* tp_repr */
-    0,                                  /* tp_as_number */
-    0,                                  /* tp_as_sequence */
-    0,                                  /* tp_as_mapping */
-    (hashfunc)pattern_hash,             /* tp_hash */
-    0,                                  /* tp_call */
-    0,                                  /* tp_str */
-    0,                                  /* tp_getattro */
-    0,                                  /* tp_setattro */
-    0,                                  /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,                 /* tp_flags */
-    pattern_doc,                        /* tp_doc */
-    0,                                  /* tp_traverse */
-    0,                                  /* tp_clear */
-    pattern_richcompare,                /* tp_richcompare */
-    offsetof(PatternObject, weakreflist),       /* tp_weaklistoffset */
-    0,                                  /* tp_iter */
-    0,                                  /* tp_iternext */
-    pattern_methods,                    /* tp_methods */
-    pattern_members,                    /* tp_members */
-    pattern_getset,                     /* tp_getset */
+static PyType_Slot pattern_slots[] = {
+    {Py_tp_dealloc, (destructor)pattern_dealloc},
+    {Py_tp_repr, (reprfunc)pattern_repr},
+    {Py_tp_hash, (hashfunc)pattern_hash},
+    {Py_tp_doc, (void *)pattern_doc},
+    {Py_tp_richcompare, pattern_richcompare},
+    {Py_tp_methods, pattern_methods},
+    {Py_tp_members, pattern_members},
+    {Py_tp_getset, pattern_getset},
+    {0, NULL},
 };
 
-/* Match objects do not support length or assignment, but do support
-   __getitem__. */
-static PyMappingMethods match_as_mapping = {
-    NULL,
-    (binaryfunc)match_getitem,
-    NULL
+static PyType_Spec pattern_spec = {
+    .name = "re.Pattern",
+    .basicsize = sizeof(PatternObject),
+    .itemsize = sizeof(SRE_CODE),
+    .flags = Py_TPFLAGS_DEFAULT,
+    .slots = pattern_slots,
 };
 
 static PyMethodDef match_methods[] = {
@@ -2674,37 +2732,30 @@ static PyMemberDef match_members[] = {
 
 /* FIXME: implement setattr("string", None) as a special case (to
    detach the associated string, if any */
+static PyType_Slot match_slots[] = {
+    {Py_tp_dealloc, match_dealloc},
+    {Py_tp_repr, match_repr},
+    {Py_tp_doc, (void *)match_doc},
+    {Py_tp_methods, match_methods},
+    {Py_tp_members, match_members},
+    {Py_tp_getset, match_getset},
 
-static PyTypeObject Match_Type = {
-    PyVarObject_HEAD_INIT(NULL,0)
-    "re.Match",
-    sizeof(MatchObject), sizeof(Py_ssize_t),
-    (destructor)match_dealloc,  /* tp_dealloc */
-    0,                          /* tp_vectorcall_offset */
-    0,                          /* tp_getattr */
-    0,                          /* tp_setattr */
-    0,                          /* tp_as_async */
-    (reprfunc)match_repr,       /* tp_repr */
-    0,                          /* tp_as_number */
-    0,                          /* tp_as_sequence */
-    &match_as_mapping,          /* tp_as_mapping */
-    0,                          /* tp_hash */
-    0,                          /* tp_call */
-    0,                          /* tp_str */
-    0,                          /* tp_getattro */
-    0,                          /* tp_setattro */
-    0,                          /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,         /* tp_flags */
-    match_doc,                  /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    match_methods,              /* tp_methods */
-    match_members,              /* tp_members */
-    match_getset,               /* tp_getset */
+    /* As mapping.
+     *
+     * Match objects do not support length or assignment, but do support
+     * __getitem__.
+     */
+    {Py_mp_subscript, match_getitem},
+
+    {0, NULL},
+};
+
+static PyType_Spec match_spec = {
+    .name = "re.Match",
+    .basicsize = sizeof(MatchObject),
+    .itemsize = sizeof(Py_ssize_t),
+    .flags = Py_TPFLAGS_DEFAULT,
+    .slots = match_slots,
 };
 
 static PyMethodDef scanner_methods[] = {
@@ -2719,36 +2770,18 @@ static PyMemberDef scanner_members[] = {
     {NULL}  /* Sentinel */
 };
 
-static PyTypeObject Scanner_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_" SRE_MODULE ".SRE_Scanner",
-    sizeof(ScannerObject), 0,
-    (destructor)scanner_dealloc,/* 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 */
-    0,                          /* tp_getattro */
-    0,                          /* tp_setattro */
-    0,                          /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,         /* tp_flags */
-    0,                          /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    scanner_methods,            /* tp_methods */
-    scanner_members,            /* tp_members */
-    0,                          /* tp_getset */
+static PyType_Slot scanner_slots[] = {
+    {Py_tp_dealloc, scanner_dealloc},
+    {Py_tp_methods, scanner_methods},
+    {Py_tp_members, scanner_members},
+    {0, NULL},
+};
+
+static PyType_Spec scanner_spec = {
+    .name = "_" SRE_MODULE ".SRE_Scanner",
+    .basicsize = sizeof(ScannerObject),
+    .flags = Py_TPFLAGS_DEFAULT,
+    .slots = scanner_slots,
 };
 
 static PyMethodDef _functions[] = {
@@ -2761,64 +2794,108 @@ static PyMethodDef _functions[] = {
     {NULL, NULL}
 };
 
-static struct PyModuleDef sremodule = {
-        PyModuleDef_HEAD_INIT,
-        "_" SRE_MODULE,
-        NULL,
-        -1,
-        _functions,
-        NULL,
-        NULL,
-        NULL,
-        NULL
+static int
+sre_traverse(PyObject *module, visitproc visit, void *arg)
+{
+    _sremodulestate *state = get_sre_module_state(module);
+
+    Py_VISIT(state->Pattern_Type);
+    Py_VISIT(state->Match_Type);
+    Py_VISIT(state->Scanner_Type);
+
+    return 0;
+}
+
+static int
+sre_clear(PyObject *module)
+{
+    _sremodulestate *state = get_sre_module_state(module);
+
+    Py_CLEAR(state->Pattern_Type);
+    Py_CLEAR(state->Match_Type);
+    Py_CLEAR(state->Scanner_Type);
+
+    return 0;
+}
+
+static void
+sre_free(void *module)
+{
+    sre_clear((PyObject *)module);
+}
+
+#define CREATE_TYPE(m, type, spec)                                  \
+do {                                                                \
+    type = (PyTypeObject *)PyType_FromModuleAndSpec(m, spec, NULL); \
+    if (type == NULL) {                                             \
+        goto error;                                                 \
+    }                                                               \
+} while (0)
+
+#define ADD_ULONG_CONSTANT(module, name, value)           \
+    do {                                                  \
+        PyObject *o = PyLong_FromUnsignedLong(value);     \
+        if (!o)                                           \
+            goto error;                                   \
+        int res = PyModule_AddObjectRef(module, name, o); \
+        Py_DECREF(o);                                     \
+        if (res < 0) {                                    \
+            goto error;                                   \
+        }                                                 \
+} while (0)
+
+static int
+sre_exec(PyObject *m)
+{
+    _sremodulestate *state;
+
+    /* Create heap types */
+    state = get_sre_module_state(m);
+    CREATE_TYPE(m, state->Pattern_Type, &pattern_spec);
+    CREATE_TYPE(m, state->Match_Type, &match_spec);
+    CREATE_TYPE(m, state->Scanner_Type, &scanner_spec);
+
+    if (PyModule_AddIntConstant(m, "MAGIC", SRE_MAGIC) < 0) {
+        goto error;
+    }
+
+    if (PyModule_AddIntConstant(m, "CODESIZE", sizeof(SRE_CODE)) < 0) {
+        goto error;
+    }
+
+    ADD_ULONG_CONSTANT(m, "MAXREPEAT", SRE_MAXREPEAT);
+    ADD_ULONG_CONSTANT(m, "MAXGROUPS", SRE_MAXGROUPS);
+
+    if (PyModule_AddStringConstant(m, "copyright", copyright) < 0) {
+        goto error;
+    }
+
+    return 0;
+
+error:
+    return -1;
+}
+
+static PyModuleDef_Slot sre_slots[] = {
+    {Py_mod_exec, sre_exec},
+    {0, NULL},
 };
 
-PyMODINIT_FUNC PyInit__sre(void)
+static struct PyModuleDef sremodule = {
+    .m_base = PyModuleDef_HEAD_INIT,
+    .m_name = "_" SRE_MODULE,
+    .m_size = sizeof(_sremodulestate),
+    .m_methods = _functions,
+    .m_slots = sre_slots,
+    .m_traverse = sre_traverse,
+    .m_free = sre_free,
+    .m_clear = sre_clear,
+};
+
+PyMODINIT_FUNC
+PyInit__sre(void)
 {
-    PyObject* m;
-    PyObject* d;
-    PyObject* x;
-
-    /* Patch object types */
-    if (PyType_Ready(&Pattern_Type) || PyType_Ready(&Match_Type) ||
-        PyType_Ready(&Scanner_Type))
-        return NULL;
-
-    m = PyModule_Create(&sremodule);
-    if (m == NULL)
-        return NULL;
-    d = PyModule_GetDict(m);
-
-    x = PyLong_FromLong(SRE_MAGIC);
-    if (x) {
-        PyDict_SetItemString(d, "MAGIC", x);
-        Py_DECREF(x);
-    }
-
-    x = PyLong_FromLong(sizeof(SRE_CODE));
-    if (x) {
-        PyDict_SetItemString(d, "CODESIZE", x);
-        Py_DECREF(x);
-    }
-
-    x = PyLong_FromUnsignedLong(SRE_MAXREPEAT);
-    if (x) {
-        PyDict_SetItemString(d, "MAXREPEAT", x);
-        Py_DECREF(x);
-    }
-
-    x = PyLong_FromUnsignedLong(SRE_MAXGROUPS);
-    if (x) {
-        PyDict_SetItemString(d, "MAXGROUPS", x);
-        Py_DECREF(x);
-    }
-
-    x = PyUnicode_FromString(copyright);
-    if (x) {
-        PyDict_SetItemString(d, "copyright", x);
-        Py_DECREF(x);
-    }
-    return m;
+    return PyModuleDef_Init(&sremodule);
 }
 
 /* vim:ts=4:sw=4:et