Skip to content

Commit 135cabd

Browse files
authored
bpo-44525: Copy free variables in bytecode to allow calls to inner functions to be specialized (GH-29595)
* Make internal APIs that take PyFrameConstructor take a PyFunctionObject instead. * Add reference to function to frame, borrow references to builtins and globals. * Add COPY_FREE_VARS instruction to allow specialization of calls to inner functions.
1 parent d82f2ca commit 135cabd

25 files changed

+269
-157
lines changed

Doc/library/dis.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,15 @@ All of the following opcodes use their arguments.
991991
``i`` is no longer offset by the length of ``co_varnames``.
992992

993993

994+
.. opcode:: COPY_FREE_VARS (n)
995+
996+
Copies the ``n`` free variables from the closure into the frame.
997+
Removes the need for special code on the caller's side when calling
998+
closures.
999+
1000+
.. versionadded:: 3.11
1001+
1002+
9941003
.. opcode:: RAISE_VARARGS (argc)
9951004

9961005
Raises an exception using one of the 3 forms of the ``raise`` statement,

Include/cpython/funcobject.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
101101
#define PyFunction_GET_ANNOTATIONS(func) \
102102
(((PyFunctionObject *)func) -> func_annotations)
103103

104-
#define PyFunction_AS_FRAME_CONSTRUCTOR(func) \
105-
((PyFrameConstructor *)&((PyFunctionObject *)(func))->func_globals)
106-
107104
/* The classmethod and staticmethod types lives here, too */
108105
PyAPI_DATA(PyTypeObject) PyClassMethod_Type;
109106
PyAPI_DATA(PyTypeObject) PyStaticMethod_Type;

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ _PyEval_EvalFrame(PyThreadState *tstate, struct _interpreter_frame *frame, int t
5252

5353
extern PyObject *
5454
_PyEval_Vector(PyThreadState *tstate,
55-
PyFrameConstructor *desc, PyObject *locals,
55+
PyFunctionObject *func, PyObject *locals,
5656
PyObject* const* args, size_t argcount,
5757
PyObject *kwnames);
5858

@@ -113,7 +113,7 @@ static inline void _Py_LeaveRecursiveCall_inline(void) {
113113

114114
struct _interpreter_frame *_PyEval_GetFrame(void);
115115

116-
PyObject *_Py_MakeCoro(PyFrameConstructor *, struct _interpreter_frame *);
116+
PyObject *_Py_MakeCoro(PyFunctionObject *func, struct _interpreter_frame *);
117117

118118
#ifdef __cplusplus
119119
}

Include/internal/pycore_frame.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ enum _framestate {
2020
typedef signed char PyFrameState;
2121

2222
typedef struct _interpreter_frame {
23-
PyObject *f_globals;
24-
PyObject *f_builtins;
25-
PyObject *f_locals;
26-
PyCodeObject *f_code;
27-
PyFrameObject *frame_obj;
28-
/* Borrowed reference to a generator, or NULL */
29-
PyObject *generator;
23+
PyFunctionObject *f_func; /* Strong reference */
24+
PyObject *f_globals; /* Borrowed reference */
25+
PyObject *f_builtins; /* Borrowed reference */
26+
PyObject *f_locals; /* Strong reference, may be NULL */
27+
PyCodeObject *f_code; /* Strong reference */
28+
PyFrameObject *frame_obj; /* Strong reference, may be NULL */
29+
PyObject *generator; /* Borrowed reference, may be NULL */
3030
struct _interpreter_frame *previous;
3131
int f_lasti; /* Last instruction if called */
3232
int stacktop; /* Offset of TOS from localsplus */
@@ -70,16 +70,18 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
7070
#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
7171

7272
InterpreterFrame *
73-
_PyInterpreterFrame_HeapAlloc(PyFrameConstructor *con, PyObject *locals);
73+
_PyInterpreterFrame_HeapAlloc(PyFunctionObject *func, PyObject *locals);
7474

7575
static inline void
7676
_PyFrame_InitializeSpecials(
77-
InterpreterFrame *frame, PyFrameConstructor *con,
77+
InterpreterFrame *frame, PyFunctionObject *func,
7878
PyObject *locals, int nlocalsplus)
7979
{
80-
frame->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
81-
frame->f_builtins = Py_NewRef(con->fc_builtins);
82-
frame->f_globals = Py_NewRef(con->fc_globals);
80+
Py_INCREF(func);
81+
frame->f_func = func;
82+
frame->f_code = (PyCodeObject *)Py_NewRef(func->func_code);
83+
frame->f_builtins = func->func_builtins;
84+
frame->f_globals = func->func_globals;
8385
frame->f_locals = Py_XNewRef(locals);
8486
frame->stacktop = nlocalsplus;
8587
frame->frame_obj = NULL;
@@ -150,7 +152,7 @@ void
150152
_PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
151153

152154
InterpreterFrame *_PyThreadState_PushFrame(
153-
PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals);
155+
PyThreadState *tstate, PyFunctionObject *func, PyObject *locals);
154156

155157
extern InterpreterFrame *
156158
_PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size);

Include/internal/pycore_function.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef Py_INTERNAL_FUNCTION_H
2+
#define Py_INTERNAL_FUNCTION_H
3+
4+
5+
#include "Python.h"
6+
7+
PyFunctionObject *
8+
_PyFunction_FromConstructor(PyFrameConstructor *constr);
9+
10+
11+
#endif /* !Py_INTERNAL_FUNCTION_H */

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/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ def _write_atomic(path, data, mode=0o666):
370370
# active exception)
371371
# Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into
372372
# BINARY_OP)
373+
# Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
373374

374375
#
375376
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -379,7 +380,7 @@ def _write_atomic(path, data, mode=0o666):
379380
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
380381
# in PC/launcher.c must also be updated.
381382

382-
MAGIC_NUMBER = (3464).to_bytes(2, 'little') + b'\r\n'
383+
MAGIC_NUMBER = (3465).to_bytes(2, 'little') + b'\r\n'
383384
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
384385

385386
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ def jabs_op(name, op):
177177
def_op('MAP_ADD', 147)
178178
def_op('LOAD_CLASSDEREF', 148)
179179
hasfree.append(148)
180+
def_op('COPY_FREE_VARS', 149)
180181

181182
def_op('MATCH_CLASS', 152)
182183

Lib/test/test_code.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@
141141
check_impl_detail, requires_debug_ranges,
142142
gc_collect)
143143
from test.support.script_helper import assert_python_ok
144+
from opcode import opmap
145+
COPY_FREE_VARS = opmap['COPY_FREE_VARS']
144146

145147

146148
def consts(t):
@@ -185,7 +187,7 @@ def create_closure(__class__):
185187

186188
def new_code(c):
187189
'''A new code object with a __class__ cell added to freevars'''
188-
return c.replace(co_freevars=c.co_freevars + ('__class__',))
190+
return c.replace(co_freevars=c.co_freevars + ('__class__',), co_code=bytes([COPY_FREE_VARS, 1])+c.co_code)
189191

190192
def add_foreign_method(cls, name, f):
191193
code = new_code(f.__code__)

Lib/test/test_dis.py

Lines changed: 56 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -459,16 +459,17 @@ def foo(x):
459459

460460
dis_nested_1 = """%s
461461
Disassembly of <code object foo at 0x..., file "%s", line %d>:
462-
0 MAKE_CELL 0 (x)
463-
464-
%3d 2 LOAD_CLOSURE 0 (x)
465-
4 BUILD_TUPLE 1
466-
6 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
467-
8 MAKE_FUNCTION 8 (closure)
468-
10 LOAD_DEREF 1 (y)
469-
12 GET_ITER
470-
14 CALL_FUNCTION 1
471-
16 RETURN_VALUE
462+
0 COPY_FREE_VARS 1
463+
2 MAKE_CELL 0 (x)
464+
465+
%3d 4 LOAD_CLOSURE 0 (x)
466+
6 BUILD_TUPLE 1
467+
8 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
468+
10 MAKE_FUNCTION 8 (closure)
469+
12 LOAD_DEREF 1 (y)
470+
14 GET_ITER
471+
16 CALL_FUNCTION 1
472+
18 RETURN_VALUE
472473
""" % (dis_nested_0,
473474
__file__,
474475
_h.__code__.co_firstlineno + 1,
@@ -479,16 +480,18 @@ def foo(x):
479480

480481
dis_nested_2 = """%s
481482
Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>:
482-
%3d 0 BUILD_LIST 0
483-
2 LOAD_FAST 0 (.0)
484-
>> 4 FOR_ITER 6 (to 18)
485-
6 STORE_FAST 1 (z)
486-
8 LOAD_DEREF 2 (x)
487-
10 LOAD_FAST 1 (z)
488-
12 BINARY_OP 0 (+)
489-
14 LIST_APPEND 2
490-
16 JUMP_ABSOLUTE 2 (to 4)
491-
>> 18 RETURN_VALUE
483+
0 COPY_FREE_VARS 1
484+
485+
%3d 2 BUILD_LIST 0
486+
4 LOAD_FAST 0 (.0)
487+
>> 6 FOR_ITER 6 (to 20)
488+
8 STORE_FAST 1 (z)
489+
10 LOAD_DEREF 2 (x)
490+
12 LOAD_FAST 1 (z)
491+
14 BINARY_OP 0 (+)
492+
16 LIST_APPEND 2
493+
18 JUMP_ABSOLUTE 3 (to 6)
494+
>> 20 RETURN_VALUE
492495
""" % (dis_nested_1,
493496
__file__,
494497
_h.__code__.co_firstlineno + 3,
@@ -1007,42 +1010,43 @@ def _prepare_test_cases():
10071010
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
10081011
]
10091012

1010-
10111013
expected_opinfo_f = [
1012-
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=0, starts_line=None, is_jump_target=False, positions=None),
1013-
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=2, starts_line=None, is_jump_target=False, positions=None),
1014-
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=(5, 6), argrepr='(5, 6)', offset=4, starts_line=3, is_jump_target=False, positions=None),
1015-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False, positions=None),
1016-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False, positions=None),
1017-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=10, starts_line=None, is_jump_target=False, positions=None),
1018-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False, positions=None),
1019-
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None),
1020-
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=16, starts_line=None, is_jump_target=False, positions=None),
1021-
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=18, starts_line=None, is_jump_target=False, positions=None),
1022-
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=20, starts_line=None, is_jump_target=False, positions=None),
1023-
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=22, starts_line=5, is_jump_target=False, positions=None),
1024-
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=24, starts_line=None, is_jump_target=False, positions=None),
1025-
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=26, starts_line=None, is_jump_target=False, positions=None),
1026-
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=28, starts_line=None, is_jump_target=False, positions=None),
1027-
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=30, starts_line=None, is_jump_target=False, positions=None),
1028-
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None),
1029-
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
1030-
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=36, starts_line=6, is_jump_target=False, positions=None),
1031-
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
1014+
Instruction(opname='COPY_FREE_VARS', opcode=149, arg=2, argval=2, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None),
1015+
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=2, starts_line=None, is_jump_target=False, positions=None),
1016+
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, starts_line=None, is_jump_target=False, positions=None),
1017+
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=(5, 6), argrepr='(5, 6)', offset=6, starts_line=3, is_jump_target=False, positions=None),
1018+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=8, starts_line=None, is_jump_target=False, positions=None),
1019+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=10, starts_line=None, is_jump_target=False, positions=None),
1020+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=12, starts_line=None, is_jump_target=False, positions=None),
1021+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=14, starts_line=None, is_jump_target=False, positions=None),
1022+
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
1023+
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=18, starts_line=None, is_jump_target=False, positions=None),
1024+
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=20, starts_line=None, is_jump_target=False, positions=None),
1025+
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=22, starts_line=None, is_jump_target=False, positions=None),
1026+
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=24, starts_line=5, is_jump_target=False, positions=None),
1027+
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=26, starts_line=None, is_jump_target=False, positions=None),
1028+
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False, positions=None),
1029+
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False, positions=None),
1030+
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False, positions=None),
1031+
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
1032+
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
1033+
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False, positions=None),
1034+
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
10321035
]
10331036

