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.
This commit is contained in:
Mark Shannon 2021-11-23 09:53:24 +00:00 committed by GitHub
parent d82f2caf94
commit 135cabd328
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 268 additions and 156 deletions

View File

@ -991,6 +991,15 @@ All of the following opcodes use their arguments.
``i`` is no longer offset by the length of ``co_varnames``. ``i`` is no longer offset by the length of ``co_varnames``.
.. opcode:: COPY_FREE_VARS (n)
Copies the ``n`` free variables from the closure into the frame.
Removes the need for special code on the caller's side when calling
closures.
.. versionadded:: 3.11
.. opcode:: RAISE_VARARGS (argc) .. opcode:: RAISE_VARARGS (argc)
Raises an exception using one of the 3 forms of the ``raise`` statement, Raises an exception using one of the 3 forms of the ``raise`` statement,

View File

@ -101,9 +101,6 @@ uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
#define PyFunction_GET_ANNOTATIONS(func) \ #define PyFunction_GET_ANNOTATIONS(func) \
(((PyFunctionObject *)func) -> func_annotations) (((PyFunctionObject *)func) -> func_annotations)
#define PyFunction_AS_FRAME_CONSTRUCTOR(func) \
((PyFrameConstructor *)&((PyFunctionObject *)(func))->func_globals)
/* The classmethod and staticmethod types lives here, too */ /* The classmethod and staticmethod types lives here, too */
PyAPI_DATA(PyTypeObject) PyClassMethod_Type; PyAPI_DATA(PyTypeObject) PyClassMethod_Type;
PyAPI_DATA(PyTypeObject) PyStaticMethod_Type; PyAPI_DATA(PyTypeObject) PyStaticMethod_Type;

View File

@ -52,7 +52,7 @@ _PyEval_EvalFrame(PyThreadState *tstate, struct _interpreter_frame *frame, int t
extern PyObject * extern PyObject *
_PyEval_Vector(PyThreadState *tstate, _PyEval_Vector(PyThreadState *tstate,
PyFrameConstructor *desc, PyObject *locals, PyFunctionObject *func, PyObject *locals,
PyObject* const* args, size_t argcount, PyObject* const* args, size_t argcount,
PyObject *kwnames); PyObject *kwnames);
@ -113,7 +113,7 @@ static inline void _Py_LeaveRecursiveCall_inline(void) {
struct _interpreter_frame *_PyEval_GetFrame(void); struct _interpreter_frame *_PyEval_GetFrame(void);
PyObject *_Py_MakeCoro(PyFrameConstructor *, struct _interpreter_frame *); PyObject *_Py_MakeCoro(PyFunctionObject *func, struct _interpreter_frame *);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -20,13 +20,13 @@ enum _framestate {
typedef signed char PyFrameState; typedef signed char PyFrameState;
typedef struct _interpreter_frame { typedef struct _interpreter_frame {
PyObject *f_globals; PyFunctionObject *f_func; /* Strong reference */
PyObject *f_builtins; PyObject *f_globals; /* Borrowed reference */
PyObject *f_locals; PyObject *f_builtins; /* Borrowed reference */
PyCodeObject *f_code; PyObject *f_locals; /* Strong reference, may be NULL */
PyFrameObject *frame_obj; PyCodeObject *f_code; /* Strong reference */
/* Borrowed reference to a generator, or NULL */ PyFrameObject *frame_obj; /* Strong reference, may be NULL */
PyObject *generator; PyObject *generator; /* Borrowed reference, may be NULL */
struct _interpreter_frame *previous; struct _interpreter_frame *previous;
int f_lasti; /* Last instruction if called */ int f_lasti; /* Last instruction if called */
int stacktop; /* Offset of TOS from localsplus */ int stacktop; /* Offset of TOS from localsplus */
@ -70,16 +70,18 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *)) #define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
InterpreterFrame * InterpreterFrame *
_PyInterpreterFrame_HeapAlloc(PyFrameConstructor *con, PyObject *locals); _PyInterpreterFrame_HeapAlloc(PyFunctionObject *func, PyObject *locals);
static inline void static inline void
_PyFrame_InitializeSpecials( _PyFrame_InitializeSpecials(
InterpreterFrame *frame, PyFrameConstructor *con, InterpreterFrame *frame, PyFunctionObject *func,
PyObject *locals, int nlocalsplus) PyObject *locals, int nlocalsplus)
{ {
frame->f_code = (PyCodeObject *)Py_NewRef(con->fc_code); Py_INCREF(func);
frame->f_builtins = Py_NewRef(con->fc_builtins); frame->f_func = func;
frame->f_globals = Py_NewRef(con->fc_globals); frame->f_code = (PyCodeObject *)Py_NewRef(func->func_code);
frame->f_builtins = func->func_builtins;
frame->f_globals = func->func_globals;
frame->f_locals = Py_XNewRef(locals); frame->f_locals = Py_XNewRef(locals);
frame->stacktop = nlocalsplus; frame->stacktop = nlocalsplus;
frame->frame_obj = NULL; frame->frame_obj = NULL;
@ -150,7 +152,7 @@ void
_PyFrame_LocalsToFast(InterpreterFrame *frame, int clear); _PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
InterpreterFrame *_PyThreadState_PushFrame( InterpreterFrame *_PyThreadState_PushFrame(
PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals); PyThreadState *tstate, PyFunctionObject *func, PyObject *locals);
extern InterpreterFrame * extern InterpreterFrame *
_PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size); _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size);

View File

@ -0,0 +1,11 @@
#ifndef Py_INTERNAL_FUNCTION_H
#define Py_INTERNAL_FUNCTION_H
#include "Python.h"
PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr);
#endif /* !Py_INTERNAL_FUNCTION_H */

1
Include/opcode.h generated
View File

@ -100,6 +100,7 @@ extern "C" {
#define SET_ADD 146 #define SET_ADD 146
#define MAP_ADD 147 #define MAP_ADD 147
#define LOAD_CLASSDEREF 148 #define LOAD_CLASSDEREF 148
#define COPY_FREE_VARS 149
#define MATCH_CLASS 152 #define MATCH_CLASS 152
#define FORMAT_VALUE 155 #define FORMAT_VALUE 155
#define BUILD_CONST_KEY_MAP 156 #define BUILD_CONST_KEY_MAP 156

View File

@ -370,6 +370,7 @@ _code_type = type(_write_atomic.__code__)
# active exception) # active exception)
# Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into # Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into
# BINARY_OP) # BINARY_OP)
# Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
# #
# MAGIC must change whenever the bytecode emitted by the compiler may no # MAGIC must change whenever the bytecode emitted by the compiler may no
@ -379,7 +380,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3464).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3465).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'

View File

@ -177,6 +177,7 @@ def_op('SET_ADD', 146)
def_op('MAP_ADD', 147) def_op('MAP_ADD', 147)
def_op('LOAD_CLASSDEREF', 148) def_op('LOAD_CLASSDEREF', 148)
hasfree.append(148) hasfree.append(148)
def_op('COPY_FREE_VARS', 149)
def_op('MATCH_CLASS', 152) def_op('MATCH_CLASS', 152)

View File

@ -141,6 +141,8 @@ from test.support import (cpython_only,
check_impl_detail, requires_debug_ranges, check_impl_detail, requires_debug_ranges,
gc_collect) gc_collect)
from test.support.script_helper import assert_python_ok from test.support.script_helper import assert_python_ok
from opcode import opmap
COPY_FREE_VARS = opmap['COPY_FREE_VARS']
def consts(t): def consts(t):
@ -185,7 +187,7 @@ class CodeTest(unittest.TestCase):
def new_code(c): def new_code(c):
'''A new code object with a __class__ cell added to freevars''' '''A new code object with a __class__ cell added to freevars'''
return c.replace(co_freevars=c.co_freevars + ('__class__',)) return c.replace(co_freevars=c.co_freevars + ('__class__',), co_code=bytes([COPY_FREE_VARS, 1])+c.co_code)
def add_foreign_method(cls, name, f): def add_foreign_method(cls, name, f):
code = new_code(f.__code__) code = new_code(f.__code__)

