Skip to content

Commit 0982ded

Browse files
authored
bpo-44032: Move pointer to code object from frame-object to frame specials array. (pythonGH-26771)
1 parent 7f01f77 commit 0982ded

File tree

6 files changed

+59
-41
lines changed

6 files changed

+59
-41
lines changed

Include/cpython/frameobject.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ typedef signed char PyFrameState;
2222
struct _frame {
2323
PyObject_HEAD
2424
struct _frame *f_back; /* previous frame, or NULL */
25-
PyCodeObject *f_code; /* code segment */
2625
PyObject **f_valuestack; /* points after the last local */
2726
PyObject *f_trace; /* Trace function */
2827
/* Borrowed reference to a generator, or NULL */

Include/internal/pycore_frame.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ enum {
88
FRAME_SPECIALS_GLOBALS_OFFSET = 0,
99
FRAME_SPECIALS_BUILTINS_OFFSET = 1,
1010
FRAME_SPECIALS_LOCALS_OFFSET = 2,
11-
FRAME_SPECIALS_SIZE = 3
11+
FRAME_SPECIALS_CODE_OFFSET = 3,
12+
FRAME_SPECIALS_SIZE = 4
1213
};
1314

1415
static inline PyObject **
@@ -30,6 +31,13 @@ _PyFrame_GetBuiltins(PyFrameObject *f)
3031
return _PyFrame_Specials(f)[FRAME_SPECIALS_BUILTINS_OFFSET];
3132
}
3233

34+
/* Returns a *borrowed* reference. */
35+
static inline PyCodeObject *
36+
_PyFrame_GetCode(PyFrameObject *f)
37+
{
38+
return (PyCodeObject *)_PyFrame_Specials(f)[FRAME_SPECIALS_CODE_OFFSET];
39+
}
40+
3341
int _PyFrame_TakeLocals(PyFrameObject *f);
3442

3543
#ifdef __cplusplus

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,7 @@ class C(object): pass
12751275
# frame
12761276
import inspect
12771277
x = inspect.currentframe()
1278-
check(x, size('5P3i4cP'))
1278+
check(x, size('4P3i4cP'))
12791279
# function
12801280
def func(): pass
12811281
check(func, size('14P'))

Objects/frameobject.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ PyFrame_GetLineNumber(PyFrameObject *f)
4646
return f->f_lineno;
4747
}
4848
else {
49-
return PyCode_Addr2Line(f->f_code, f->f_lasti*2);
49+
return PyCode_Addr2Line(_PyFrame_GetCode(f), f->f_lasti*2);
5050
}
5151
}
5252

@@ -472,7 +472,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
472472
}
473473
new_lineno = (int)l_new_lineno;
474474

