8000 Changed strategy, func_class_dict and *_CLASS_DICT. · python/cpython@0bb175a · GitHub
[go: up one dir, main page]

Skip to content

Commit 0bb175a

Browse files
committed
Changed strategy, func_class_dict and *_CLASS_DICT.
Rather than changing a bunch of stuff (and confusing the runtime by having __annotate__ functions have *both* fast *and* slow locals) we're changing the approach. For delayed-evaluation expressions (e.g. __annotate__ in PEP 649) we're going to change the LOAD_NAME opcodes we generate into LOAD_CLASS_DICT opcodes. Then when we bind that function (e.g. an __annotate__ inside a class body) we're going to use the new INTRINSIC2 SET_CLASS_DICT opcode to set the new func_class_dict field. LOAD_CLASS_DICT does its lookup in frame->f_funcobj->func_class_dict, so, we didn't make the frame larger!
1 parent 9632c02 commit 0bb175a

15 files changed

+384
-327
lines changed

Include/cpython/funcobject.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ extern "C" {
1010

1111
#define COMMON_FIELDS(PREFIX) \
1212
PyObject *PREFIX ## globals; \
13-
PyObject *PREFIX ## locals; /* "slow" locals, not fast */ \
1413
PyObject *PREFIX ## builtins; \
1514
PyObject *PREFIX ## name; \
1615
PyObject *PREFIX ## qualname; \
@@ -42,6 +41,7 @@ typedef struct {
4241
PyObject *func_weakreflist; /* List of weak references */
4342
PyObject *func_module; /* The __module__ attribute, can be anything */
4443
PyObject *func_annotations; /* Annotations, a dict or NULL */
44+
PyObject *func_class_dict; /* Class dict, a dict or NULL */
4545
vectorcallfunc vectorcall;
4646
/* Version number for use by specializer.
4747
* Can set to non-zero when we want to specialize.
@@ -68,7 +68,7 @@ PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *);
6868
PyAPI_FUNC(PyObject *) PyFunction_NewWithQualName(PyObject *, PyObject *, PyObject *);
6969
PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *);
7070
PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *);
71-
PyAPI_FUNC(PyObject *) PyFunction_GetLocals(PyObject *);
71+
PyAPI_FUNC(PyObject *) PyFunction_GetClassDict(PyObject *);
7272
PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
7373
PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *);
7474
PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *);
@@ -101,10 +101,10 @@ static inline PyObject* PyFunction_GET_GLOBALS(PyObject *func) {
101101
}
102102
#define PyFunction_GET_GLOBALS(func) PyFunction_GET_GLOBALS(_PyObject_CAST(func))
103103

104-
static inline PyObject* PyFunction_GET_LOCALS(PyObject *func) {
105-
return _PyFunction_CAST(func)->func_locals;
104+
static inline PyObject* PyFunction_GET_CLASS_DICT(PyObject *func) {
105+
return _PyFunction_CAST(func)->func_class_dict;
106106
}
107-
#define PyFunction_GET_LOCALS(func) PyFunction_GET_LOCALS(_PyObject_CAST(func))
107+
#define PyFunction_GET_CLASS_DICT(func) PyFunction_GET_CLASS_DICT(_PyObject_CAST(func))
108108

109109
static inline PyObject* PyFunction_GET_MODULE(PyObject *func) {
110110
return _PyFunction_CAST(func)->func_module;

Include/internal/pycore_intrinsics.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
/* Binary Functions: */
1515

1616
#define INTRINSIC_PREP_RERAISE_STAR 1
17+
#define INTRINSIC_SET_CLASS_DICT 2
1718

18-
#define MAX_INTRINSIC_2 1
19+
#define MAX_INTRINSIC_2 2
1920

2021

2122
typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value);

Include/internal/pycore_opcode.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/opcode.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ def pseudo_op(name, op, real_ops):
227227
def_op('CALL_INTRINSIC_1', 173)
228228
def_op('CALL_INTRINSIC_2', 174)
229229

230+
def_op('LOAD_CLASS_DICT', 175)
231+
230232
# Instrumented instructions
231233
MIN_INSTRUMENTED_OPCODE = 238
232234

Objects/frameobject.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,6 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
10711071
}
10721072
PyFrameConstructor desc = {
10731073
.fc_globals = globals,
1074-
.fc_locals = NULL,
10751074
.fc_builtins = builtins,
10761075
.fc_name = code F438 ->co_name,
10771076
.fc_qualname = code->co_name,

Objects/funcobject.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,14 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr)
112112
return NULL;
113113
}
114114
op->func_globals = Py_NewRef(constr->fc_globals);
115-
op->func_locals = Py_XNewRef(constr->fc_locals);
116115
op->func_builtins = Py_NewRef(constr->fc_builtins);
117116
op->func_name = Py_NewRef(constr->fc_name);
118117
op->func_qualname = Py_NewRef(constr->fc_qualname);
119118
op->func_code = Py_NewRef(constr->fc_code);
120119
op->func_defaults = Py_XNewRef(constr->fc_defaults);
121120
op->func_kwdefaults = Py_XNewRef(constr->fc_kwdefaults);
122121
op->func_closure = Py_XNewRef(constr->fc_closure);
122+
op->func_class_dict = NULL;
123123
op->func_doc = Py_NewRef(Py_None);
124124
op->func_dict = NULL;
125125
op->func_weakreflist = NULL;
@@ -191,7 +191,6 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
191191
expect a partially-created object. */
192192

