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( "", 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