475-
if (new_lineno < f->f_code->co_firstlineno) {
475+
if (new_lineno < _PyFrame_GetCode(f)->co_firstlineno) {
476476
PyErr_Format(PyExc_ValueError,
477477
"line %d comes before the current code block",
478478
new_lineno);
@@ -481,8 +481,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
481481

482482
/* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
483483
* should never overflow. */
484-
int len = (int)(PyBytes_GET_SIZE(f->f_code->co_code) / sizeof(_Py_CODEUNIT));
485-
int *lines = marklines(f->f_code, len);
484+
int len = (int)(PyBytes_GET_SIZE(_PyFrame_GetCode(f)->co_code) / sizeof(_Py_CODEUNIT));
485+
int *lines = marklines(_PyFrame_GetCode(f), len);
486486
if (lines == NULL) {
487487
return -1;
488488
}
@@ -496,7 +496,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
496496
return -1;
497497
}
498498

499-
int64_t *stacks = mark_stacks(f->f_code, len);
499+
int64_t *stacks = mark_stacks(_PyFrame_GetCode(f), len);
500500
if (stacks == NULL) {
501501
PyMem_Free(lines);
502502
return -1;
@@ -610,11 +610,17 @@ frame_dealloc(PyFrameObject *f)
610610
}
611611

612612
Py_TRASHCAN_SAFE_BEGIN(f)
613-
PyCodeObject *co = f->f_code;
613+
PyCodeObject *co = NULL;
614614

615615
/* Kill all local variables including specials. */
616616
if (f->f_localsptr) {
617-
for (int i = 0; i < co->co_nlocalsplus+FRAME_SPECIALS_SIZE; i++) {
617+
/* Don't clear code object until the end */
618+
co = _PyFrame_GetCode(f);
619+
PyObject **specials = _PyFrame_Specials(f);
620+
Py_CLEAR(specials[FRAME_SPECIALS_GLOBALS_OFFSET]);
621+
Py_CLEAR(specials[FRAME_SPECIALS_BUILTINS_OFFSET]);
622+
Py_CLEAR(specials[FRAME_SPECIALS_LOCALS_OFFSET]);
623+
for (int i = 0; i < co->co_nlocalsplus; i++) {
618624
Py_CLEAR(f->f_localsptr[i]);
619625
}
620626
/* Free items on stack */
@@ -625,6 +631,7 @@ frame_dealloc(PyFrameObject *f)
625631
PyMem_Free(f->f_localsptr);
626632
f->f_own_locals_memory = 0;
627633
}
634+
f->f_localsptr = NULL;
628635
}
629636
f->f_stackdepth = 0;
630637
Py_XDECREF(f->f_back);
@@ -643,7 +650,7 @@ frame_dealloc(PyFrameObject *f)
643650
PyObject_GC_Del(f);
644651
}
645652

646-
Py_DECREF(co);
653+
Py_XDECREF(co);
647654
Py_TRASHCAN_SAFE_END(f)
648655
}
649656

@@ -683,7 +690,7 @@ frame_tp_clear(PyFrameObject *f)
683690
f->f_state = FRAME_CLEARED;
684691

