bpo-40429: PyFrame_GetCode() result cannot be NULL (GH-19772)

Add frame_nslots() to factorize duplicate code.
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 92206c5..6b3559e 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -665,12 +665,18 @@
     Py_TRASHCAN_SAFE_END(f)
 }
 
+static inline Py_ssize_t
+frame_nslots(PyFrameObject *frame)
+{
+    PyCodeObject *code = frame->f_code;
+    return (code->co_nlocals
+            + PyTuple_GET_SIZE(code->co_cellvars)
+            + PyTuple_GET_SIZE(code->co_freevars));
+}
+
 static int
 frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
 {
-    PyObject **fastlocals, **p;
-    Py_ssize_t i, slots;
-
     Py_VISIT(f->f_back);
     Py_VISIT(f->f_code);
     Py_VISIT(f->f_builtins);
@@ -679,15 +685,16 @@
     Py_VISIT(f->f_trace);
 
     /* locals */
-    slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
-    fastlocals = f->f_localsplus;
-    for (i = slots; --i >= 0; ++fastlocals)
+    PyObject **fastlocals = f->f_localsplus;
+    for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) {
         Py_VISIT(*fastlocals);
+    }
 
     /* stack */
     if (f->f_stacktop != NULL) {
-        for (p = f->f_valuestack; p < f->f_stacktop; p++)
+        for (PyObject **p = f->f_valuestack; p < f->f_stacktop; p++) {
             Py_VISIT(*p);
+        }
     }
     return 0;
 }
@@ -695,30 +702,28 @@
 static int
 frame_tp_clear(PyFrameObject *f)
 {
-    PyObject **fastlocals, **p, **oldtop;
-    Py_ssize_t i, slots;
-
     /* Before anything else, make sure that this frame is clearly marked
      * as being defunct!  Else, e.g., a generator reachable from this
      * frame may also point to this frame, believe itself to still be
      * active, and try cleaning up this frame again.
      */
-    oldtop = f->f_stacktop;
+    PyObject **oldtop = f->f_stacktop;
     f->f_stacktop = NULL;
     f->f_executing = 0;
 
     Py_CLEAR(f->f_trace);
 
     /* locals */
-    slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
-    fastlocals = f->f_localsplus;
-    for (i = slots; --i >= 0; ++fastlocals)
+    PyObject **fastlocals = f->f_localsplus;
+    for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++fastlocals) {
         Py_CLEAR(*fastlocals);
+    }
 
     /* stack */
     if (oldtop != NULL) {
-        for (p = f->f_valuestack; p < oldtop; p++)
+        for (PyObject **p = f->f_valuestack; p < oldtop; p++) {
             Py_CLEAR(*p);
+        }
     }
     return 0;
 }
@@ -747,10 +752,10 @@
 {
     Py_ssize_t res, extras, ncells, nfrees;
 
-    ncells = PyTuple_GET_SIZE(f->f_code->co_cellvars);
-    nfrees = PyTuple_GET_SIZE(f->f_code->co_freevars);
-    extras = f->f_code->co_stacksize + f->f_code->co_nlocals +
-             ncells + nfrees;
+    PyCodeObject *code = f->f_code;
+    ncells = PyTuple_GET_SIZE(code->co_cellvars);
+    nfrees = PyTuple_GET_SIZE(code->co_freevars);
+    extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
     /* subtract one as it is already included in PyFrameObject */
     res = sizeof(PyFrameObject) + (extras-1) * sizeof(PyObject *);
 
@@ -764,9 +769,10 @@
 frame_repr(PyFrameObject *f)
 {
     int lineno = PyFrame_GetLineNumber(f);
+    PyCodeObject *code = f->f_code;
     return PyUnicode_FromFormat(
         "<frame at %p, file %R, line %d, code %S>",
-        f, f->f_code->co_filename, lineno, f->f_code->co_name);
+        f, code->co_filename, lineno, code->co_name);
 }
 
 static PyMethodDef frame_methods[] = {
@@ -940,6 +946,8 @@
     f->f_trace_opcodes = 0;
     f->f_trace_lines = 1;
 
+    assert(f->f_code != NULL);
+
     return f;
 }
 
@@ -1227,5 +1235,7 @@
 PyFrame_GetCode(PyFrameObject *frame)
 {
     assert(frame != NULL);
-    return frame->f_code;
+    PyCodeObject *code = frame->f_code;
+    assert(code != NULL);
+    return code;
 }
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 66c6ccb..071def8 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -1117,11 +1117,11 @@
     }
     frame = PyEval_GetFrame();
     for (int i = 0; i < frame_count; ++i) {
-        PyObject *frameinfo = Py_BuildValue(
-            "OiO",
-            frame->f_code->co_filename,
-            PyFrame_GetLineNumber(frame),
-            frame->f_code->co_name);
+        PyCodeObject *code = frame->f_code;
+        PyObject *frameinfo = Py_BuildValue("OiO",
+                                            code->co_filename,
+                                            PyFrame_GetLineNumber(frame),
+                                            code->co_name);
         if (!frameinfo) {
             Py_DECREF(cr_origin);
             return NULL;
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 9d97f38..f65f053 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -8040,11 +8040,6 @@
             return -1;
         }
         co = PyFrame_GetCode(f);
-        if (co == NULL) {
-            PyErr_SetString(PyExc_RuntimeError,
-                            "super(): no code object");
-            return -1;
-        }
         if (co->co_argcount == 0) {
             PyErr_SetString(PyExc_RuntimeError,
                             "super(): no arguments");