Skip to content

Commit a555393

Browse files
committed
Move (slow) locals frame object to per-thread stack.
1 parent 5a4803c commit a555393

File tree

4 files changed

+38
-33
lines changed

4 files changed

+38
-33
lines changed

Include/cpython/frameobject.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ typedef signed char PyFrameState;
2222
enum {
2323
FRAME_SPECIALS_GLOBALS_OFFSET = 0,
2424
FRAME_SPECIALS_BUILTINS_OFFSET = 1,
25-
FRAME_SPECIALS_SIZE = 2
25+
FRAME_SPECIALS_LOCALS_OFFSET = 2,
26+
FRAME_SPECIALS_SIZE = 3
2627
};
2728

2829
struct _frame {
2930
PyObject_HEAD
3031
struct _frame *f_back; /* previous frame, or NULL */
3132
PyCodeObject *f_code; /* code segment */
32-
PyObject *f_locals; /* local symbol table (any mapping) */
3333
PyObject **f_valuestack; /* points after the last local */
3434
PyObject *f_trace; /* Trace function */
3535
/* Borrowed reference to a generator, or NULL */

Lib/test/test_sys.py

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

Objects/frameobject.c

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,20 @@ get_frame_state(void)
2525
return &interp->frame;
2626
}
2727

28+
static inline PyObject **
29+
_PyFrame_Specials(PyFrameObject *f) {
30+
return &f->f_valuestack[-FRAME_SPECIALS_SIZE];
31+
}
32+
2833

2934
static PyObject *
3035
frame_getlocals(PyFrameObject *f, void *closure)
3136
{
3237
if (PyFrame_FastToLocalsWithError(f) < 0)
3338
return NULL;
34-
Py_INCREF(f->f_locals);
35-
return f->f_locals;
36-
}
37-
38-
static inline PyObject **
39-
_PyFrame_Specials(PyFrameObject *f) {
40-
return &f->f_valuestack[-FRAME_SPECIALS_SIZE];
39+
PyObject *locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
40+
Py_INCREF(locals);
41+
return locals;
4142
}
4243