193193
op->func_globals = globals;
194-
op->func_locals = NULL;
195194
op->func_builtins = builtins;
196195
op->func_name = name;
197196
op->func_qualname = qualname;
@@ -204,6 +203,7 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
204203
op->func_weakreflist = NULL;
205204
op->func_module = module;
206205
op->func_annotations = NULL;
206+
op->func_class_dict = NULL;
207207
op->vectorcall = _PyFunction_Vectorcall;
208208
op->func_version = 0;
209209
_PyObject_GC_TRACK(op);
@@ -265,13 +265,13 @@ PyFunction_GetGlobals(PyObject *op)
265265
}
266266

267267
PyObject *
268-
PyFunction_GetLocals(PyObject *op)
268+
PyFunction_GetClassDict(PyObject *op)
269269
{
270270
if (!PyFunction_Check(op)) {
271271
PyErr_BadInternalCall();
272272
return NULL;
273273
}
274-
return ((PyFunctionObject *) op) -> func_locals;
274+
return ((PyFunctionObject *) op) -> func_class_dict;
275275
}
276276

277277
PyObject *
@@ -462,9 +462,9 @@ static PyMemberDef func_memberlist[] = {
462462
{"__closure__", T_OBJECT, OFF(func_closure), READONLY},
463463
{"__doc__", T_OBJECT, OFF(func_doc), 0},
464464
{"__globals__", T_OBJECT, OFF(func_globals), READONLY},
465-
{"__locals__", T_OBJECT, OFF(func_locals), 0},
466465
{"__module__", T_OBJECT, OFF(func_module), 0},
467466
{"__builtins__", T_OBJECT, OFF(func_builtins), READONLY},
467+
{"__class_dict__",T_OBJECT, OFF(func_class_dict), READONLY},
468468
{NULL} /* Sentinel */
469469
};
470470

@@ -788,7 +788,6 @@ func_clear(PyFunctionObject *op)
788788
{
789789
op->func_version = 0;
790790
Py_CLEAR(op->func_globals);
791-
Py_CLEAR(op->func_locals);
792791
Py_CLEAR(op->func_builtins);
793792
Py_CLEAR(op->func_module);
794793
Py_CLEAR(op->func_defaults);
@@ -797,6 +796,7 @@ func_clear(PyFunctionObject *op)
797796
Py_CLEAR(op->func_dict);
798797
Py_CLEAR(op->func_closure);
799798
Py_CLEAR(op->func_annotations);
799+
Py_CLEAR(op->func_class_dict);
800800
// Don't Py_CLEAR(op->func_code), since code is always required
801801
// to be non-NULL. Similarly, name and qualname shouldn't be NULL.
802802
// However, name and qualname could be str subclasses, so they
@@ -842,7 +842,6 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
842842
{
843843
Py_VISIT(f->func_code);
844844
Py_VISIT(f->func_globals);
845-
Py_VISIT(f->func_locals);
846845
Py_VISIT(f->func_builtins);
847846
Py_VISIT(f->func_module);
848847
Py_VISIT(f->func_defaults);
@@ -852,6 +851,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
852851
Py_VISIT(f->func_dict);
853852
Py_VISIT(f->func_closure);
854853
Py_VISIT(f->func_annotations);
854+
Py_VISIT(f->func_class_dict);
855855
Py_VISIT(f->func_qualname);
856856
return 0;
857857
}

Python/bltinmodule.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,6 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
196196
goto error;
197197
}
198198