View File

@ -459,16 +459,17 @@ dis_nested_0 = """\
dis_nested_1 = """%s dis_nested_1 = """%s
Disassembly of <code object foo at 0x..., file "%s", line %d>: Disassembly of <code object foo at 0x..., file "%s", line %d>:
0 MAKE_CELL 0 (x) 0 COPY_FREE_VARS 1
2 MAKE_CELL 0 (x)
%3d 2 LOAD_CLOSURE 0 (x) %3d 4 LOAD_CLOSURE 0 (x)
4 BUILD_TUPLE 1 6 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>) 8 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
8 MAKE_FUNCTION 8 (closure) 10 MAKE_FUNCTION 8 (closure)
10 LOAD_DEREF 1 (y) 12 LOAD_DEREF 1 (y)
12 GET_ITER 14 GET_ITER
14 CALL_FUNCTION 1 16 CALL_FUNCTION 1
16 RETURN_VALUE 18 RETURN_VALUE
""" % (dis_nested_0, """ % (dis_nested_0,
__file__, __file__,
_h.__code__.co_firstlineno + 1, _h.__code__.co_firstlineno + 1,
@ -479,16 +480,18 @@ Disassembly of <code object foo at 0x..., file "%s", line %d>:
dis_nested_2 = """%s dis_nested_2 = """%s
Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>: Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>:
%3d 0 BUILD_LIST 0 0 COPY_FREE_VARS 1
2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 6 (to 18) %3d 2 BUILD_LIST 0
6 STORE_FAST 1 (z) 4 LOAD_FAST 0 (.0)
8 LOAD_DEREF 2 (x) >> 6 FOR_ITER 6 (to 20)
10 LOAD_FAST 1 (z) 8 STORE_FAST 1 (z)
12 BINARY_OP 0 (+) 10 LOAD_DEREF 2 (x)
14 LIST_APPEND 2 12 LOAD_FAST 1 (z)
16 JUMP_ABSOLUTE 2 (to 4) 14 BINARY_OP 0 (+)
>> 18 RETURN_VALUE 16 LIST_APPEND 2
18 JUMP_ABSOLUTE 3 (to 6)
>> 20 RETURN_VALUE
""" % (dis_nested_1, """ % (dis_nested_1,
__file__, __file__,
_h.__code__.co_firstlineno + 3, _h.__code__.co_firstlineno + 3,
@ -1007,42 +1010,43 @@ expected_opinfo_outer = [
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
] ]
expected_opinfo_f = [ expected_opinfo_f = [
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=0, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='COPY_FREE_VARS', opcode=149, arg=2, argval=2, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=2, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=2, starts_line=None, is_jump_target=False, positions=None),
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), Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=4, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False, positions=None), 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),
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=8, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=10, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=10, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=12, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=14, starts_line=None, is_jump_target=False, positions=None),
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), Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=18, starts_line=None, is_jump_target=False, positions=None), 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),
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=20, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=22, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=22, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=24, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=24, starts_line=5, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=26, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=26, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=28, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=30, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=36, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
] ]
expected_opinfo_inner = [ expected_opinfo_inner = [
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False, positions=None), Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=2, starts_line=4, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=4, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=8, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=10, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=12, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=20, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
] ]
expected_opinfo_jumpy = [ expected_opinfo_jumpy = [

View File

@ -1605,6 +1605,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_fileutils.h \ $(srcdir)/Include/internal/pycore_fileutils.h \
$(srcdir)/Include/internal/pycore_floatobject.h \ $(srcdir)/Include/internal/pycore_floatobject.h \
$(srcdir)/Include/internal/pycore_format.h \ $(srcdir)/Include/internal/pycore_format.h \
$(srcdir)/Include/internal/pycore_function.h \
$(srcdir)/Include/internal/pycore_getopt.h \ $(srcdir)/Include/internal/pycore_getopt.h \
$(srcdir)/Include/internal/pycore_gil.h \ $(srcdir)/Include/internal/pycore_gil.h \
$(srcdir)/Include/internal/pycore_hamt.h \ $(srcdir)/Include/internal/pycore_hamt.h \

View File

@ -0,0 +1,3 @@
Adds new :opcode:`COPY_FREE_VARS` opcode, to make copying of free variables
from function to frame explicit. Helps optimization of calls to Python
function.

View File

@ -383,16 +383,16 @@ _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
size_t nargsf, PyObject *kwnames) size_t nargsf, PyObject *kwnames)
{ {
assert(PyFunction_Check(func)); assert(PyFunction_Check(func));
PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func); PyFunctionObject *f = (PyFunctionObject *)func;
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
assert(nargs >= 0); assert(nargs >= 0);
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
assert(nargs == 0 || stack != NULL); assert(nargs == 0 || stack != NULL);
if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) { if (((PyCodeObject *)f->func_code)->co_flags & CO_OPTIMIZED) {
return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames); return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames);
} }
else { else {
return _PyEval_Vector(tstate, f, f->fc_globals, stack, nargs, kwnames); return _PyEval_Vector(tstate, f, f->func_globals, stack, nargs, kwnames);
} }
} }

View File

@ -5,6 +5,7 @@
#include "pycore_moduleobject.h" // _PyModule_GetDict() #include "pycore_moduleobject.h" // _PyModule_GetDict()
#include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_code.h" // CO_FAST_LOCAL, etc. #include "pycore_code.h" // CO_FAST_LOCAL, etc.
#include "pycore_function.h" // _PyFunction_FromConstructor()
#include "frameobject.h" // PyFrameObject #include "frameobject.h" // PyFrameObject
#include "pycore_frame.h" #include "pycore_frame.h"
@ -626,8 +627,7 @@ frame_dealloc(PyFrameObject *f)
/* Don't clear code object until the end */ /* Don't clear code object until the end */
co = frame->f_code; co = frame->f_code;
frame->f_code = NULL; frame->f_code = NULL;
Py_CLEAR(frame->f_globals); Py_CLEAR(frame->f_func);
Py_CLEAR(frame->f_builtins);
Py_CLEAR(frame->f_locals); Py_CLEAR(frame->f_locals);
PyObject **locals = _PyFrame_GetLocalsArray(frame); PyObject **locals = _PyFrame_GetLocalsArray(frame);
for (int i = 0; i < frame->stacktop; i++) { for (int i = 0; i < frame->stacktop; i++) {
@ -782,16 +782,16 @@ PyTypeObject PyFrame_Type = {
_Py_IDENTIFIER(__builtins__); _Py_IDENTIFIER(__builtins__);
static InterpreterFrame * static InterpreterFrame *
allocate_heap_frame(PyFrameConstructor *con, PyObject *locals) allocate_heap_frame(PyFunctionObject *func, PyObject *locals)
{ {
PyCodeObject *code = (PyCodeObject *)con->fc_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size); InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
if (frame == NULL) { if (frame == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return NULL; return NULL;
} }
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) { for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
frame->localsplus[i] = NULL; frame->localsplus[i] = NULL;
} }
@ -872,7 +872,12 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
.fc_kwdefaults = NULL, .fc_kwdefaults = NULL,
.fc_closure = NULL .fc_closure = NULL
}; };
InterpreterFrame *frame = allocate_heap_frame(&desc, locals); PyFunctionObject *func = _PyFunction_FromConstructor(&desc);
if (func == NULL) {
return NULL;
}
InterpreterFrame *frame = allocate_heap_frame(func, locals);
Py_DECREF(func);
if (frame == NULL) { if (frame == NULL) {
return NULL; return NULL;
} }
@ -910,6 +915,18 @@ _PyFrame_FastToLocalsWithError(InterpreterFrame *frame) {
} }
co = frame->f_code; co = frame->f_code;
fast = _PyFrame_GetLocalsArray(frame); fast = _PyFrame_GetLocalsArray(frame);
if (frame->f_lasti < 0 && _Py_OPCODE(co->co_firstinstr[0]) == COPY_FREE_VARS) {
/* Free vars have not been initialized -- Do that */
PyCodeObject *co = frame->f_code;
PyObject *closure = frame->f_func->func_closure;
int offset = co->co_nlocals + co->co_nplaincellvars;
for (int i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
Py_INCREF(o);
frame->localsplus[offset + i] = o;
}
frame->f_lasti = 0;
}
for (int i = 0; i < co->co_nlocalsplus; i++) { for (int i = 0; i < co->co_nlocalsplus; i++) {
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
@ -929,8 +946,7 @@ _PyFrame_FastToLocalsWithError(InterpreterFrame *frame) {
PyObject *value = fast[i]; PyObject *value = fast[i];
if (frame->f_state != FRAME_CLEARED) { if (frame->f_state != FRAME_CLEARED) {
if (kind & CO_FAST_FREE) { if (kind & CO_FAST_FREE) {
// The cell was set when the frame was created from // The cell was set by COPY_FREE_VARS.
// the function's closure.
assert(value != NULL && PyCell_Check(value)); assert(value != NULL && PyCell_Check(value));
value = PyCell_GET(value); value = PyCell_GET(value);
} }

View File

@ -9,6 +9,39 @@
static uint32_t next_func_version = 1; static uint32_t next_func_version = 1;
PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr)
{
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op == NULL) {
return NULL;
}
Py_INCREF(constr->fc_globals);
op->func_globals = constr->fc_globals;
Py_INCREF(constr->fc_builtins);
op->func_builtins = constr->fc_builtins;
Py_INCREF(constr->fc_name);
op->func_name = constr->fc_name;
Py_INCREF(constr->fc_qualname);
op->func_qualname = constr->fc_qualname;
Py_INCREF(constr->fc_code);
op->func_code = constr->fc_code;
op->func_defaults = NULL;
op->func_kwdefaults = NULL;
op->func_closure = NULL;
Py_INCREF(Py_None);
op->func_doc = Py_None;
op->func_dict = NULL;
op->func_weakreflist = NULL;
op->func_module = NULL;
op->func_annotations = NULL;
op->vectorcall = _PyFunction_Vectorcall;
op->func_version = 0;
_PyObject_GC_TRACK(op);
return op;
}
PyObject * PyObject *
PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname) PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
{ {

View File

@ -188,7 +188,6 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
} }
assert(_PyFrame_IsRunnable(frame)); assert(_PyFrame_IsRunnable(frame));
assert(frame->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(gen->gi_code->co_code))[0] == GEN_START);
/* Push arg onto the frame's value stack */ /* Push arg onto the frame's value stack */
result = arg ? arg : Py_None; result = arg ? arg : Py_None;
Py_INCREF(result); Py_INCREF(result);
@ -841,7 +840,7 @@ PyTypeObject PyGen_Type = {
}; };
static PyObject * static PyObject *
make_gen(PyTypeObject *type, PyFrameConstructor *con, InterpreterFrame *frame) make_gen(PyTypeObject *type, PyFunctionObject *func, InterpreterFrame *frame)
{ {
PyGenObject *gen = PyObject_GC_New(PyGenObject, type); PyGenObject *gen = PyObject_GC_New(PyGenObject, type);
if (gen == NULL) { if (gen == NULL) {
@ -858,13 +857,13 @@ make_gen(PyTypeObject *type, PyFrameConstructor *con, InterpreterFrame *frame)
gen->gi_exc_state.exc_value = NULL; gen->gi_exc_state.exc_value = NULL;
gen->gi_exc_state.exc_traceback = NULL; gen->gi_exc_state.exc_traceback = NULL;
gen->gi_exc_state.previous_item = NULL; gen->gi_exc_state.previous_item = NULL;
if (con->fc_name != NULL) if (func->func_name != NULL)
gen->gi_name = con->fc_name; gen->gi_name = func->func_name;
else else
gen->gi_name = gen->gi_code->co_name; gen->gi_name = gen->gi_code->co_name;
Py_INCREF(gen->gi_name); Py_INCREF(gen->gi_name);
if (con->fc_qualname != NULL) if (func->func_qualname != NULL)
gen->gi_qualname = con->fc_qualname; gen->gi_qualname = func->func_qualname;
else else
gen->gi_qualname = gen->gi_name; gen->gi_qualname = gen->gi_name;
Py_INCREF(gen->gi_qualname); Py_INCREF(gen->gi_qualname);
@ -876,17 +875,17 @@ static PyObject *
compute_cr_origin(int origin_depth); compute_cr_origin(int origin_depth);
PyObject * PyObject *
_Py_MakeCoro(PyFrameConstructor *con, InterpreterFrame *frame) _Py_MakeCoro(PyFunctionObject *func, InterpreterFrame *frame)
{ {
int coro_flags = ((PyCodeObject *)con->fc_code)->co_flags & int coro_flags = ((PyCodeObject *)func->func_code)->co_flags &
(CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
assert(coro_flags); assert(coro_flags);
if (coro_flags == CO_GENERATOR) { if (coro_flags == CO_GENERATOR) {
return make_gen(&PyGen_Type, con, frame); return make_gen(&PyGen_Type, func, frame);
} }
if (coro_flags == CO_ASYNC_GENERATOR) { if (coro_flags == CO_ASYNC_GENERATOR) {
PyAsyncGenObject *o; PyAsyncGenObject *o;
o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, con, frame); o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, func, frame);
if (o == NULL) { if (o == NULL) {
return NULL; return NULL;
} }
@ -897,7 +896,7 @@ _Py_MakeCoro(PyFrameConstructor *con, InterpreterFrame *frame)
return (PyObject*)o; return (PyObject*)o;
} }
assert (coro_flags == CO_COROUTINE); assert (coro_flags == CO_COROUTINE);
PyObject *coro = make_gen(&PyCoro_Type, con, frame); PyObject *coro = make_gen(&PyCoro_Type, func, frame);
if (!coro) { if (!coro) {
return NULL; return NULL;
} }

View File

@ -8936,7 +8936,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
// "firstarg" is a cell here unless (very unlikely) super() // "firstarg" is a cell here unless (very unlikely) super()
// was called from the C-API before the first MAKE_CELL op. // was called from the C-API before the first MAKE_CELL op.
if (f->f_frame->f_lasti >= 0) { if (f->f_frame->f_lasti >= 0) {
assert(_Py_OPCODE(*co->co_firstinstr) == MAKE_CELL); assert(_Py_OPCODE(*co->co_firstinstr) == MAKE_CELL || _Py_OPCODE(*co->co_firstinstr) == COPY_FREE_VARS);
assert(PyCell_Check(firstarg)); assert(PyCell_Check(firstarg));
firstarg = PyCell_GET(firstarg); firstarg = PyCell_GET(firstarg);
} }

View File

@ -193,6 +193,7 @@
<ClInclude Include="..\Include\internal\pycore_fileutils.h" /> <ClInclude Include="..\Include\internal\pycore_fileutils.h" />
<ClInclude Include="..\Include\internal\pycore_floatobject.h" /> <ClInclude Include="..\Include\internal\pycore_floatobject.h" />
<ClInclude Include="..\Include\internal\pycore_format.h" /> <ClInclude Include="..\Include\internal\pycore_format.h" />
<ClInclude Include="..\Include\internal\pycore_function.h" />
<ClInclude Include="..\Include\internal\pycore_gc.h" /> <ClInclude Include="..\Include\internal\pycore_gc.h" />
<ClInclude Include="..\Include\internal\pycore_getopt.h" /> <ClInclude Include="..\Include\internal\pycore_getopt.h" />
<ClInclude Include="..\Include\internal\pycore_gil.h" /> <ClInclude Include="..\Include\internal\pycore_gil.h" />

View File

@ -212,9 +212,8 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
Py_TYPE(ns)->tp_name); Py_TYPE(ns)->tp_name);
goto error; goto error;
} }
PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
PyThreadState *tstate = _PyThreadState_GET(); PyThreadState *tstate = _PyThreadState_GET();
cell = _PyEval_Vector(tstate, f, ns, NULL, 0, NULL); cell = _PyEval_Vector(tstate, (PyFunctionObject *)func, ns, NULL, 0, NULL);
if (cell != NULL) { if (cell != NULL) {
if (bases != orig_bases) { if (bases != orig_bases) {
if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) { if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) {

View File

@ -14,6 +14,7 @@
#include "pycore_call.h" // _PyObject_FastCallDictTstate() #include "pycore_call.h" // _PyObject_FastCallDictTstate()
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc() #include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
#include "pycore_code.h" #include "pycore_code.h"
#include "pycore_function.h"
#include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_long.h" // _PyLong_GetZero() #include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_object.h" // _PyObject_GC_TRACK()
@ -98,7 +99,7 @@ static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwarg
static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int); static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int);
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
static InterpreterFrame * static InterpreterFrame *
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con, _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject* const* args, PyObject *locals, PyObject* const* args,
size_t argcount, PyObject *kwnames); size_t argcount, PyObject *kwnames);
static int static int
@ -1135,7 +1136,13 @@ PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
.fc_kwdefaults = NULL, .fc_kwdefaults = NULL,
.fc_closure = NULL .fc_closure = NULL
}; };
return _PyEval_Vector(tstate, &desc, locals, NULL, 0, NULL); PyFunctionObject *func = _PyFunction_FromConstructor(&desc);
if (func == NULL) {
return NULL;
}
PyObject *res = _PyEval_Vector(tstate, func, locals, NULL, 0, NULL);
Py_DECREF(func);
return res;
} }
@ -1570,7 +1577,7 @@ trace_function_entry(PyThreadState *tstate, InterpreterFrame *frame)
} }
static PyObject * static PyObject *
make_coro(PyThreadState *tstate, PyFrameConstructor *con, make_coro(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject *locals,
PyObject* const* args, size_t argcount, PyObject* const* args, size_t argcount,
PyObject *kwnames); PyObject *kwnames);
@ -2240,7 +2247,7 @@ check_eval_breaker:
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
_PyFrame_InitializeSpecials(new_frame, PyFunction_AS_FRAME_CONSTRUCTOR(getitem), _PyFrame_InitializeSpecials(new_frame, getitem,
NULL, code->co_nlocalsplus); NULL, code->co_nlocalsplus);
STACK_SHRINK(2); STACK_SHRINK(2);
new_frame->localsplus[0] = container; new_frame->localsplus[0] = container;
@ -3179,6 +3186,20 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(COPY_FREE_VARS) {
/* Copy closure variables to free variables */
PyCodeObject *co = frame->f_code;
PyObject *closure = frame->f_func->func_closure;
int offset = co->co_nlocals + co->co_nplaincellvars;
assert(oparg == co->co_nfreevars);
for (int i = 0; i < oparg; ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
Py_INCREF(o);
frame->localsplus[offset + i] = o;
}
DISPATCH();
}
TARGET(BUILD_STRING) { TARGET(BUILD_STRING) {
PyObject *str; PyObject *str;
PyObject *empty = PyUnicode_New(0, 0); PyObject *empty = PyUnicode_New(0, 0);
@ -4423,9 +4444,9 @@ check_eval_breaker:
PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : PyFunction_GET_GLOBALS(function); PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : PyFunction_GET_GLOBALS(function);
STACK_SHRINK(oparg); STACK_SHRINK(oparg);
InterpreterFrame *new_frame = _PyEvalFramePushAndInit( InterpreterFrame *new_frame = _PyEvalFramePushAndInit(
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(function), locals, tstate, (PyFunctionObject *)function, locals,
stack_pointer, stack_pointer, nargs, kwnames
nargs, kwnames); );
STACK_SHRINK(postcall_shrink); STACK_SHRINK(postcall_shrink);
// The frame has stolen all the arguments from the stack, // The frame has stolen all the arguments from the stack,
// so there is no need to clean them up. // so there is no need to clean them up.
@ -4506,7 +4527,7 @@ check_eval_breaker:
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
_PyFrame_InitializeSpecials(new_frame, PyFunction_AS_FRAME_CONSTRUCTOR(func), _PyFrame_InitializeSpecials(new_frame, func,
NULL, code->co_nlocalsplus); NULL, code->co_nlocalsplus);
STACK_SHRINK(argcount); STACK_SHRINK(argcount);
for (int i = 0; i < argcount; i++) { for (int i = 0; i < argcount; i++) {
@ -5426,11 +5447,11 @@ get_exception_handler(PyCodeObject *code, int index, int *level, int *handler, i
} }
static int static int
initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
PyObject **localsplus, PyObject *const *args, PyObject **localsplus, PyObject *const *args,
Py_ssize_t argcount, PyObject *kwnames) Py_ssize_t argcount, PyObject *kwnames)
{ {
PyCodeObject *co = (PyCodeObject*)con->fc_code; PyCodeObject *co = (PyCodeObject*)func->func_code;
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
/* Create a dictionary for keyword parameters (**kwags) */ /* Create a dictionary for keyword parameters (**kwags) */
@ -5495,7 +5516,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (keyword == NULL || !PyUnicode_Check(keyword)) { if (keyword == NULL || !PyUnicode_Check(keyword)) {
_PyErr_Format(tstate, PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%U() keywords must be strings", "%U() keywords must be strings",
con->fc_qualname); func->func_qualname);
goto kw_fail; goto kw_fail;
} }
@ -5527,14 +5548,14 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (co->co_posonlyargcount if (co->co_posonlyargcount
&& positional_only_passed_as_keyword(tstate, co, && positional_only_passed_as_keyword(tstate, co,
kwcount, kwnames, kwcount, kwnames,
con->fc_qualname)) func->func_qualname))
{ {
goto kw_fail; goto kw_fail;
} }
_PyErr_Format(tstate, PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%U() got an unexpected keyword argument '%S'", "%U() got an unexpected keyword argument '%S'",
con->fc_qualname, keyword); func->func_qualname, keyword);
goto kw_fail; goto kw_fail;
} }
@ -5555,7 +5576,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (localsplus[j] != NULL) { if (localsplus[j] != NULL) {
_PyErr_Format(tstate, PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"%U() got multiple values for argument '%S'", "%U() got multiple values for argument '%S'",
con->fc_qualname, keyword); func->func_qualname, keyword);
goto kw_fail; goto kw_fail;
} }
localsplus[j] = value; localsplus[j] = value;
@ -5564,14 +5585,14 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
/* Check the number of positional arguments */ /* Check the number of positional arguments */
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) { if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
too_many_positional(tstate, co, argcount, con->fc_defaults, localsplus, too_many_positional(tstate, co, argcount, func->func_defaults, localsplus,
con->fc_qualname); func->func_qualname);
goto fail_post_args; goto fail_post_args;
} }
/* Add missing positional arguments (copy default values from defs) */ /* Add missing positional arguments (copy default values from defs) */
if (argcount < co->co_argcount) { if (argcount < co->co_argcount) {
Py_ssize_t defcount = con->fc_defaults == NULL ? 0 : PyTuple_GET_SIZE(con->fc_defaults); Py_ssize_t defcount = func->func_defaults == NULL ? 0 : PyTuple_GET_SIZE(func->func_defaults);
Py_ssize_t m = co->co_argcount - defcount; Py_ssize_t m = co->co_argcount - defcount;
Py_ssize_t missing = 0; Py_ssize_t missing = 0;
for (i = argcount; i < m; i++) { for (i = argcount; i < m; i++) {
@ -5581,7 +5602,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
} }
if (missing) { if (missing) {
missing_arguments(tstate, co, missing, defcount, localsplus, missing_arguments(tstate, co, missing, defcount, localsplus,
con->fc_qualname); func->func_qualname);
goto fail_post_args; goto fail_post_args;
} }
if (n > m) if (n > m)
@ -5589,7 +5610,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
else else
i = 0; i = 0;
if (defcount) { if (defcount) {
PyObject **defs = &PyTuple_GET_ITEM(con->fc_defaults, 0); PyObject **defs = &PyTuple_GET_ITEM(func->func_defaults, 0);
for (; i < defcount; i++) { for (; i < defcount; i++) {
if (localsplus[m+i] == NULL) { if (localsplus[m+i] == NULL) {
PyObject *def = defs[i]; PyObject *def = defs[i];
@ -5607,8 +5628,8 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (localsplus[i] != NULL) if (localsplus[i] != NULL)
continue; continue;
PyObject *varname = PyTuple_GET_ITEM(co->co_localsplusnames, i); PyObject *varname = PyTuple_GET_ITEM(co->co_localsplusnames, i);
if (con->fc_kwdefaults != NULL) { if (func->func_kwdefaults != NULL) {
PyObject *def = PyDict_GetItemWithError(con->fc_kwdefaults, varname); PyObject *def = PyDict_GetItemWithError(func->func_kwdefaults, varname);
if (def) { if (def) {
Py_INCREF(def); Py_INCREF(def);
localsplus[i] = def; localsplus[i] = def;
@ -5622,16 +5643,10 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
} }
if (missing) { if (missing) {
missing_arguments(tstate, co, missing, -1, localsplus, missing_arguments(tstate, co, missing, -1, localsplus,
con->fc_qualname); func->func_qualname);
goto fail_post_args; goto fail_post_args;
} }
} }
/* Copy closure variables to free variables */
for (i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i);
Py_INCREF(o);
localsplus[co->co_nlocals + co->co_nplaincellvars + i] = o;
}
return 0; return 0;
fail_pre_positional: fail_pre_positional:
@ -5653,24 +5668,24 @@ fail_post_args:
static InterpreterFrame * static InterpreterFrame *
make_coro_frame(PyThreadState *tstate, make_coro_frame(PyThreadState *tstate,
PyFrameConstructor *con, PyObject *locals, PyFunctionObject *func, PyObject *locals,
PyObject *const *args, Py_ssize_t argcount, PyObject *const *args, Py_ssize_t argcount,
PyObject *kwnames) PyObject *kwnames)
{ {
assert(is_tstate_valid(tstate)); assert(is_tstate_valid(tstate));
assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults)); assert(func->func_defaults == NULL || PyTuple_CheckExact(func->func_defaults));
PyCodeObject *code = (PyCodeObject *)con->fc_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size); InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
if (frame == NULL) { if (frame == NULL) {
goto fail_no_memory; goto fail_no_memory;
} }
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
for (int i = 0; i < code->co_nlocalsplus; i++) { for (int i = 0; i < code->co_nlocalsplus; i++) {
frame->localsplus[i] = NULL; frame->localsplus[i] = NULL;
} }
assert(frame->frame_obj == NULL); assert(frame->frame_obj == NULL);
if (initialize_locals(tstate, con, frame->localsplus, args, argcount, kwnames)) { if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
_PyFrame_Clear(frame, 1); _PyFrame_Clear(frame, 1);
return NULL; return NULL;
} }
@ -5692,17 +5707,17 @@ fail_no_memory:
/* Consumes all the references to the args */ /* Consumes all the references to the args */
static PyObject * static PyObject *
make_coro(PyThreadState *tstate, PyFrameConstructor *con, make_coro(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject *locals,
PyObject* const* args, size_t argcount, PyObject* const* args, size_t argcount,
PyObject *kwnames) PyObject *kwnames)
{ {
assert (((PyCodeObject *)con->fc_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)); assert (((PyCodeObject *)func->func_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR));
InterpreterFrame *frame = make_coro_frame(tstate, con, locals, args, argcount, kwnames); InterpreterFrame *frame = make_coro_frame(tstate, func, locals, args, argcount, kwnames);
if (frame == NULL) { if (frame == NULL) {
return NULL; return NULL;
} }
PyObject *gen = _Py_MakeCoro(con, frame); PyObject *gen = _Py_MakeCoro(func, frame);
if (gen == NULL) { if (gen == NULL) {
return NULL; return NULL;
} }
@ -5711,22 +5726,22 @@ make_coro(PyThreadState *tstate, PyFrameConstructor *con,
/* Consumes all the references to the args */ /* Consumes all the references to the args */
static InterpreterFrame * static InterpreterFrame *
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con, _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject* const* args, PyObject *locals, PyObject* const* args,
size_t argcount, PyObject *kwnames) size_t argcount, PyObject *kwnames)
{ {
PyCodeObject * code = (PyCodeObject *)con->fc_code; PyCodeObject * code = (PyCodeObject *)func->func_code;
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size); InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
if (frame == NULL) { if (frame == NULL) {
goto fail; goto fail;
} }
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
PyObject **localsarray = &frame->localsplus[0]; PyObject **localsarray = &frame->localsplus[0];
for (int i = 0; i < code->co_nlocalsplus; i++) { for (int i = 0; i < code->co_nlocalsplus; i++) {
localsarray[i] = NULL; localsarray[i] = NULL;
} }
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) { if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
_PyFrame_Clear(frame, 0); _PyFrame_Clear(frame, 0);
return NULL; return NULL;
} }
@ -5761,12 +5776,12 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame)
} }
PyObject * PyObject *
_PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con, _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject *locals,
PyObject* const* args, size_t argcount, PyObject* const* args, size_t argcount,
PyObject *kwnames) PyObject *kwnames)
{ {
PyCodeObject *code = (PyCodeObject *)con->fc_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
/* _PyEvalFramePushAndInit and make_coro consume /* _PyEvalFramePushAndInit and make_coro consume
* all the references to their arguments * all the references to their arguments
*/ */
@ -5782,10 +5797,10 @@ _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
int is_coro = code->co_flags & int is_coro = code->co_flags &
(CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
if (is_coro) { if (is_coro) {
return make_coro(tstate, con, locals, args, argcount, kwnames); return make_coro(tstate, func, locals, args, argcount, kwnames);
} }
InterpreterFrame *frame = _PyEvalFramePushAndInit( InterpreterFrame *frame = _PyEvalFramePushAndInit(
tstate, con, locals, args, argcount, kwnames); tstate, func, locals, args, argcount, kwnames);
if (frame == NULL) { if (frame == NULL) {
return NULL; return NULL;
} }
@ -5869,9 +5884,14 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
.fc_kwdefaults = kwdefs, .fc_kwdefaults = kwdefs,
.fc_closure = closure .fc_closure = closure
}; };
res = _PyEval_Vector(tstate, &constr, locals, PyFunctionObject *func = _PyFunction_FromConstructor(&constr);
if (func == NULL) {
return NULL;
}
res = _PyEval_Vector(tstate, func, locals,
allargs, argcount, allargs, argcount,
kwnames); kwnames);
Py_DECREF(func);
if (kwcount) { if (kwcount) {
Py_DECREF(kwnames); Py_DECREF(kwnames);
PyMem_Free(newargs); PyMem_Free(newargs);

View File

@ -1171,6 +1171,7 @@ stack_effect(int opcode, int oparg, int jump)
/* Closures */ /* Closures */
case MAKE_CELL: case MAKE_CELL:
case COPY_FREE_VARS:
return 0; return 0;
case LOAD_CLOSURE: case LOAD_CLOSURE:
return 1; return 1;
@ -7611,7 +7612,7 @@ insert_instruction(basicblock *block, int pos, struct instr *instr) {
static int static int
insert_prefix_instructions(struct compiler *c, basicblock *entryblock, insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
int *fixed) int *fixed, int nfreevars)
{ {
int flags = compute_code_flags(c); int flags = compute_code_flags(c);
@ -7684,6 +7685,22 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
} }
} }
if (nfreevars) {
struct instr copy_frees = {
.i_opcode = COPY_FREE_VARS,
.i_oparg = nfreevars,
.i_lineno = -1,
.i_col_offset = -1,
.i_end_lineno = -1,
.i_end_col_offset = -1,
.i_target = NULL,
};
if (insert_instruction(entryblock, 0, &copy_frees) < 0) {
return -1;
}
}
return 0; return 0;
} }
@ -7818,7 +7835,7 @@ assemble(struct compiler *c, int addNone)
} }
// This must be called before fix_cell_offsets(). // This must be called before fix_cell_offsets().
if (insert_prefix_instructions(c, entryblock, cellfixedoffsets)) { if (insert_prefix_instructions(c, entryblock, cellfixedoffsets, nfreevars)) {
goto error; goto error;
} }

View File

@ -8,9 +8,8 @@ int
_PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg) _PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg)
{ {
Py_VISIT(frame->frame_obj); Py_VISIT(frame->frame_obj);
Py_VISIT(frame->f_globals);
Py_VISIT(frame->f_builtins);
Py_VISIT(frame->f_locals); Py_VISIT(frame->f_locals);
Py_VISIT(frame->f_func);
Py_VISIT(frame->f_code); Py_VISIT(frame->f_code);
/* locals */ /* locals */
PyObject **locals = _PyFrame_GetLocalsArray(frame); PyObject **locals = _PyFrame_GetLocalsArray(frame);
@ -62,8 +61,7 @@ clear_specials(InterpreterFrame *frame)
frame->generator = NULL; frame->generator = NULL;
Py_XDECREF(frame->frame_obj); Py_XDECREF(frame->frame_obj);
Py_XDECREF(frame->f_locals); Py_XDECREF(frame->f_locals);
Py_DECREF(frame->f_globals); Py_DECREF(frame->f_func);
Py_DECREF(frame->f_builtins);
Py_DECREF(frame->f_code); Py_DECREF(frame->f_code);
} }

View File

@ -148,7 +148,7 @@ static void *opcode_targets[256] = {
&&TARGET_SET_ADD, &&TARGET_SET_ADD,
&&TARGET_MAP_ADD, &&TARGET_MAP_ADD,
&&TARGET_LOAD_CLASSDEREF, &&TARGET_LOAD_CLASSDEREF,
&&_unknown_opcode, &&TARGET_COPY_FREE_VARS,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_MATCH_CLASS, &&TARGET_MATCH_CLASS,

View File

@ -2087,9 +2087,9 @@ _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size)
InterpreterFrame * InterpreterFrame *
_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals) _PyThreadState_PushFrame(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals)
{ {
PyCodeObject *code = (PyCodeObject *)con->fc_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
int nlocalsplus = code->co_nlocalsplus; int nlocalsplus = code->co_nlocalsplus;
size_t size = nlocalsplus + code->co_stacksize + size_t size = nlocalsplus + code->co_stacksize +
FRAME_SPECIALS_SIZE; FRAME_SPECIALS_SIZE;
@ -2097,7 +2097,7 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObjec
if (frame == NULL) { if (frame == NULL) {
return NULL; return NULL;
} }
_PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus); _PyFrame_InitializeSpecials(frame, func, locals, nlocalsplus);
for (int i=0; i < nlocalsplus; i++) { for (int i=0; i < nlocalsplus; i++) {
frame->localsplus[i] = NULL; frame->localsplus[i] = NULL;
} }

View File

@ -479,7 +479,7 @@ initial_counter_value(void) {
#define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 9 #define SPEC_FAIL_WRONG_NUMBER_ARGUMENTS 9
#define SPEC_FAIL_CO_NOT_OPTIMIZED 10 #define SPEC_FAIL_CO_NOT_OPTIMIZED 10
/* SPEC_FAIL_METHOD defined as 11 above */ /* SPEC_FAIL_METHOD defined as 11 above */
#define SPEC_FAIL_FREE_VARS 12
#define SPEC_FAIL_PYCFUNCTION 13 #define SPEC_FAIL_PYCFUNCTION 13
#define SPEC_FAIL_PYCFUNCTION_WITH_KEYWORDS 14 #define SPEC_FAIL_PYCFUNCTION_WITH_KEYWORDS 14
#define SPEC_FAIL_PYCFUNCTION_FAST_WITH_KEYWORDS 15 #define SPEC_FAIL_PYCFUNCTION_FAST_WITH_KEYWORDS 15
@ -1158,9 +1158,6 @@ function_kind(PyCodeObject *code) {
if ((flags & CO_OPTIMIZED) == 0) { if ((flags & CO_OPTIMIZED) == 0) {
return SPEC_FAIL_CO_NOT_OPTIMIZED; return SPEC_FAIL_CO_NOT_OPTIMIZED;
} }
if (code->co_nfreevars) {
return SPEC_FAIL_FREE_VARS;
}
return SIMPLE_FUNCTION; return SIMPLE_FUNCTION;
} }