diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index a5bc5e7fb6ea71..2f175a54e9090d 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1300,6 +1300,20 @@ iterations of the loop. * 2: ``raise STACK[-2] from STACK[-1]`` (raise exception instance or type at ``STACK[-2]`` with ``__cause__`` set to ``STACK[-1]``) +.. opcode:: COMPREHENSION (flag) + + Calls a comprehension code object, without creating and throwing away a + single-use function object. ``flag`` must be either ``0`` or ``1``, the + latter indicating the comprehension has free variables and a closure tuple + will be on the stack. + + The stack should contain, from bottom to top: + + * a tuple containing cells for free variables, if ``flag`` is set + * the code object for the comprehension + * the single "argument" to the comprehension (the iterated object) + + .. versionadded:: 3.12 .. opcode:: CALL (argc) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 81d16b219c305b..509318d193e6fd 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -53,6 +53,9 @@ typedef struct _PyInterpreterFrame { PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ + // For comprehensions, f_closure and f_code may not match func_closure and + // func_code from f_funcobj above; f_funcobj will be the calling function. + PyObject *f_closure; /* Strong reference, may be NULL. Only valid if not on C stack */ PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ // NOTE: This is not necessarily the last instruction started in the given // frame. Rather, it is the code unit *prior to* the *next* instruction. For @@ -110,12 +113,14 @@ void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest); static inline void _PyFrame_Initialize( _PyInterpreterFrame *frame, PyFunctionObject *func, - PyObject *locals, PyCodeObject *code, int null_locals_from) + PyObject *locals, PyCodeObject *code, PyObject *closure, + int null_locals_from) { frame->f_funcobj = (PyObject *)func; frame->f_code = (PyCodeObject *)Py_NewRef(code); frame->f_builtins = func->func_builtins; frame->f_globals = func->func_globals; + frame->f_closure = Py_XNewRef(closure); frame->f_locals = locals; frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; @@ -248,7 +253,7 @@ _PyFrame_PushUnchecked(PyThreadState *tstate, PyFunctionObject *func, int null_l _PyInterpreterFrame *new_frame = (_PyInterpreterFrame *)tstate->datastack_top; tstate->datastack_top += code->co_framesize; assert(tstate->datastack_top < tstate->datastack_limit); - _PyFrame_Initialize(new_frame, func, NULL, code, null_locals_from); + _PyFrame_Initialize(new_frame, func, NULL, code, func->func_closure, null_locals_from); return new_frame; } diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index f9ab95ca4bb9d3..6c7ca705361ef2 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -110,6 +110,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [COMPARE_AND_BRANCH_INT] = COMPARE_AND_BRANCH, [COMPARE_AND_BRANCH_STR] = COMPARE_AND_BRANCH, [COMPARE_OP] = COMPARE_OP, + [COMPREHENSION] = COMPREHENSION, [CONTAINS_OP] = CONTAINS_OP, [COPY] = COPY, [COPY_FREE_VARS] = COPY_FREE_VARS, @@ -401,7 +402,7 @@ static const char *const _PyOpcode_OpName[263] = { [167] = "<167>", [168] = "<168>", [169] = "<169>", - [170] = "<170>", + [COMPREHENSION] = "COMPREHENSION", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", @@ -502,7 +503,6 @@ static const char *const _PyOpcode_OpName[263] = { case 167: \ case 168: \ case 169: \ - case 170: \ case 175: \ case 176: \ case 177: \ diff --git a/Include/opcode.h b/Include/opcode.h index 760ff945f31f9e..6c5a4ef87063f7 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -113,6 +113,7 @@ extern "C" { #define SET_UPDATE 163 #define DICT_MERGE 164 #define DICT_UPDATE 165 +#define COMPREHENSION 170 #define CALL 171 #define KW_NAMES 172 #define CALL_INTRINSIC_1 173 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 954401cfa85ed3..850c5f2350d5a7 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -434,6 +434,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a5 3518 (Add RETURN_CONST instruction) # Python 3.12a5 3519 (Modify SEND instruction) # Python 3.12a5 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) +# Python 3.12a5 3521 (Add COMPREHENSION instruction) # Python 3.13 will start with 3550 @@ -446,7 +447,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3520).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3521).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 809d24e51676bd..2d6ff505e3c091 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -219,6 +219,7 @@ def pseudo_op(name, op, real_ops): def_op('DICT_MERGE', 164) def_op('DICT_UPDATE', 165) +def_op('COMPREHENSION', 170) def_op('CALL', 171) def_op('KW_NAMES', 172) hasconst.append(172) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 9086824dd6f40c..526bfdbb2d87bc 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -163,10 +163,9 @@ def bug1333982(x=[]): %3d LOAD_ASSERTION_ERROR LOAD_CONST 1 ( at 0x..., file "%s", line %d>) - MAKE_FUNCTION 0 LOAD_FAST 0 (x) GET_ITER - CALL 0 + COMPREHENSION 0 %3d LOAD_CONST 2 (1) @@ -661,10 +660,9 @@ def foo(x): %3d LOAD_CLOSURE 0 (x) BUILD_TUPLE 1 LOAD_CONST 1 ( at 0x..., file "%s", line %d>) - MAKE_FUNCTION 8 (closure) LOAD_DEREF 1 (y) GET_ITER - CALL 0 + COMPREHENSION 1 RETURN_VALUE """ % (dis_nested_0, __file__, diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index ab1a0659471857..6894ce83092769 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1443,7 +1443,7 @@ class C(object): pass def func(): return sys._getframe() x = func() - check(x, size('3Pi3c7P2ic??2P')) + check(x, size('3Pi3c8P2ic??2P')) # function def func(): pass check(func, size('14Pi')) @@ -1460,7 +1460,7 @@ def bar(cls): check(bar, size('PP')) # generator def get_gen(): yield 1 - check(get_gen(), size('P2P4P4c7P2ic??2P')) + check(get_gen(), size('P2P4P4c8P2ic??2P')) # iterator check(iter('abc'), size('lP')) # callable-iterator diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-25-00-55-33.gh-issue-97933.1ET5Ig.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-25-00-55-33.gh-issue-97933.1ET5Ig.rst new file mode 100644 index 00000000000000..9f40e7483a4375 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-25-00-55-33.gh-issue-97933.1ET5Ig.rst @@ -0,0 +1 @@ +New COMPREHENSION bytecode instruction executes a comprehension more efficiently, without allocating a single-use function object. diff --git a/Objects/frame_layout.md b/Objects/frame_layout.md index 2f95214db56498..bc13f83cab5cb2 100644 --- a/Objects/frame_layout.md +++ b/Objects/frame_layout.md @@ -75,6 +75,7 @@ The specials sections contains the following pointers: * Builtins dict * Locals dict (not the "fast" locals, but the locals for eval and class creation) * Code object +* Closure tuple of cells for free variables, if any. * Heap allocated `PyFrameObject` for this activation record, if any. * The function. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 34143c9a40b293..e2e848406ab35a 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -884,6 +884,7 @@ frame_dealloc(PyFrameObject *f) frame->f_code = NULL; Py_CLEAR(frame->f_funcobj); Py_CLEAR(frame->f_locals); + Py_CLEAR(frame->f_closure); PyObject **locals = _PyFrame_GetLocalsArray(frame); for (int i = 0; i < frame->stacktop; i++) { Py_CLEAR(locals[i]); @@ -1022,7 +1023,7 @@ init_frame(_PyInterpreterFrame *frame, PyFunctionObject *func, PyObject *locals) { PyCodeObject *code = (PyCodeObject *)func->func_code; _PyFrame_Initialize(frame, (PyFunctionObject*)Py_NewRef(func), - Py_XNewRef(locals), code, 0); + Py_XNewRef(locals), code, func->func_closure, 0); frame->previous = NULL; } @@ -1125,7 +1126,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame) } /* Free vars have not been initialized -- Do that */ - PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; + PyObject *closure = frame->f_closure; int offset = PyCode_GetFirstFree(co); for (int i = 0; i < co->co_nfreevars; ++i) { PyObject *o = PyTuple_GET_ITEM(closure, i); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c5959f2f994fdc..3e67145226e8f8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1248,8 +1248,7 @@ dummy_func( inst(COPY_FREE_VARS, (--)) { /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; - assert(PyFunction_Check(frame->f_funcobj)); - PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; + PyObject *closure = frame->f_closure; assert(oparg == co->co_nfreevars); int offset = co->co_nlocalsplus - oparg; for (int i = 0; i < oparg; ++i) { @@ -2383,6 +2382,20 @@ dummy_func( kwnames = GETITEM(consts, oparg); } + inst(COMPREHENSION, (closure if (oparg), code, unused -- res)) { + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)Py_NewRef(frame->f_funcobj), code, + closure, NULL, stack_pointer - 1, 1, NULL + ); + Py_XDECREF(code); + Py_XDECREF(closure); + STACK_SHRINK(oparg + 2); + if (new_frame == NULL) { + goto error; + } + DISPATCH_INLINED(new_frame); + } + // Cache layout: counter/1, func_version/2, min_args/1 // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! family(call, INLINE_CACHE_ENTRIES_CALL) = { @@ -2451,8 +2464,9 @@ dummy_func( { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + PyFunctionObject *func = (PyFunctionObject *)callable; _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, (PyFunctionObject *)callable, locals, + tstate, func, func->func_code, func->func_closure, locals, args, positional_args, kwnames ); kwnames = NULL; diff --git a/Python/ceval.c b/Python/ceval.c index b85231a1df8a95..8606b5bdd2b909 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -208,8 +208,8 @@ static void format_awaitable_error(PyThreadState *, PyTypeObject *, int); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); static _PyInterpreterFrame * _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, - PyObject *locals, PyObject* const* args, - size_t argcount, PyObject *kwnames); + PyObject *code, PyObject *closure, PyObject *locals, + PyObject* const* args, size_t argcount, PyObject *kwnames); static void _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame); @@ -744,6 +744,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int entry_frame.frame_obj = (PyFrameObject*)0xaaa2; entry_frame.f_globals = (PyObject*)0xaaa3; entry_frame.f_builtins = (PyObject*)0xaaa4; + entry_frame.f_closure = (PyObject*)0xaaa5; #endif entry_frame.f_code = tstate->interp->interpreter_trampoline; entry_frame.prev_instr = @@ -1382,10 +1383,9 @@ get_exception_handler(PyCodeObject *code, int index, int *level, int *handler, i static int initialize_locals(PyThreadState *tstate, PyFunctionObject *func, - PyObject **localsplus, PyObject *const *args, + PyCodeObject *co, PyObject **localsplus, PyObject *const *args, Py_ssize_t argcount, PyObject *kwnames) { - PyCodeObject *co = (PyCodeObject*)func->func_code; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; /* Create a dictionary for keyword parameters (**kwags) */ @@ -1607,18 +1607,19 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func, /* Consumes references to func, locals and all the args */ static _PyInterpreterFrame * _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, - PyObject *locals, PyObject* const* args, - size_t argcount, PyObject *kwnames) + PyObject *codeobj, PyObject *closure, PyObject *locals, + PyObject* const* args, size_t argcount, PyObject *kwnames) { - PyCodeObject * code = (PyCodeObject *)func->func_code; CALL_STAT_INC(frames_pushed); + assert(PyCode_Check(codeobj)); + PyCodeObject *code = (PyCodeObject *)codeobj; _PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize); if (frame == NULL) { goto fail; } - _PyFrame_Initialize(frame, func, locals, code, 0); + _PyFrame_Initialize(frame, func, locals, code, closure, 0); PyObject **localsarray = &frame->localsplus[0]; - if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) { + if (initialize_locals(tstate, func, code, localsarray, args, argcount, kwnames)) { assert(frame->owner != FRAME_OWNED_BY_GENERATOR); _PyEvalFrameClearAndPop(tstate, frame); return NULL; @@ -1702,7 +1703,8 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func, } } _PyInterpreterFrame *frame = _PyEvalFramePushAndInit( - tstate, func, locals, args, argcount, kwnames); + tstate, func, func->func_code, func->func_closure, locals, + args, argcount, kwnames); if (frame == NULL) { return NULL; } diff --git a/Python/compile.c b/Python/compile.c index 3f620beb0d0205..469607b9706373 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2068,53 +2068,63 @@ compiler_lookup_arg(PyObject *dict, PyObject *name) static int compiler_make_closure(struct compiler *c, location loc, - PyCodeObject *co, Py_ssize_t flags) + PyCodeObject *co) { - if (co->co_nfreevars) { - int i = PyCode_GetFirstFree(co); - for (; i < co->co_nlocalsplus; ++i) { - /* Bypass com_addop_varname because it will generate - LOAD_DEREF but LOAD_CLOSURE is needed. - */ - PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); + int i = PyCode_GetFirstFree(co); + for (; i < co->co_nlocalsplus; ++i) { + /* Bypass com_addop_varname because it will generate + LOAD_DEREF but LOAD_CLOSURE is needed. + */ + PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); - /* Special case: If a class contains a method with a - free variable that has the same name as a method, - the name will be considered free *and* local in the - class. It should be handled by the closure, as - well as by the normal name lookup logic. - */ - int reftype = get_ref_type(c, name); - if (reftype == -1) { - return ERROR; - } - int arg; - if (reftype == CELL) { - arg = compiler_lookup_arg(c->u->u_cellvars, name); - } - else { - arg = compiler_lookup_arg(c->u->u_freevars, name); - } - if (arg == -1) { - PyObject *freevars = _PyCode_GetFreevars(co); - if (freevars == NULL) { - PyErr_Clear(); - } - PyErr_Format(PyExc_SystemError, - "compiler_lookup_arg(name=%R) with reftype=%d failed in %S; " - "freevars of code %S: %R", - name, - reftype, - c->u->u_name, - co->co_name, - freevars); - Py_DECREF(freevars); - return ERROR; + /* Special case: If a class contains a method with a + free variable that has the same name as a method, + the name will be considered free *and* local in the + class. It should be handled by the closure, as + well as by the normal name lookup logic. + */ + int reftype = get_ref_type(c, name); + if (reftype == -1) { + return ERROR; + } + int arg; + if (reftype == CELL) { + arg = compiler_lookup_arg(c->u->u_cellvars, name); + } + else { + arg = compiler_lookup_arg(c->u->u_freevars, name); + } + if (arg == -1) { + PyObject *freevars = _PyCode_GetFreevars(co); + if (freevars == NULL) { + PyErr_Clear(); } - ADDOP_I(c, loc, LOAD_CLOSURE, arg); + PyErr_Format(PyExc_SystemError, + "compiler_lookup_arg(name=%R) with reftype=%d failed in %S; " + "freevars of code %S: %R", + name, + reftype, + c->u->u_name, + co->co_name, + freevars); + Py_DECREF(freevars); + return ERROR; + } + ADDOP_I(c, loc, LOAD_CLOSURE, arg); + } + ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars); + return SUCCESS; +} + +static int +compiler_make_function(struct compiler *c, location loc, + PyCodeObject *co, Py_ssize_t flags) +{ + if (co->co_nfreevars) { + if(compiler_make_closure(c, loc, co) < 0) { + return ERROR; } flags |= 0x08; - ADDOP_I(c, loc, BUILD_TUPLE, co->co_nfreevars); } ADDOP_LOAD_CONST(c, loc, (PyObject*)co); ADDOP_I(c, loc, MAKE_FUNCTION, flags); @@ -2506,7 +2516,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) Py_XDECREF(co); return ERROR; } - if (compiler_make_closure(c, loc, co, funcflags) < 0) { + if (compiler_make_function(c, loc, co, funcflags) < 0) { Py_DECREF(co); return ERROR; } @@ -2609,7 +2619,7 @@ compiler_class(struct compiler *c, stmt_ty s) ADDOP(c, loc, LOAD_BUILD_CLASS); /* 3. load a function (or closure) made from the code object */ - if (compiler_make_closure(c, loc, co, 0) < 0) { + if (compiler_make_function(c, loc, co, 0) < 0) { Py_DECREF(co); return ERROR; } @@ -2870,7 +2880,7 @@ compiler_lambda(struct compiler *c, expr_ty e) return ERROR; } - if (compiler_make_closure(c, loc, co, funcflags) < 0) { + if (compiler_make_function(c, loc, co, funcflags) < 0) { Py_DECREF(co); return ERROR; } @@ -5270,9 +5280,24 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } loc = LOC(e); - if (compiler_make_closure(c, loc, co, 0) < 0) { - goto error; + int oparg = 0; + int opcode = COMPREHENSION; + + if (type == COMP_GENEXP || is_async_generator) { + opcode = CALL; + if (compiler_make_function(c, loc, co, 0) < 0) { + goto error; + } + } else { + if (co->co_nfreevars) { + oparg = 1; + if (compiler_make_closure(c, loc, co) < 0) { + goto error; + } + } + ADDOP_LOAD_CONST(c, loc, (PyObject*)co); } + Py_DECREF(co); VISIT(c, expr, outermost->iter); @@ -5284,7 +5309,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, ADDOP(c, loc, GET_ITER); } - ADDOP_I(c, loc, CALL, 0); + ADDOP_I(c, loc, opcode, oparg); if (is_async_generator && type != COMP_GENEXP) { ADDOP_I(c, loc, GET_AWAITABLE, 0); diff --git a/Python/frame.c b/Python/frame.c index 6a287d4724051a..93feb38ce8cf24 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -15,6 +15,7 @@ _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg) Py_VISIT(frame->f_locals); Py_VISIT(frame->f_funcobj); Py_VISIT(frame->f_code); + Py_VISIT(frame->f_closure); /* locals */ PyObject **locals = _PyFrame_GetLocalsArray(frame); int i = 0; @@ -145,6 +146,7 @@ _PyFrame_Clear(_PyInterpreterFrame *frame) Py_XDECREF(frame->f_locals); Py_DECREF(frame->f_funcobj); Py_DECREF(frame->f_code); + Py_XDECREF(frame->f_closure); } int diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 487e63d855d14a..4151909a0f077f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1566,8 +1566,7 @@ TARGET(COPY_FREE_VARS) { /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; - assert(PyFunction_Check(frame->f_funcobj)); - PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; + PyObject *closure = frame->f_closure; assert(oparg == co->co_nfreevars); int offset = co->co_nlocalsplus - oparg; for (int i = 0; i < oparg; ++i) { @@ -3017,6 +3016,23 @@ DISPATCH(); } + TARGET(COMPREHENSION) { + PyObject *code = PEEK(2); + PyObject *closure = (oparg) ? PEEK(2 + (oparg ? 1 : 0)) : NULL; + PyObject *res; + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)Py_NewRef(frame->f_funcobj), code, + closure, NULL, stack_pointer - 1, 1, NULL + ); + Py_XDECREF(code); + Py_XDECREF(closure); + STACK_SHRINK(oparg + 2); + if (new_frame == NULL) { + goto error; + } + DISPATCH_INLINED(new_frame); + } + TARGET(CALL) { PREDICTED(CALL); static_assert(INLINE_CACHE_ENTRIES_CALL == 4, "incorrect cache size"); @@ -3061,8 +3077,9 @@ { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + PyFunctionObject *func = (PyFunctionObject *)callable; _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, (PyFunctionObject *)callable, locals, + tstate, func, func->func_code, func->func_closure, locals, args, positional_args, kwnames ); kwnames = NULL; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index f27906a3e349eb..80cb62e7275635 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -292,6 +292,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case KW_NAMES: return 0; + case COMPREHENSION: + return (oparg ? 1 : 0) + 2; case CALL: return oparg + 2; case CALL_BOUND_METHOD_EXACT_ARGS: @@ -644,6 +646,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return ((oparg & 1) ? 1 : 0) + 1; case KW_NAMES: return 0; + case COMPREHENSION: + return 1; case CALL: return 1; case CALL_BOUND_METHOD_EXACT_ARGS: @@ -862,6 +866,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [LOAD_ATTR_METHOD_NO_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, [LOAD_ATTR_METHOD_LAZY_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, [KW_NAMES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [COMPREHENSION] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [CALL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, [CALL_BOUND_METHOD_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, [CALL_PY_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index bc64bd582fd572..806e7979e73a64 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -169,7 +169,7 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_COMPREHENSION, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1,