[Python-checkins] bpo-44032: Move pointer to code object from frame-object to frame specials array. (GH-26771)

markshannon webhook-mailer at python.org
Fri Jun 18 06:00:50 EDT 2021


https://github.com/python/cpython/commit/0982ded179f280176868c1c4eccf77bf70687816
commit: 0982ded179f280176868c1c4eccf77bf70687816
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-06-18T11:00:29+01:00
summary:

bpo-44032: Move pointer to code object from frame-object to frame specials array. (GH-26771)

files:
M Include/cpython/frameobject.h
M Include/internal/pycore_frame.h
M Lib/test/test_sys.py
M Objects/frameobject.c
M Python/ceval.c
M Tools/gdb/libpython.py

diff --git a/Include/cpython/frameobject.h b/Include/cpython/frameobject.h
index fc20bc2ff89b0c..2bf458cab35451 100644
--- a/Include/cpython/frameobject.h
+++ b/Include/cpython/frameobject.h
@@ -22,7 +22,6 @@ typedef signed char PyFrameState;
 struct _frame {
     PyObject_HEAD
     struct _frame *f_back;      /* previous frame, or NULL */
-    PyCodeObject *f_code;       /* code segment */
     PyObject **f_valuestack;    /* points after the last local */
     PyObject *f_trace;          /* Trace function */
     /* Borrowed reference to a generator, or NULL */
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index 44f58fb6948712..e30e3c89bfb62b 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -8,7 +8,8 @@ enum {
     FRAME_SPECIALS_GLOBALS_OFFSET = 0,
     FRAME_SPECIALS_BUILTINS_OFFSET = 1,
     FRAME_SPECIALS_LOCALS_OFFSET = 2,
-    FRAME_SPECIALS_SIZE = 3
+    FRAME_SPECIALS_CODE_OFFSET = 3,
+    FRAME_SPECIALS_SIZE = 4
 };
 
 static inline PyObject **
@@ -30,6 +31,13 @@ _PyFrame_GetBuiltins(PyFrameObject *f)
     return _PyFrame_Specials(f)[FRAME_SPECIALS_BUILTINS_OFFSET];
 }
 
+/* Returns a *borrowed* reference. */
+static inline PyCodeObject *
+_PyFrame_GetCode(PyFrameObject *f)
+{
+    return (PyCodeObject *)_PyFrame_Specials(f)[FRAME_SPECIALS_CODE_OFFSET];
+}
+
 int _PyFrame_TakeLocals(PyFrameObject *f);
 
 #ifdef __cplusplus
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 40fb721f3fa595..a549d44c5210fc 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1275,7 +1275,7 @@ class C(object): pass
         # frame
         import inspect
         x = inspect.currentframe()
-        check(x, size('5P3i4cP'))
+        check(x, size('4P3i4cP'))
         # function
         def func(): pass
         check(func, size('14P'))
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 5057313870c60b..f9090d8cb14d27 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -46,7 +46,7 @@ PyFrame_GetLineNumber(PyFrameObject *f)
         return f->f_lineno;
     }
     else {
-        return PyCode_Addr2Line(f->f_code, f->f_lasti*2);
+        return PyCode_Addr2Line(_PyFrame_GetCode(f), f->f_lasti*2);
     }
 }
 
@@ -472,7 +472,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
     }
     new_lineno = (int)l_new_lineno;
 