685692
Py_CLEAR(f->f_trace);
686-
PyCodeObject *co = f->f_code;
693+
PyCodeObject *co = _PyFrame_GetCode(f);
687694
/* locals */
688695
for (int i = 0; i < co->co_nlocalsplus; i++) {
689696
Py_CLEAR(f->f_localsptr[i]);
@@ -722,7 +729,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
722729
Py_ssize_t res;
723730
res = sizeof(PyFrameObject);
724731
if (f->f_own_locals_memory) {
725-
PyCodeObject *code = f->f_code;
732+
PyCodeObject *code = _PyFrame_GetCode(f);
726733
res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *);
727734
}
728735
return PyLong_FromSsize_t(res);
@@ -735,7 +742,7 @@ static PyObject *
735742
frame_repr(PyFrameObject *f)
736743
{
737744
int lineno = PyFrame_GetLineNumber(f);
738-
PyCodeObject *code = f->f_code;
745+
PyCodeObject *code = _PyFrame_GetCode(f);
739746
return PyUnicode_FromFormat(
740747
"<frame at %p, file %R, line %d, code %S>",
741748
f, code->co_filename, lineno, code->co_name);
@@ -876,7 +883,7 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *l
876883
PyObject **specials = f->f_localsptr + code->co_nlocalsplus;
877884
f->f_valuestack = specials + FRAME_SPECIALS_SIZE;
878885
f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame);
879-
f->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
886+
specials[FRAME_SPECIALS_CODE_OFFSET] = Py_NewRef(con->fc_code);
880887
specials[FRAME_SPECIALS_BUILTINS_OFFSET] = Py_NewRef(con->fc_builtins);
881888
specials[FRAME_SPECIALS_GLOBALS_OFFSET] = Py_NewRef(con->fc_globals);
882889
specials[FRAME_SPECIALS_LOCALS_OFFSET] = Py_XNewRef(locals);
@@ -921,7 +928,7 @@ static int
921928
_PyFrame_OpAlreadyRan(PyFrameObject *f, int opcode, int oparg)
922929
{
923930
const _Py_CODEUNIT *code =
924-
(const _Py_CODEUNIT *)PyBytes_AS_STRING(f->f_code->co_code);
931+
(const _Py_CODEUNIT *)PyBytes_AS_STRING(_PyFrame_GetCode(f)->co_code);
925932
for (int i = 0; i < f->f_lasti; i++) {
926933
if (_Py_OPCODE(code[i]) == opcode && _Py_OPARG(code[i]) == oparg) {
927934
return 1;
@@ -948,7 +955,7 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
948955
if (locals == NULL)
949956
return -1;
950957
}
951-
co = f->f_code;
958+
co = _PyFrame_GetCode(f);
952959
fast = f->f_localsptr;
953960
for (int i = 0; i < co->co_nlocalsplus; i++) {
954961
_PyLocalsPlusKind kind = co->co_localspluskinds[i];
@@ -1041,7 +1048,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
10411048
if (locals == NULL)
10421049
return;
10431050
fast = f->f_localsptr;
1044-
co = f->f_code;
1051+
co = _PyFrame_GetCode(f);
10451052

10461053
PyErr_Fetch(&error_type, &error_value, &error_traceback);
10471054
for (int i = 0; i < co->co_nlocalsplus; i++) {
@@ -1134,7 +1141,7 @@ PyCodeObject *
11341141
PyFrame_GetCode(PyFrameObject *frame)
11351142
{
11361143
assert(frame != NULL);
1137-
PyCodeObject *code = frame->f_code;
1144+
PyCodeObject *code = _PyFrame_GetCode(frame);
11381145
assert(code != NULL);
11391146
Py_INCREF(code);
11401147
return code;

Python/ceval.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
14511451
/* push frame */
14521452
tstate->frame = f;
14531453
specials = f->f_valuestack - FRAME_SPECIALS_SIZE;
1454-
co = f->f_code;
1454+
co = (PyCodeObject *)specials[FRAME_SPECIALS_CODE_OFFSET];
14551455

14561456
if (cframe.use_tracing) {
14571457
if (tstate->c_tracefunc != NULL) {
@@ -5388,9 +5388,10 @@ call_trace_protected(Py_tracefunc func, PyObject *obj,
53885388
static void
53895389
initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame)
53905390
{
5391-
if (trace_info->code != frame->f_code) {
5392-
trace_info->code = frame->f_code;
5393-
_PyCode_InitAddressRange(frame->f_code, &trace_info->bounds);
5391+
PyCodeObject *code = _PyFrame_GetCode(frame);
5392+
if (trace_info->code != code) {
5393+
trace_info->code = code;
5394+
_PyCode_InitAddressRange(code, &trace_info->bounds);
53945395
}
53955396
}
53965397

@@ -5405,7 +5406,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
54055406
tstate->tracing++;
54065407
tstate->cframe->use_tracing = 0;
54075408
if (frame->f_lasti < 0) {
5408-
frame->f_lineno = frame->f_code->co_firstlineno;
5409+
frame->f_lineno = _PyFrame_GetCode(frame)->co_firstlineno;
54095410
}
54105411
else {
54115412
initialize_trace_info(&tstate->trace_info, frame);
@@ -5684,7 +5685,7 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
56845685
int result = cf->cf_flags != 0;
56855686

56865687
if (current_frame != NULL) {
5687-
const int codeflags = current_frame->f_code->co_flags;
5688+
const int codeflags = _PyFrame_GetCode(current_frame)->co_flags;
56885689
const int compilerflags = codeflags & PyCF_MASK;
56895690
if (compilerflags) {
56905691
result = 1;
@@ -6289,7 +6290,7 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
62896290
}
62906291
case STORE_NAME:
62916292
{
6292-
PyObject *names = f->f_code->co_names;
6293+
PyObject *names = _PyFrame_GetCode(f)->co_names;
62936294
PyObject *name = GETITEM(names, oparg);
62946295
PyObject *locals = f->f_valuestack[
62956296
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
@@ -6376,7 +6377,7 @@ dtrace_function_entry(PyFrameObject *f)
63766377
const char *funcname;
63776378
int lineno;
63786379

6379-
PyCodeObject *code = f->f_code;
6380+
PyCodeObject *code = _PyFrame_GetCode(f);
63806381
filename = PyUnicode_AsUTF8(code->co_filename);
63816382
funcname = PyUnicode_AsUTF8(code->co_name);
63826383
lineno = PyFrame_GetLineNumber(f);
@@ -6391,7 +6392,7 @@ dtrace_function_return(PyFrameObject *f)
63916392
const char *funcname;
63926393
int lineno;
63936394

6394-
PyCodeObject *code = f->f_code;
6395+
PyCodeObject *code = _PyFrame_GetCode(f);
63956396
filename = PyUnicode_AsUTF8(code->co_filename);
63966397
funcname = PyUnicode_AsUTF8(code->co_name);
63976398
lineno = PyFrame_GetLineNumber(f);
@@ -6418,10 +6419,10 @@ maybe_dtrace_line(PyFrameObject *frame,
64186419
if (line != frame->f_lineno || frame->f_lasti < instr_prev) {
64196420
if (line != -1) {
64206421
frame->f_lineno = line;
6421-
co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
6422+
co_filename = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename);
64226423
if (!co_filename)
64236424
co_filename = "?";
6424-
co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
6425+
co_name = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_name);
64256426
if (!co_name)
64266427
co_name = "?";
64276428
PyDTrace_LINE(co_filename, co_name, line);

Tools/gdb/libpython.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,8 @@ def proxyval(self, visited):
856856

857857
FRAME_SPECIALS_GLOBAL_OFFSET = 0
858858
FRAME_SPECIALS_BUILTINS_OFFSET = 1
859+
FRAME_SPECIALS_CODE_OFFSET = 3
860+
FRAME_SPECIALS_SIZE = 4
859861

860862
class PyFrameObjectPtr(PyObjectPtr):
861863
_typename = 'PyFrameObject'
@@ -864,7 +866,7 @@ def __init__(self, gdbval, cast_to=None):
864866
PyObjectPtr.__init__(self, gdbval, cast_to)
865867

866868
if not self.is_optimized_out():
867-
self.co = PyCodeObjectPtr.from_pyobject_ptr(self.field('f_code'))
869+
self.co = self._f_code()
868870
self.co_name = self.co.pyop_field('co_name')
869871
self.co_filename = self.co.pyop_field('co_filename')
870872

@@ -890,11 +892,18 @@ def iter_locals(self):
890892
pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_localsplusnames[i])
891893
yield (pyop_name, pyop_value)
892894

895+
def _f_specials(self, index, cls=PyObjectPtr):
896+
f_valuestack = self.field('f_valuestack')
897+
return cls.from_pyobject_ptr(f_valuestack[index - FRAME_SPECIALS_SIZE])
898+
893899
def _f_globals(self):
894-
f_localsplus = self.field('f_localsptr')
895-
nlocalsplus = int_from_int(self.co.field('co_nlocalsplus'))
896-
index = nlocalsplus + FRAME_SPECIALS_GLOBAL_OFFSET
897-
return PyObjectPtr.from_pyobject_ptr(f_localsplus[index])
900+
return self._f_specials(FRAME_SPECIALS_GLOBAL_OFFSET)
901+
902+
def _f_builtins(self):
903+
return self._f_specials(FRAME_SPECIALS_BUILTINS_OFFSET)
904+
905+
def _f_code(self):
906+
return self._f_specials(FRAME_SPECIALS_CODE_OFFSET, PyCodeObjectPtr)
898907

899908
def iter_globals(self):
900909
'''
@@ -907,12 +916,6 @@ def iter_globals(self):
907916
pyop_globals = self._f_globals()
908917
return pyop_globals.iteritems()
909918

910-
def _f_builtins(self):
911-
f_localsplus = self.field('f_localsptr')
912-
nlocalsplus = int_from_int(self.co.field('co_nlocalsplus'))
913-
index = nlocalsplus + FRAME_SPECIALS_BUILTINS_OFFSET
914-
return PyObjectPtr.from_pyobject_ptr(f_localsplus[index])
915-
916919
def iter_builtins(self):
917920
'''
918921
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for

0 commit comments

Comments
 (0)