4344
int
@@ -642,7 +643,6 @@ frame_dealloc(PyFrameObject *f)
642643
}
643644
f->f_stackdepth = 0;
644645
Py_XDECREF(f->f_back);
645-
Py_CLEAR(f->f_locals);
646646
Py_CLEAR(f->f_trace);
647647
struct _Py_frame_state *state = get_frame_state();
648648
#ifdef Py_DEBUG
@@ -672,7 +672,6 @@ static int
672672
frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
673673
{
674674
Py_VISIT(f->f_back);
675-
Py_VISIT(f->f_locals);
676675
Py_VISIT(f->f_trace);
677676

678677
/* locals */
@@ -894,7 +893,7 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *l
894893
f->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
895894
_PyFrame_Specials(f)[FRAME_SPECIALS_BUILTINS_OFFSET] = Py_NewRef(con->fc_builtins);
896895
_PyFrame_Specials(f)[FRAME_SPECIALS_GLOBALS_OFFSET] = Py_NewRef(con->fc_globals);
897-
f->f_locals = Py_XNewRef(locals);
896+
_PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET] = Py_XNewRef(locals);
898897
// f_valuestack initialized by frame_alloc()
899898
f->f_trace = NULL;
900899
f->f_stackdepth = 0;
@@ -1046,9 +1045,9 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
10461045
PyErr_BadInternalCall();
10471046
return -1;
10481047
}
1049-
locals = f->f_locals;
1048+
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
10501049
if (locals == NULL) {
1051-
locals = f->f_locals = PyDict_New();
1050+
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET] = PyDict_New();
10521051
if (locals == NULL)
10531052
return -1;
10541053
}
@@ -1107,7 +1106,7 @@ PyFrame_FastToLocals(PyFrameObject *f)
11071106
void
11081107
PyFrame_LocalsToFast(PyFrameObject *f, int clear)
11091108
{
1110-
/* Merge f->f_locals into fast locals */
1109+
/* Merge locals into fast locals */
11111110
PyObject *locals, *map;
11121111
PyObject **fast;
11131112
PyObject *error_type, *error_value, *error_traceback;
@@ -1116,7 +1115,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
11161115
Py_ssize_t ncells, nfreevars;
11171116
if (f == NULL)
11181117
return;
1119-
locals = f->f_locals;
1118+
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
11201119
co = f->f_code;
11211120
map = co->co_varnames;
11221121
if (locals == NULL)

Python/ceval.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
15491549

15501550
#define GLOBALS() specials[FRAME_SPECIALS_GLOBALS_OFFSET]
15511551
#define BUILTINS() specials[FRAME_SPECIALS_BUILTINS_OFFSET]
1552+
#define LOCALS() specials[FRAME_SPECIALS_LOCALS_OFFSET]
15521553

15531554
PyObject* _Py_HOT_FUNCTION
15541555
_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
@@ -2759,7 +2760,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
27592760
case TARGET(STORE_NAME): {
27602761
PyObject *name = GETITEM(names, oparg);
27612762
PyObject *v = POP();
2762-
PyObject *ns = f->f_locals;
2763+
PyObject *ns = LOCALS();
27632764
int err;
27642765
if (ns == NULL) {
27652766
_PyErr_Format(tstate, PyExc_SystemError,
@@ -2779,7 +2780,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
27792780

27802781
case TARGET(DELETE_NAME): {
27812782
PyObject *name = GETITEM(names, oparg);
2782-
PyObject *ns = f->f_locals;
2783+
PyObject *ns = LOCALS();
27832784
int err;
27842785
if (ns == NULL) {
27852786
_PyErr_Format(tstate, PyExc_SystemError,
@@ -2894,7 +2895,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
28942895

28952896
case TARGET(LOAD_NAME): {
28962897
PyObject *name = GETITEM(names, oparg);
2897-
PyObject *locals = f->f_locals;
2898+
PyObject *locals = LOCALS();
28982899
PyObject *v;
28992900
if (locals == NULL) {
29002901
_PyErr_Format(tstate, PyExc_SystemError,
@@ -3076,7 +3077,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
30763077
}
30773078

30783079
case TARGET(LOAD_CLASSDEREF): {
3079-
PyObject *name, *value, *locals = f->f_locals;
3080+
PyObject *name, *value, *locals = LOCALS();
30803081
Py_ssize_t idx;
30813082
assert(locals);
30823083
assert(oparg >= PyTuple_GET_SIZE(co->co_cellvars));
@@ -3269,14 +3270,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
32693270
_Py_IDENTIFIER(__annotations__);
32703271
int err;
32713272
PyObject *ann_dict;
3272-
if (f->f_locals == NULL) {
3273+
if (LOCALS() == NULL) {
32733274
_PyErr_Format(tstate, PyExc_SystemError,
32743275
"no locals found when setting up annotations");
32753276
goto error;
32763277
}
32773278
/* check if __annotations__ in locals()... */
3278-
if (PyDict_CheckExact(f->f_locals)) {
3279-
ann_dict = _PyDict_GetItemIdWithError(f->f_locals,
3279+
if (PyDict_CheckExact(LOCALS())) {
3280+
ann_dict = _PyDict_GetItemIdWithError(LOCALS(),
32803281
&PyId___annotations__);
32813282
if (ann_dict == NULL) {
32823283
if (_PyErr_Occurred(tstate)) {
@@ -3287,7 +3288,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
32873288
if (ann_dict == NULL) {
32883289
goto error;
32893290
}
3290-
err = _PyDict_SetItemId(f->f_locals,
3291+
err = _PyDict_SetItemId(LOCALS(),
32913292
&PyId___annotations__, ann_dict);
32923293
Py_DECREF(ann_dict);
32933294
if (err != 0) {
@@ -3301,7 +3302,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
33013302
if (ann_str == NULL) {
33023303
goto error;
33033304
}
3304-
ann_dict = PyObject_GetItem(f->f_locals, ann_str);
3305+
ann_dict = PyObject_GetItem(LOCALS(), ann_str);
33053306
if (ann_dict == NULL) {
33063307
if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
33073308
goto error;
@@ -3311,7 +3312,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
33113312
if (ann_dict == NULL) {
33123313
goto error;
33133314
}
3314-
err = PyObject_SetItem(f->f_locals, ann_str, ann_dict);
3315+
err = PyObject_SetItem(LOCALS(), ann_str, ann_dict);
33153316
Py_DECREF(ann_dict);
33163317
if (err != 0) {
33173318
goto error;
@@ -3710,7 +3711,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
37103711
goto error;
37113712
}
37123713

3713-
locals = f->f_locals;
3714+
locals = LOCALS();
37143715
if (locals == NULL) {
37153716
_PyErr_SetString(tstate, PyExc_SystemError,
37163717
"no locals found during 'import *'");
@@ -5837,8 +5838,10 @@ PyEval_GetLocals(void)
58375838
return NULL;
58385839
}
58395840

5840-
assert(current_frame->f_locals != NULL);
5841-
return current_frame->f_locals;
5841+
PyObject *locals = current_frame->f_valuestack[
5842+
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
5843+
assert(locals != NULL);
5844+
return locals;
58425845
}
58435846

58445847
PyObject *
@@ -6107,6 +6110,8 @@ import_name(PyThreadState *tstate, PyFrameObject *f,
61076110
}
61086111
return NULL;
61096112
}
6113+
PyObject *locals = f->f_valuestack[
6114+
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
61106115
/* Fast path for not overloaded __import__. */
61116116
if (import_func == tstate->interp->import_func) {
61126117
int ilevel = _PyLong_AsInt(level);
@@ -6116,7 +6121,7 @@ import_name(PyThreadState *tstate, PyFrameObject *f,
61166121
res = PyImport_ImportModuleLevelObject(
61176122
name,
61186123
_PyFrame_GetGlobals(f),
6119-
f->f_locals == NULL ? Py_None : f->f_locals,
6124+
locals == NULL ? Py_None :locals,
61206125
fromlist,
61216126
ilevel);
61226127
return res;
@@ -6126,7 +6131,7 @@ import_name(PyThreadState *tstate, PyFrameObject *f,
61266131

61276132
stack[0] = name;
61286133
stack[1] = _PyFrame_GetGlobals(f);
6129-
stack[2] = f->f_locals == NULL ? Py_None : f->f_locals;
6134+
stack[2] = locals == NULL ? Py_None : locals;
61306135
stack[3] = fromlist;
61316136
stack[4] = level;
61326137
res = _PyObject_FastCall(import_func, stack, 5);
@@ -6471,7 +6476,8 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
64716476
{
64726477
PyObject *names = f->f_code->co_names;
64736478
PyObject *name = GETITEM(names, oparg);
6474-
PyObject *locals = f->f_locals;
6479+
PyObject *locals = f->f_valuestack[
6480+
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
64756481
if (locals && PyDict_CheckExact(locals)) {
64766482
PyObject *w = PyDict_GetItemWithError(locals, name);
64776483
if ((w == v && PyDict_DelItem(locals, name) != 0) ||

0 commit comments

Comments
 (0)