199-
if (((PyFunctionObject *)func)->func_locals != NULL) {
200-
const char *msg =
201-
"__locals__ not set on class body function defining %.200R";
202-
PyErr_Format(PyExc_RuntimeError, msg, cls);
203-
}
204-
205199
PyThreadState *tstate = _PyThreadState_GET();
206200
EVAL_CALL_STAT_INC(EVAL_CALL_BUILD_CLASS);
207201
cell = _PyEval_Vector(tstate, (PyFunctionObject *)func, ns, NULL, 0, NULL);

Python/bytecodes.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,35 @@ dummy_func(
12191219
}
12201220
}
12211221

1222+
inst(LOAD_CLASS_DICT, ( -- v)) {
1223+
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
1224+
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
1225+
if (func == NULL) {
1226+
_PyErr_Format(tstate, PyExc_SystemError,
1227+
"no function defined when loading %R from class dict", name);
1228+
goto error;
1229+
}
1230+
PyObject *class_dict = func->func_class_dict;
1231+
if (class_dict == NULL) {
1232+
_PyErr_Format(tstate, PyExc_SystemError,
1233+
"no class dict set when loading %R", name);
1234+
goto error;
1235+
}
1236+
if (PyDict_CheckExact(class_dict)) {
1237+
v = PyDict_GetItemWithError(class_dict, name);
1238+
if (v != NULL) {
1239+
Py_INCREF(v);
1240+
}
1241+
}
1242+
else {
1243+
v = PyObject_GetItem(class_dict, name);
1244+
}
1245+
if (_PyErr_Occurred(tstate)) {
1246+
goto error;
1247+
}
1248+
assert(v != NULL);
1249+
}
1250+
12221251
family(load_global, INLINE_CACHE_ENTRIES_LOAD_GLOBAL) = {
12231252
LOAD_GLOBAL,
12241253
LOAD_GLOBAL_MODULE,
@@ -3081,7 +3110,6 @@ dummy_func(
30813110
kwdefaults if (oparg & 0x02),
30823111
annotations if (oparg & 0x04),
30833112
closure if (oparg & 0x08),
3084-
locals if (oparg & 0x20),
30853113
codeobj -- func)) {
30863114

30873115
PyFunctionObject *func_obj = (PyFunctionObject *)
@@ -3092,10 +3120,6 @@ dummy_func(
30923120
goto error;
30933121
}
30943122

3095-
if (oparg & 0x20) {
3096-
assert(PyDict_CheckExact(locals));
3097-
func_obj->func_locals = locals;
3098-
}
30993123
if (oparg & 0x08) {
31003124
assert(PyTuple_CheckExact(closure));
31013125
func_obj->func_closure = closure;

Python/ceval.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,6 @@ PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
549549
}
550550
PyFrameConstructor desc = {
551551
.fc_globals = globals,
552-
.fc_locals = locals,
553552
.fc_builtins = builtins,
554553
.fc_name = ((PyCodeObject *)co)->co_name,
555554
.fc_qualname = ((PyCodeObject *)co)->co_name,
@@ -1584,7 +1583,6 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
15841583
}
15851584
PyFrameConstructor constr = {
15861585
.fc_globals = globals,
1587-
.fc_locals = locals,
15881586
.fc_builtins = builtins,
15891587
.fc_name = ((PyCodeObject *)_co)->co_name,
15901588
.fc_qualname = ((PyCodeObject *)_co)->co_name,

Python/compile.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,14 +1754,6 @@ compiler_make_closure(struct compiler *c, location loc,
17541754
ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars);
17551755
}
17561756

1757-
/* If flag 0x20 is set, we want to bind func_locals
1758-
to the current locals at runtime.
1759-
Push them on the stack in the right spot.
1760-
*/
1761-
if (flags & 0x20) {
1762-
ADDOP(c, loc, LOAD_LOCALS);
1763-
}
1764-
17651757
ADDOP_LOAD_CONST(c, loc, (PyObject*)co);
17661758
ADDOP_I(c, loc, MAKE_FUNCTION, flags);
17671759
return SUCCESS;

0 commit comments

Comments
 (0)
0