10341037
expected_opinfo_inner = [
1035-
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False, positions=None),
1036-
Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False, positions=None),
1037-
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False, positions=None),
1038-
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False, positions=None),
1039-
Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False, positions=None),
1040-
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False, positions=None),
1041-
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False, positions=None),
1042-
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None),
1043-
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
1044-
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False, positions=None),
1045-
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None),
1038+
Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None),
1039+
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=2, starts_line=4, is_jump_target=False, positions=None),
1040+
Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=4, starts_line=None, is_jump_target=False, positions=None),
1041+
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False, positions=None),
1042+
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=8, starts_line=None, is_jump_target=False, positions=None),
1043+
Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=10, starts_line=None, is_jump_target=False, positions=None),
1044+
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=12, starts_line=None, is_jump_target=False, positions=None),
1045+
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False, positions=None),
1046+
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
1047+
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None),
1048+
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=20, starts_line=None, is_jump_target=False, positions=None),
1049+
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
10461050
]
10471051

10481052
expected_opinfo_jumpy = [

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,7 @@ PYTHON_HEADERS= \
16051605
$(srcdir)/Include/internal/pycore_fileutils.h \
16061606
$(srcdir)/Include/internal/pycore_floatobject.h \
16071607
$(srcdir)/Include/internal/pycore_format.h \
1608+
$(srcdir)/Include/internal/pycore_function.h \
16081609
$(srcdir)/Include/internal/pycore_getopt.h \
16091610
$(srcdir)/Include/internal/pycore_gil.h \
16101611
$(srcdir)/Include/internal/pycore_hamt.h \
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Adds new :opcode:`COPY_FREE_VARS` opcode, to make copying of free variables
2+
from function to frame explicit. Helps optimization of calls to Python
3+
function.

Objects/call.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,16 +383,16 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
383383
size_t nargsf, PyObject *kwnames)
384384
{
385385
assert(PyFunction_Check(func));
386-
PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
386+
PyFunctionObject *f = (PyFunctionObject *)func;
387387
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
388388
assert(nargs >= 0);
389389
PyThreadState *tstate = _PyThreadState_GET();
390390
assert(nargs == 0 || stack != NULL);
391-
if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) {
391+
if (((PyCodeObject *)f->func_code)->co_flags & CO_OPTIMIZED) {
392392
return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames);
393393
}
394394
else {
395-
return _PyEval_Vector(tstate, f, f->fc_globals, stack, nargs, kwnames);
395+
return _PyEval_Vector(tstate, f, f->func_globals, stack, nargs, kwnames);
396396
}
397397
}
398398

0 commit comments

Comments
 (0)