-    if (new_lineno < f->f_code->co_firstlineno) {
+    if (new_lineno < _PyFrame_GetCode(f)->co_firstlineno) {
         PyErr_Format(PyExc_ValueError,
                     "line %d comes before the current code block",
                     new_lineno);
@@ -481,8 +481,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
 
     /* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
      * should never overflow. */
-    int len = (int)(PyBytes_GET_SIZE(f->f_code->co_code) / sizeof(_Py_CODEUNIT));
-    int *lines = marklines(f->f_code, len);
+    int len = (int)(PyBytes_GET_SIZE(_PyFrame_GetCode(f)->co_code) / sizeof(_Py_CODEUNIT));
+    int *lines = marklines(_PyFrame_GetCode(f), len);
     if (lines == NULL) {
         return -1;
     }
@@ -496,7 +496,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
         return -1;
     }
 
-    int64_t *stacks = mark_stacks(f->f_code, len);
+    int64_t *stacks = mark_stacks(_PyFrame_GetCode(f), len);
     if (stacks == NULL) {
         PyMem_Free(lines);
         return -1;
@@ -610,11 +610,17 @@ frame_dealloc(PyFrameObject *f)
     }
 
     Py_TRASHCAN_SAFE_BEGIN(f)
-    PyCodeObject *co = f->f_code;
+    PyCodeObject *co = NULL;
 
     /* Kill all local variables including specials. */
     if (f->f_localsptr) {
-        for (int i = 0; i < co->co_nlocalsplus+FRAME_SPECIALS_SIZE; i++) {
+        /* Don't clear code object until the end */
+        co = _PyFrame_GetCode(f);
+        PyObject **specials = _PyFrame_Specials(f);
+        Py_CLEAR(specials[FRAME_SPECIALS_GLOBALS_OFFSET]);
+        Py_CLEAR(specials[FRAME_SPECIALS_BUILTINS_OFFSET]);
+        Py_CLEAR(specials[FRAME_SPECIALS_LOCALS_OFFSET]);
+        for (int i = 0; i < co->co_nlocalsplus; i++) {
             Py_CLEAR(f->f_localsptr[i]);
         }
         /* Free items on stack */
@@ -625,6 +631,7 @@ frame_dealloc(PyFrameObject *f)
             PyMem_Free(f->f_localsptr);
             f->f_own_locals_memory = 0;
         }
+        f->f_localsptr = NULL;
     }
     f->f_stackdepth = 0;
     Py_XDECREF(f->f_back);
@@ -643,7 +650,7 @@ frame_dealloc(PyFrameObject *f)
         PyObject_GC_Del(f);
     }
 
-    Py_DECREF(co);
+    Py_XDECREF(co);
     Py_TRASHCAN_SAFE_END(f)
 }
 
@@ -683,7 +690,7 @@ frame_tp_clear(PyFrameObject *f)
     f->f_state = FRAME_CLEARED;
 
     Py_CLEAR(f->f_trace);
-    PyCodeObject *co = f->f_code;
+    PyCodeObject *co = _PyFrame_GetCode(f);
     /* locals */
     for (int i = 0; i < co->co_nlocalsplus; i++) {
         Py_CLEAR(f->f_localsptr[i]);
@@ -722,7 +729,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
     Py_ssize_t res;
     res = sizeof(PyFrameObject);
     if (f->f_own_locals_memory) {
-        PyCodeObject *code = f->f_code;
+        PyCodeObject *code = _PyFrame_GetCode(f);
         res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *);
     }
     return PyLong_FromSsize_t(res);
@@ -735,7 +742,7 @@ static PyObject *
 frame_repr(PyFrameObject *f)
 {
     int lineno = PyFrame_GetLineNumber(f);
-    PyCodeObject *code = f->f_code;
+    PyCodeObject *code = _PyFrame_GetCode(f);
     return PyUnicode_FromFormat(
         "<frame at %p, file %R, line %d, code %S>",
         f, code->co_filename, lineno, code->co_name);
@@ -876,7 +883,7 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *l
     PyObject **specials = f->f_localsptr + code->co_nlocalsplus;
     f->f_valuestack = specials + FRAME_SPECIALS_SIZE;
     f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame);
-    f->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
+    specials[FRAME_SPECIALS_CODE_OFFSET] = Py_NewRef(con->fc_code);
     specials[FRAME_SPECIALS_BUILTINS_OFFSET] = Py_NewRef(con->fc_builtins);
     specials[FRAME_SPECIALS_GLOBALS_OFFSET] = Py_NewRef(con->fc_globals);
     specials[FRAME_SPECIALS_LOCALS_OFFSET] = Py_XNewRef(locals);
