Skip to content

bpo-44032: Move pointer to code object from frame-object to frame specials array. #26771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Include/cpython/frameobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
10 changes: 9 additions & 1 deletion Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 **
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'))
Expand Down
39 changes: 23 additions & 16 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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);
Expand All @@ -643,7 +650,7 @@ frame_dealloc(PyFrameObject *f)
PyObject_GC_Del(f);
}

Py_DECREF(co);
Py_XDECREF(co);
Py_TRASHCAN_SAFE_END(f)
}

Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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];
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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;
Expand Down
23 changes: 12 additions & 11 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
25 changes: 14 additions & 11 deletions Tools/gdb/libpython.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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')

Expand All @@ -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):
'''
Expand All @@ -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
Expand Down