@@ -921,7 +928,7 @@ static int
 _PyFrame_OpAlreadyRan(PyFrameObject *f, int opcode, int oparg)
 {
     const _Py_CODEUNIT *code =
-        (const _Py_CODEUNIT *)PyBytes_AS_STRING(f->f_code->co_code);
+        (const _Py_CODEUNIT *)PyBytes_AS_STRING(_PyFrame_GetCode(f)->co_code);
     for (int i = 0; i < f->f_lasti; i++) {
         if (_Py_OPCODE(code[i]) == opcode && _Py_OPARG(code[i]) == oparg) {
             return 1;
@@ -948,7 +955,7 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
         if (locals == NULL)
             return -1;
     }
-    co = f->f_code;
+    co = _PyFrame_GetCode(f);
     fast = f->f_localsptr;
     for (int i = 0; i < co->co_nlocalsplus; i++) {
         _PyLocalsPlusKind kind = co->co_localspluskinds[i];
@@ -1041,7 +1048,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
     if (locals == NULL)
         return;
     fast = f->f_localsptr;
-    co = f->f_code;
+    co = _PyFrame_GetCode(f);
 
     PyErr_Fetch(&error_type, &error_value, &error_traceback);
     for (int i = 0; i < co->co_nlocalsplus; i++) {
@@ -1134,7 +1141,7 @@ PyCodeObject *
 PyFrame_GetCode(PyFrameObject *frame)
 {
     assert(frame != NULL);
-    PyCodeObject *code = frame->f_code;
+    PyCodeObject *code = _PyFrame_GetCode(frame);
     assert(code != NULL);
     Py_INCREF(code);
     return code;
diff --git a/Python/ceval.c b/Python/ceval.c
index a9b9aca0399035..699cd865faa1be 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1451,7 +1451,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
     /* push frame */
     tstate->frame = f;
     specials = f->f_valuestack - FRAME_SPECIALS_SIZE;
-    co = f->f_code;
+    co = (PyCodeObject *)specials[FRAME_SPECIALS_CODE_OFFSET];
 
     if (cframe.use_tracing) {
         if (tstate->c_tracefunc != NULL) {
@@ -5388,9 +5388,10 @@ call_trace_protected(Py_tracefunc func, PyObject *obj,
 static void
 initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame)
 {
-    if (trace_info->code != frame->f_code) {
-        trace_info->code = frame->f_code;
-        _PyCode_InitAddressRange(frame->f_code, &trace_info->bounds);
+    PyCodeObject *code = _PyFrame_GetCode(frame);
+    if (trace_info->code != code) {
+        trace_info->code = code;
+        _PyCode_InitAddressRange(code, &trace_info->bounds);
     }
 }
 
@@ -5405,7 +5406,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
     tstate->tracing++;
     tstate->cframe->use_tracing = 0;
     if (frame->f_lasti < 0) {
-        frame->f_lineno = frame->f_code->co_firstlineno;
+        frame->f_lineno = _PyFrame_GetCode(frame)->co_firstlineno;
     }
     else {
         initialize_trace_info(&tstate->trace_info, frame);
@@ -5684,7 +5685,7 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
     int result = cf->cf_flags != 0;
 
     if (current_frame != NULL) {
-        const int codeflags = current_frame->f_code->co_flags;
+        const int codeflags = _PyFrame_GetCode(current_frame)->co_flags;
         const int compilerflags = codeflags & PyCF_MASK;
         if (compilerflags) {
             result = 1;
@@ -6289,7 +6290,7 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
         }
         case STORE_NAME:
         {
-            PyObject *names = f->f_code->co_names;
+            PyObject *names = _PyFrame_GetCode(f)->co_names;
             PyObject *name = GETITEM(names, oparg);
             PyObject *locals = f->f_valuestack[
                 FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
@@ -6376,7 +6377,7 @@ dtrace_function_entry(PyFrameObject *f)
     const char *funcname;
     int lineno;
 
-    PyCodeObject *code = f->f_code;
+    PyCodeObject *code = _PyFrame_GetCode(f);
     filename = PyUnicode_AsUTF8(code->co_filename);
     funcname = PyUnicode_AsUTF8(code->co_name);
     lineno = PyFrame_GetLineNumber(f);
@@ -6391,7 +6392,7 @@ dtrace_function_return(PyFrameObject *f)
     const char *funcname;
     int lineno;
 
-    PyCodeObject *code = f->f_code;
+    PyCodeObject *code = _PyFrame_GetCode(f);
     filename = PyUnicode_AsUTF8(code->co_filename);
     funcname = PyUnicode_AsUTF8(code->co_name);
     lineno = PyFrame_GetLineNumber(f);
@@ -6418,10 +6419,10 @@ maybe_dtrace_line(PyFrameObject *frame,
     if (line != frame->f_lineno || frame->f_lasti < instr_prev) {
         if (line != -1) {
             frame->f_lineno = line;
-            co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
+            co_filename = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename);
             if (!co_filename)
                 co_filename = "?";
-            co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
+            co_name = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_name);
             if (!co_name)
                 co_name = "?";
             PyDTrace_LINE(co_filename, co_name, line);
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index 756b52c3c57a61..0198500265be41 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -856,6 +856,8 @@ def proxyval(self, visited):
 
 FRAME_SPECIALS_GLOBAL_OFFSET = 0
 FRAME_SPECIALS_BUILTINS_OFFSET = 1
+FRAME_SPECIALS_CODE_OFFSET = 3
+FRAME_SPECIALS_SIZE = 4
 
 class PyFrameObjectPtr(PyObjectPtr):
     _typename = 'PyFrameObject'
@@ -864,7 +866,7 @@ def __init__(self, gdbval, cast_to=None):
         PyObjectPtr.__init__(self, gdbval, cast_to)
 
         if not self.is_optimized_out():
-            self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
+            self.co = self._f_code()
             self.co_name = self.co.pyop_field('co_name')
             self.co_filename = self.co.pyop_field('co_filename')
 
@@ -890,11 +892,18 @@ def iter_locals(self):
             pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_localsplusnames[i])
             yield (pyop_name, pyop_value)
 
+    def _f_specials(self, index, cls=PyObjectPtr):
+        f_valuestack = self.field('f_valuestack')
+        return cls.from_pyobject_ptr(f_valuestack[index - FRAME_SPECIALS_SIZE])
+
     def _f_globals(self):
-        f_localsplus = self.field('f_localsptr')
-        nlocalsplus = int_from_int(self.co.field('co_nlocalsplus'))
-        index = nlocalsplus + FRAME_SPECIALS_GLOBAL_OFFSET
-        return PyObjectPtr.from_pyobject_ptr(f_localsplus[index])
+        return self._f_specials(FRAME_SPECIALS_GLOBAL_OFFSET)
+
+    def _f_builtins(self):
+        return self._f_specials(FRAME_SPECIALS_BUILTINS_OFFSET)
+
+    def _f_code(self):
+        return self._f_specials(FRAME_SPECIALS_CODE_OFFSET, PyCodeObjectPtr)
 
     def iter_globals(self):
         '''
@@ -907,12 +916,6 @@ def iter_globals(self):
         pyop_globals = self._f_globals()
         return pyop_globals.iteritems()
 
-    def _f_builtins(self):
-        f_localsplus = self.field('f_localsptr')
-        nlocalsplus = int_from_int(self.co.field('co_nlocalsplus'))
-        index = nlocalsplus + FRAME_SPECIALS_BUILTINS_OFFSET
-        return PyObjectPtr.from_pyobject_ptr(f_localsplus[index])
-
     def iter_builtins(self):
         '''
         Yield a sequence of (name,value) pairs of PyObjectPtr instances, for



More information about the Python-checkins mailing list