diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 0cf49f06c87732..3fe38a586f82e9 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -54,6 +54,7 @@ typedef struct { * - co_posonlyargcount \ * - co_kwonlyargcount \ * - co_nlocals \ + * - co_ntmps * - co_stacksize \ * - co_flags \ * - co_firstlineno \ @@ -79,6 +80,7 @@ typedef struct { int co_argcount; /* #arguments, except *args */ \ int co_posonlyargcount; /* #positional only arguments */ \ int co_kwonlyargcount; /* #keyword only arguments */ \ + int co_ntmps; /* number of tmps needed for evaluation */ \ int co_stacksize; /* #entries needed for evaluation stack */ \ int co_firstlineno; /* first source line number */ \ \ @@ -166,13 +168,13 @@ static inline int PyCode_GetFirstFree(PyCodeObject *op) { /* Public interface */ PyAPI_FUNC(PyCodeObject *) PyCode_New( - int, int, int, int, int, PyObject *, PyObject *, + int, int, int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *, PyObject *); PyAPI_FUNC(PyCodeObject *) PyCode_NewWithPosOnlyArgs( - int, int, int, int, int, int, PyObject *, PyObject *, + int, int, int, int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *, PyObject *); diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index a287250acc1912..1876863352fbf3 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -171,6 +171,7 @@ struct _PyCodeConstructor { int kwonlyargcount; /* needed to create the frame */ + int ntmps; int stacksize; /* used by the eval loop */ @@ -466,6 +467,7 @@ _PyCode_LineNumberFromArray(PyCodeObject *co, int index) typedef struct _PyShimCodeDef { const uint8_t *code; int codelen; + int ntmps; int stacksize; const char *cname; } _PyShimCodeDef; diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index f12b225ebfccf2..2d6544fb5675d3 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -71,18 +71,23 @@ typedef struct _PyInterpreterFrame { #define _PyInterpreterFrame_LASTI(IF) \ ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) +static inline int _PyFrame_StackbaseIndex(_PyInterpreterFrame *f) { + PyCodeObject *code = f->f_code; + return code->co_nlocalsplus + code->co_ntmps; +} + static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { - return f->localsplus + f->f_code->co_nlocalsplus; + return f->localsplus + _PyFrame_StackbaseIndex(f); } static inline PyObject *_PyFrame_StackPeek(_PyInterpreterFrame *f) { - assert(f->stacktop > f->f_code->co_nlocalsplus); + assert(f->stacktop > _PyFrame_StackbaseIndex(f)); assert(f->localsplus[f->stacktop-1] != NULL); return f->localsplus[f->stacktop-1]; } static inline PyObject *_PyFrame_StackPop(_PyInterpreterFrame *f) { - assert(f->stacktop > f->f_code->co_nlocalsplus); + assert(f->stacktop > _PyFrame_StackbaseIndex(f)); f->stacktop--; return f->localsplus[f->stacktop]; } @@ -97,10 +102,10 @@ static inline void _PyFrame_StackPush(_PyInterpreterFrame *f, PyObject *value) { static inline int _PyFrame_NumSlotsForCodeObject(PyCodeObject *code) { - /* This function needs to remain in sync with the calculation of - * co_framesize in Tools/build/deepfreeze.py */ assert(code->co_framesize >= FRAME_SPECIALS_SIZE); - return code->co_framesize - FRAME_SPECIALS_SIZE; + int nslots = code->co_framesize - FRAME_SPECIALS_SIZE; + assert(nslots == code->co_nlocalsplus + code->co_ntmps + code->co_stacksize); + return nslots; } void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest); @@ -119,13 +124,14 @@ _PyFrame_Initialize( frame->f_builtins = func->func_builtins; frame->f_globals = func->func_globals; frame->f_locals = locals; - frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; frame->prev_instr = _PyCode_CODE(code) - 1; frame->yield_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; - for (int i = null_locals_from; i < code->co_nlocalsplus; i++) { + int stack_start = _PyFrame_StackbaseIndex(frame); + frame->stacktop = stack_start; + for (int i = null_locals_from; i < stack_start; i++) { frame->localsplus[i] = NULL; } } @@ -142,7 +148,7 @@ _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame) static inline PyObject** _PyFrame_GetStackPointer(_PyInterpreterFrame *frame) { - return frame->localsplus+frame->stacktop; + return frame->localsplus + frame->stacktop; } static inline void diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index a5365d53150b4f..b409658647ef54 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -838,6 +838,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_name)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_names)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_nlocals)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_ntmps)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_posonlyargcount)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_qualname)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(co_stacksize)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 3d9e61e50eccaa..4463076db3c4eb 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -324,6 +324,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(co_name) STRUCT_FOR_ID(co_names) STRUCT_FOR_ID(co_nlocals) + STRUCT_FOR_ID(co_ntmps) STRUCT_FOR_ID(co_posonlyargcount) STRUCT_FOR_ID(co_qualname) STRUCT_FOR_ID(co_stacksize) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 05c0485b0641d8..322cd68a7d99c5 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -194,6 +194,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [RESUME] = RESUME, [RETURN_GENERATOR] = RETURN_GENERATOR, [RETURN_VALUE] = RETURN_VALUE, + [RETURN_VALUE_R] = RETURN_VALUE_R, [SEND] = SEND, [SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS, [SET_ADD] = SET_ADD, @@ -371,7 +372,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [RETURN_VALUE_R] = "RETURN_VALUE_R", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -381,15 +382,15 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [161] = "<161>", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", @@ -495,7 +496,6 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ - case 161: \ case 166: \ case 167: \ case 168: \ diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 3534b94753e0d3..a55d55e8f431a0 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -830,6 +830,7 @@ extern "C" { INIT_ID(co_name), \ INIT_ID(co_names), \ INIT_ID(co_nlocals), \ + INIT_ID(co_ntmps), \ INIT_ID(co_posonlyargcount), \ INIT_ID(co_qualname), \ INIT_ID(co_stacksize), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 02435071bb2cff..063400d67044af 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -554,6 +554,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(co_nlocals); PyUnicode_InternInPlace(&string); + string = &_Py_ID(co_ntmps); + PyUnicode_InternInPlace(&string); string = &_Py_ID(co_posonlyargcount); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_qualname); diff --git a/Include/opcode.h b/Include/opcode.h index 827f9931beb3e6..569c0c521bed0d 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -97,6 +97,7 @@ extern "C" { #define JUMP_BACKWARD 140 #define COMPARE_AND_BRANCH 141 #define CALL_FUNCTION_EX 142 +#define RETURN_VALUE_R 143 #define EXTENDED_ARG 144 #define LIST_APPEND 145 #define SET_ADD 146 @@ -180,12 +181,12 @@ extern "C" { #define STORE_ATTR_SLOT 87 #define STORE_ATTR_WITH_HINT 113 #define STORE_FAST__LOAD_FAST 121 -#define STORE_FAST__STORE_FAST 143 -#define STORE_SUBSCR_DICT 153 -#define STORE_SUBSCR_LIST_INT 154 -#define UNPACK_SEQUENCE_LIST 158 -#define UNPACK_SEQUENCE_TUPLE 159 -#define UNPACK_SEQUENCE_TWO_TUPLE 160 +#define STORE_FAST__STORE_FAST 153 +#define STORE_SUBSCR_DICT 154 +#define STORE_SUBSCR_LIST_INT 158 +#define UNPACK_SEQUENCE_LIST 159 +#define UNPACK_SEQUENCE_TUPLE 160 +#define UNPACK_SEQUENCE_TWO_TUPLE 161 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 5a8cbb98ed3f56..c34c192e172b8c 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -430,6 +430,8 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a1 3514 (Remove ASYNC_GEN_WRAP, LIST_TO_TUPLE, and UNARY_POSITIVE) # Python 3.12a1 3515 (Embed jump mask in COMPARE_OP oparg) # Python 3.12a1 3516 (Add COMAPRE_AND_BRANCH instruction) +# Python 3.12a1 3517 (Add ntmps to code object) +# Python 3.12a1 3518 (Add RETURN_VALUE_R) # Python 3.13 will start with 3550 @@ -442,7 +444,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 = (3516).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3518).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 c317e23beae62b..f7481714e2aa01 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -197,6 +197,8 @@ def pseudo_op(name, op, real_ops): def_op('CALL_FUNCTION_EX', 142) # Flags +def_op('RETURN_VALUE_R', 143) + def_op('EXTENDED_ARG', 144) EXTENDED_ARG = 144 def_op('LIST_APPEND', 145) diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index c17528be97b484..aab7b1580eaf35 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -934,6 +934,16 @@ def c_py_recurse(m): finally: sys.setrecursionlimit(depth) +class TestFunctionWithManyArgs(unittest.TestCase): + def test_function_with_many_args(self): + for N in (10, 500, 1000): + with self.subTest(N=N): + args = ",".join([f"a{i}" for i in range(N)]) + src = f"def f({args}) : return a{N//2}" + l = {} + exec(src, {}, l) + self.assertEqual(l['f'](*range(N)), N//2) + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index 67ed1694205cd6..8fc412c7f77137 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -225,6 +225,7 @@ def func(): pass co.co_posonlyargcount, co.co_kwonlyargcount, co.co_nlocals, + co.co_ntmps, co.co_stacksize, co.co_flags, co.co_code, @@ -264,6 +265,7 @@ def func2(): ("co_posonlyargcount", 0), ("co_kwonlyargcount", 0), ("co_nlocals", 1), + ("co_ntmps", 13), ("co_stacksize", 0), ("co_flags", code.co_flags | inspect.CO_COROUTINE), ("co_firstlineno", 100), @@ -302,6 +304,7 @@ def func(): co.co_kwonlyargcount, # This is the only change. co.co_nlocals + diff, + co.co_ntmps, co.co_stacksize, co.co_flags, co.co_code, diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 05a5ed1fa9a637..95e91266d920a6 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -738,10 +738,10 @@ def unused_code_at_end(): raise RuntimeError("unreachable") # The above function definition will trigger the out of bounds # bug in the peephole optimizer as it scans opcodes past the - # RETURN_VALUE opcode. This does not always crash an interpreter. + # RETURN_VALUE_R opcode. This does not always crash an interpreter. # When you build with the clang memory sanitizer it reliably aborts. self.assertEqual( - 'RETURN_VALUE', + 'RETURN_VALUE_R', list(dis.get_instructions(unused_code_at_end))[-1].opname) def test_dont_merge_constants(self): @@ -822,10 +822,10 @@ def unused_block_while_else(): for func in funcs: opcodes = list(dis.get_instructions(func)) - self.assertLessEqual(len(opcodes), 4) - self.assertEqual('LOAD_CONST', opcodes[-2].opname) - self.assertEqual(None, opcodes[-2].argval) - self.assertEqual('RETURN_VALUE', opcodes[-1].opname) + self.assertLessEqual(len(opcodes), 5) + self.assertEqual('LOAD_CONST', opcodes[-3].opname) + self.assertEqual(None, opcodes[-3].argval) + self.assertEqual('RETURN_VALUE_R', opcodes[-1].opname) def test_false_while_loop(self): def break_in_while(): @@ -841,10 +841,10 @@ def continue_in_while(): # Check that we did not raise but we also don't generate bytecode for func in funcs: opcodes = list(dis.get_instructions(func)) - self.assertEqual(3, len(opcodes)) + self.assertEqual(4, len(opcodes)) self.assertEqual('LOAD_CONST', opcodes[1].opname) self.assertEqual(None, opcodes[1].argval) - self.assertEqual('RETURN_VALUE', opcodes[2].opname) + self.assertEqual('RETURN_VALUE_R', opcodes[3].opname) def test_consts_in_conditionals(self): def and_true(x): @@ -865,9 +865,9 @@ def or_false(x): for func in funcs: with self.subTest(func=func): opcodes = list(dis.get_instructions(func)) - self.assertLessEqual(len(opcodes), 3) - self.assertIn('LOAD_', opcodes[-2].opname) - self.assertEqual('RETURN_VALUE', opcodes[-1].opname) + self.assertLessEqual(len(opcodes), 4) + self.assertIn('LOAD_', opcodes[-3].opname) + self.assertEqual('RETURN_VALUE_R', opcodes[-1].opname) def test_imported_load_method(self): sources = [ @@ -1311,7 +1311,7 @@ def test_multiline_generator_expression(self): line=1, end_line=2, column=1, end_column=8, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=8, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_generator_expression(self): @@ -1328,7 +1328,7 @@ def test_multiline_async_generator_expression(self): self.assertIsInstance(compiled_code, types.CodeType) self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE', line=1, end_line=2, column=1, end_column=8, occurrence=2) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_list_comprehension(self): @@ -1347,7 +1347,7 @@ def test_multiline_list_comprehension(self): line=1, end_line=2, column=1, end_column=8, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=8, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_list_comprehension(self): @@ -1369,7 +1369,7 @@ async def f(): line=2, end_line=3, column=5, end_column=12, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=2, end_line=3, column=5, end_column=12, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=2, end_line=7, column=4, end_column=36, occurrence=1) def test_multiline_set_comprehension(self): @@ -1388,7 +1388,7 @@ def test_multiline_set_comprehension(self): line=1, end_line=2, column=1, end_column=8, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=8, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_set_comprehension(self): @@ -1410,7 +1410,7 @@ async def f(): line=2, end_line=3, column=5, end_column=12, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=2, end_line=3, column=5, end_column=12, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=2, end_line=7, column=4, end_column=36, occurrence=1) def test_multiline_dict_comprehension(self): @@ -1429,7 +1429,7 @@ def test_multiline_dict_comprehension(self): line=1, end_line=2, column=1, end_column=7, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=1, end_line=2, column=1, end_column=7, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=1, end_line=6, column=0, end_column=32, occurrence=1) def test_multiline_async_dict_comprehension(self): @@ -1451,7 +1451,7 @@ async def f(): line=2, end_line=3, column=5, end_column=11, occurrence=1) self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD', line=2, end_line=3, column=5, end_column=11, occurrence=1) - self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE', + self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE_R', line=2, end_line=7, column=4, end_column=36, occurrence=1) def test_matchcase_sequence(self): diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 27487de8fb3d81..a000752a6cb2ab 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -50,7 +50,8 @@ def cm(cls, x): LOAD_FAST 0 (self) STORE_ATTR 0 (x) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 """ % (_C.__init__.__code__.co_firstlineno, _C.__init__.__code__.co_firstlineno + 1,) dis_c_instance_method_bytes = """\ @@ -61,7 +62,8 @@ def cm(cls, x): LOAD_FAST 0 STORE_ATTR 0 LOAD_CONST 0 - RETURN_VALUE + STORE_FAST 2 + RETURN_VALUE_R 2 """ dis_c_class_method = """\ @@ -73,7 +75,8 @@ def cm(cls, x): LOAD_FAST 0 (cls) STORE_ATTR 0 (x) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 """ % (_C.cm.__code__.co_firstlineno, _C.cm.__code__.co_firstlineno + 2,) dis_c_static_method = """\ @@ -84,7 +87,8 @@ def cm(cls, x): COMPARE_OP 32 (==) STORE_FAST 0 (x) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 1 ($0) + RETURN_VALUE_R 1 """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) # Class disassembling info has an extra newline at end. @@ -112,7 +116,8 @@ def _f(a): POP_TOP %3d LOAD_CONST 1 (1) - RETURN_VALUE + STORE_FAST 1 ($0) + RETURN_VALUE_R 1 """ % (_f.__code__.co_firstlineno, _f.__code__.co_firstlineno + 1, _f.__code__.co_firstlineno + 2) @@ -125,7 +130,8 @@ def _f(a): CALL 1 POP_TOP LOAD_CONST 1 - RETURN_VALUE + STORE_FAST 1 + RETURN_VALUE_R 1 """ @@ -151,7 +157,8 @@ def bug708901(): %3d >> END_FOR LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 1 ($0) + RETURN_VALUE_R 1 """ % (bug708901.__code__.co_firstlineno, bug708901.__code__.co_firstlineno + 1, bug708901.__code__.co_firstlineno + 2, @@ -199,7 +206,8 @@ def bug42562(): dis_bug42562 = """\ RESUME 0 LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ # Extended arg followed by NOP @@ -208,7 +216,7 @@ def bug42562(): 0x09, 0xFF, # NOP 0xFF 0x90, 0x01, # EXTENDED_ARG 0x01 0x64, 0x29, # LOAD_CONST 0x29 - 0x53, 0x00, # RETURN_VALUE 0x00 + 0x8f, 0x00, # RETURN_VALUE_R 0x00 ]) dis_bug_45757 = """\ @@ -216,7 +224,7 @@ def bug42562(): NOP EXTENDED_ARG 1 LOAD_CONST 297 - RETURN_VALUE + RETURN_VALUE_R 0 """ # [255, 255, 255, 252] is -4 in a 4 byte signed integer @@ -241,7 +249,8 @@ def bug42562(): %3d LOAD_GLOBAL 0 (spam) POP_TOP LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ _BIG_LINENO_FORMAT2 = """\ @@ -250,19 +259,22 @@ def bug42562(): %4d LOAD_GLOBAL 0 (spam) POP_TOP LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ dis_module_expected_results = """\ Disassembly of f: 4 RESUME 0 LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 Disassembly of g: 5 RESUME 0 LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ @@ -274,7 +286,8 @@ def bug42562(): 1 LOAD_NAME 0 (x) LOAD_CONST 0 (1) BINARY_OP 0 (+) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ simple_stmt_str = "x = x + 1" @@ -287,7 +300,8 @@ def bug42562(): BINARY_OP 0 (+) STORE_NAME 0 (x) LOAD_CONST 1 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ annot_stmt_str = """\ @@ -327,7 +341,8 @@ def bug42562(): LOAD_NAME 1 (int) POP_TOP LOAD_CONST 4 (None) - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ compound_stmt_str = """\ @@ -363,12 +378,13 @@ def bug42562(): POP_TOP %3d LOAD_FAST_CHECK 1 (tb) - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 >> PUSH_EXC_INFO %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 23 (to 82) + POP_JUMP_IF_FALSE 24 (to 86) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -380,7 +396,8 @@ def bug42562(): DELETE_FAST 0 (e) %3d LOAD_FAST 1 (tb) - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 >> LOAD_CONST 0 (None) STORE_FAST 0 (e) DELETE_FAST 0 (e) @@ -421,7 +438,8 @@ def _fstring(a, b, c, d): LOAD_CONST 2 ('4') FORMAT_VALUE 6 (repr, with format) BUILD_STRING 7 - RETURN_VALUE + STORE_FAST 4 ($0) + RETURN_VALUE_R 4 """ % (_fstring.__code__.co_firstlineno, _fstring.__code__.co_firstlineno + 1) def _with(c): @@ -448,11 +466,12 @@ def _with(c): %3d LOAD_CONST 2 (2) STORE_FAST 2 (y) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 3 ($0) + RETURN_VALUE_R 3 %3d >> PUSH_EXC_INFO WITH_EXCEPT_START - POP_JUMP_IF_TRUE 1 (to 46) + POP_JUMP_IF_TRUE 1 (to 48) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -462,7 +481,8 @@ def _with(c): %3d LOAD_CONST 2 (2) STORE_FAST 2 (y) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 3 ($0) + RETURN_VALUE_R 3 >> COPY 3 POP_EXCEPT RERAISE 1 @@ -515,22 +535,23 @@ async def _asyncwith(c): %3d LOAD_CONST 2 (2) STORE_FAST 2 (y) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 3 ($0) + RETURN_VALUE_R 3 %3d >> CLEANUP_THROW - JUMP_BACKWARD 24 (to 22) + JUMP_BACKWARD 25 (to 22) >> CLEANUP_THROW - JUMP_BACKWARD 9 (to 56) + JUMP_BACKWARD 10 (to 56) >> PUSH_EXC_INFO WITH_EXCEPT_START GET_AWAITABLE 2 LOAD_CONST 0 (None) - >> SEND 4 (to 92) + >> SEND 4 (to 94) YIELD_VALUE 6 RESUME 3 - JUMP_BACKWARD_NO_INTERRUPT 4 (to 82) + JUMP_BACKWARD_NO_INTERRUPT 4 (to 84) >> CLEANUP_THROW - >> POP_JUMP_IF_TRUE 1 (to 96) + >> POP_JUMP_IF_TRUE 1 (to 98) RERAISE 2 >> POP_TOP POP_EXCEPT @@ -540,7 +561,8 @@ async def _asyncwith(c): %3d LOAD_CONST 2 (2) STORE_FAST 2 (y) LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 3 ($0) + RETURN_VALUE_R 3 >> COPY 3 POP_EXCEPT RERAISE 1 @@ -581,7 +603,8 @@ def _tryfinallyconst(b): LOAD_FAST 1 (b) CALL 0 POP_TOP - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 >> PUSH_EXC_INFO PUSH_NULL LOAD_FAST 1 (b) @@ -611,7 +634,8 @@ def _tryfinallyconst(b): CALL 0 POP_TOP LOAD_CONST 1 (1) - RETURN_VALUE + STORE_FAST 1 ($0) + RETURN_VALUE_R 1 PUSH_EXC_INFO PUSH_NULL LOAD_FAST 0 (b) @@ -657,7 +681,8 @@ def foo(x): STORE_FAST 1 (foo) %3d LOAD_FAST 1 (foo) - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 """ % (_h.__code__.co_firstlineno, _h.__code__.co_firstlineno + 1, __file__, @@ -679,7 +704,8 @@ def foo(x): LOAD_DEREF 1 (y) GET_ITER CALL 0 - RETURN_VALUE + STORE_FAST 2 ($0) + RETURN_VALUE_R 2 """ % (dis_nested_0, __file__, _h.__code__.co_firstlineno + 1, @@ -704,7 +730,8 @@ def foo(x): LIST_APPEND 2 JUMP_BACKWARD 9 (to 8) >> END_FOR - RETURN_VALUE + STORE_FAST 3 ($0) + RETURN_VALUE_R 3 """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, @@ -726,7 +753,8 @@ def load_test(x, y=0): %3d 10 LOAD_FAST__LOAD_FAST 2 (a) 12 LOAD_FAST 3 (b) 14 BUILD_TUPLE 2 - 16 RETURN_VALUE + 16 STORE_FAST 4 ($0) + 18 RETURN_VALUE_R 4 """ % (load_test.__code__.co_firstlineno, load_test.__code__.co_firstlineno + 1, load_test.__code__.co_firstlineno + 2) @@ -755,7 +783,8 @@ def loop_test(): %3d >> END_FOR LOAD_CONST 0 (None) - RETURN_VALUE + STORE_FAST 1 ($0) + RETURN_VALUE_R 1 """ % (loop_test.__code__.co_firstlineno, loop_test.__code__.co_firstlineno + 1, loop_test.__code__.co_firstlineno + 2, @@ -773,7 +802,8 @@ def extended_arg_quick(): 8 STORE_FAST 0 (_) 10 STORE_FAST 0 (_) 12 LOAD_CONST 0 (None) - 14 RETURN_VALUE + 14 STORE_FAST 1 ($0) + 16 RETURN_VALUE_R 1 """% (extended_arg_quick.__code__.co_firstlineno, extended_arg_quick.__code__.co_firstlineno + 1,) @@ -976,8 +1006,9 @@ def expected(count, w): s += ['''\ 3 %*d LOAD_FAST 0 (x) - %*d RETURN_VALUE -''' % (w, 10*count + 2, w, 10*count + 4)] + %*d STORE_FAST 1 ($0) + %*d RETURN_VALUE_R 1 +''' % (w, 10*count + 2, w, 10*count + 4, w, 10*count + 6)] s[1] = ' 2' + s[1][3:] return ''.join(s) @@ -1102,7 +1133,8 @@ def test_binary_specialize(self): 1 2 LOAD_NAME 0 (a) 4 LOAD_NAME 1 (b) 6 %s - 10 RETURN_VALUE + 10 STORE_FAST 0 ($0) + 12 RETURN_VALUE_R 0 """ co_int = compile('a + b', "", "eval") self.code_quicken(lambda: exec(co_int, {}, {'a': 1, 'b': 2})) @@ -1120,7 +1152,8 @@ def test_binary_specialize(self): 1 2 LOAD_NAME 0 (a) 4 LOAD_CONST 0 (0) 6 %s - 16 RETURN_VALUE + 16 STORE_FAST 0 ($0) + 18 RETURN_VALUE_R 0 """ co_list = compile('a[0]', "", "eval") self.code_quicken(lambda: exec(co_list, {}, {'a': [0]})) @@ -1140,7 +1173,8 @@ def test_load_attr_specialize(self): 1 2 LOAD_CONST 0 ('a') 4 LOAD_ATTR_SLOT 0 (__class__) - 24 RETURN_VALUE + 24 STORE_FAST 0 ($0) + 26 RETURN_VALUE_R 0 """ co = compile("'a'.__class__", "", "eval") self.code_quicken(lambda: exec(co, {}, {})) @@ -1157,7 +1191,8 @@ def test_call_specialize(self): LOAD_NAME 0 (str) LOAD_CONST 0 (1) CALL_NO_KW_STR_1 1 - RETURN_VALUE + STORE_FAST 0 ($0) + RETURN_VALUE_R 0 """ co = compile("str(1)", "", "eval") self.code_quicken(lambda: exec(co, {}, {})) @@ -1509,8 +1544,8 @@ def _prepare_test_cases(): Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=58, starts_line=8, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), -] + Instruction(opname='STORE_FAST', opcode=125, arg=3, argval='$0', argrepr='$0', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE_R', opcode=143, arg=3, argval=3, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None)] expected_opinfo_f = [ Instruction(opname='COPY_FREE_VARS', opcode=149, arg=2, argval=2, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None), @@ -1534,8 +1569,8 @@ def _prepare_test_cases(): Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=58, starts_line=6, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), -] + Instruction(opname='STORE_FAST', opcode=125, arg=5, argval='$0', argrepr='$0', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE_R', opcode=143, arg=5, argval=5, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None)] expected_opinfo_inner = [ Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None), @@ -1550,8 +1585,8 @@ def _prepare_test_cases(): Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=40, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None), -] + Instruction(opname='STORE_FAST', opcode=125, arg=6, argval='$0', argrepr='$0', offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE_R', opcode=143, arg=6, argval=6, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None)] expected_opinfo_jumpy = [ Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=None), @@ -1631,43 +1666,44 @@ def _prepare_test_cases(): Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=298, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=300, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=304, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=312, argrepr='to 312', offset=308, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=310, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='$0', argrepr='$0', offset=302, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE_R', opcode=143, arg=2, argval=2, argrepr='', offset=304, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=306, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=314, argrepr='to 314', offset=310, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=318, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=274, argrepr='to 274', offset=320, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=330, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=16, argval=378, argrepr='to 378', offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=346, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=348, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=360, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=372, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=374, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=52, argval=274, argrepr='to 274', offset=376, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=378, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=384, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=388, starts_line=28, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=400, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=402, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=412, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=25, argval=274, argrepr='to 274', offset=322, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=330, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=332, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=16, argval=380, argrepr='to 380', offset=346, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=348, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=350, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=362, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=374, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=376, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=53, argval=274, argrepr='to 274', offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=380, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=384, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=386, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=388, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=390, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=402, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=404, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=420, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=422, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling @@ -1675,8 +1711,8 @@ def simple(): pass expected_opinfo_simple = [ Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=2, starts_line=None, is_jump_target=False), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=4, starts_line=None, is_jump_target=False) -] + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='$0', argrepr='$0', offset=4, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE_R', opcode=143, arg=0, argval=0, argrepr='', offset=6, starts_line=None, is_jump_target=False, positions=None)] class InstructionTestCase(BytecodeTestCase): @@ -1737,6 +1773,7 @@ def test_co_positions(self): (1, 3, 0, 1), (1, 3, 0, 1), (1, 3, 0, 1), + (1, 3, 0, 1), (1, 3, 0, 1) ] self.assertEqual(positions, expected) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 239c9d03fd9d1f..79cae32c8a3a50 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -340,7 +340,7 @@ def f(x): return x self.assertNotInBytecode(f, 'LOAD_CONST', None) returns = [instr for instr in dis.get_instructions(f) - if instr.opname == 'RETURN_VALUE'] + if instr.opname == 'RETURN_VALUE_R'] self.assertEqual(len(returns), 1) self.check_lnotab(f) @@ -354,7 +354,7 @@ def f(cond, true_value, false_value): self.assertNotInBytecode(f, 'JUMP_FORWARD') self.assertNotInBytecode(f, 'JUMP_BACKWARD') returns = [instr for instr in dis.get_instructions(f) - if instr.opname == 'RETURN_VALUE'] + if instr.opname == 'RETURN_VALUE_R'] self.assertEqual(len(returns), 2) self.check_lnotab(f) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index ab1a0659471857..2db90427aedf70 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('3Pi3c7P2ic??2PP')) # 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('P2P4P4c7P2ic??2PP')) # iterator check(iter('abc'), size('lP')) # callable-iterator diff --git a/Objects/clinic/codeobject.c.h b/Objects/clinic/codeobject.c.h index da33f4a6a20c1b..0b5142955df61d 100644 --- a/Objects/clinic/codeobject.c.h +++ b/Objects/clinic/codeobject.c.h @@ -9,18 +9,18 @@ preserve PyDoc_STRVAR(code_new__doc__, -"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n" -" flags, codestring, constants, names, varnames, filename, name,\n" -" qualname, firstlineno, linetable, exceptiontable, freevars=(),\n" -" cellvars=(), /)\n" +"code(argcount, posonlyargcount, kwonlyargcount, nlocals, ntmps,\n" +" stacksize, flags, codestring, constants, names, varnames,\n" +" filename, name, qualname, firstlineno, linetable, exceptiontable,\n" +" freevars=(), cellvars=(), /)\n" "--\n" "\n" "Create a code object. Not for the faint of heart."); static PyObject * code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, - int kwonlyargcount, int nlocals, int stacksize, int flags, - PyObject *code, PyObject *consts, PyObject *names, + int kwonlyargcount, int nlocals, int ntmps, int stacksize, + int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable, PyObject *freevars, @@ -34,6 +34,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) int posonlyargcount; int kwonlyargcount; int nlocals; + int ntmps; int stacksize; int flags; PyObject *code; @@ -54,7 +55,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) !_PyArg_NoKeywords("code", kwargs)) { goto exit; } - if (!_PyArg_CheckPositional("code", PyTuple_GET_SIZE(args), 16, 18)) { + if (!_PyArg_CheckPositional("code", PyTuple_GET_SIZE(args), 17, 19)) { goto exit; } argcount = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); @@ -73,42 +74,38 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) if (nlocals == -1 && PyErr_Occurred()) { goto exit; } - stacksize = _PyLong_AsInt(PyTuple_GET_ITEM(args, 4)); - if (stacksize == -1 && PyErr_Occurred()) { + ntmps = _PyLong_AsInt(PyTuple_GET_ITEM(args, 4)); + if (ntmps == -1 && PyErr_Occurred()) { goto exit; } - flags = _PyLong_AsInt(PyTuple_GET_ITEM(args, 5)); - if (flags == -1 && PyErr_Occurred()) { + stacksize = _PyLong_AsInt(PyTuple_GET_ITEM(args, 5)); + if (stacksize == -1 && PyErr_Occurred()) { goto exit; } - if (!PyBytes_Check(PyTuple_GET_ITEM(args, 6))) { - _PyArg_BadArgument("code", "argument 7", "bytes", PyTuple_GET_ITEM(args, 6)); + flags = _PyLong_AsInt(PyTuple_GET_ITEM(args, 6)); + if (flags == -1 && PyErr_Occurred()) { goto exit; } - code = PyTuple_GET_ITEM(args, 6); - if (!PyTuple_Check(PyTuple_GET_ITEM(args, 7))) { - _PyArg_BadArgument("code", "argument 8", "tuple", PyTuple_GET_ITEM(args, 7)); + if (!PyBytes_Check(PyTuple_GET_ITEM(args, 7))) { + _PyArg_BadArgument("code", "argument 8", "bytes", PyTuple_GET_ITEM(args, 7)); goto exit; } - consts = PyTuple_GET_ITEM(args, 7); + code = PyTuple_GET_ITEM(args, 7); if (!PyTuple_Check(PyTuple_GET_ITEM(args, 8))) { _PyArg_BadArgument("code", "argument 9", "tuple", PyTuple_GET_ITEM(args, 8)); goto exit; } - names = PyTuple_GET_ITEM(args, 8); + consts = PyTuple_GET_ITEM(args, 8); if (!PyTuple_Check(PyTuple_GET_ITEM(args, 9))) { _PyArg_BadArgument("code", "argument 10", "tuple", PyTuple_GET_ITEM(args, 9)); goto exit; } - varnames = PyTuple_GET_ITEM(args, 9); - if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 10))) { - _PyArg_BadArgument("code", "argument 11", "str", PyTuple_GET_ITEM(args, 10)); + names = PyTuple_GET_ITEM(args, 9); + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 10))) { + _PyArg_BadArgument("code", "argument 11", "tuple", PyTuple_GET_ITEM(args, 10)); goto exit; } - if (PyUnicode_READY(PyTuple_GET_ITEM(args, 10)) == -1) { - goto exit; - } - filename = PyTuple_GET_ITEM(args, 10); + varnames = PyTuple_GET_ITEM(args, 10); if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 11))) { _PyArg_BadArgument("code", "argument 12", "str", PyTuple_GET_ITEM(args, 11)); goto exit; @@ -116,7 +113,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) if (PyUnicode_READY(PyTuple_GET_ITEM(args, 11)) == -1) { goto exit; } - name = PyTuple_GET_ITEM(args, 11); + filename = PyTuple_GET_ITEM(args, 11); if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 12))) { _PyArg_BadArgument("code", "argument 13", "str", PyTuple_GET_ITEM(args, 12)); goto exit; @@ -124,29 +121,29 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) if (PyUnicode_READY(PyTuple_GET_ITEM(args, 12)) == -1) { goto exit; } - qualname = PyTuple_GET_ITEM(args, 12); - firstlineno = _PyLong_AsInt(PyTuple_GET_ITEM(args, 13)); - if (firstlineno == -1 && PyErr_Occurred()) { + name = PyTuple_GET_ITEM(args, 12); + if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 13))) { + _PyArg_BadArgument("code", "argument 14", "str", PyTuple_GET_ITEM(args, 13)); + goto exit; + } + if (PyUnicode_READY(PyTuple_GET_ITEM(args, 13)) == -1) { goto exit; } - if (!PyBytes_Check(PyTuple_GET_ITEM(args, 14))) { - _PyArg_BadArgument("code", "argument 15", "bytes", PyTuple_GET_ITEM(args, 14)); + qualname = PyTuple_GET_ITEM(args, 13); + firstlineno = _PyLong_AsInt(PyTuple_GET_ITEM(args, 14)); + if (firstlineno == -1 && PyErr_Occurred()) { goto exit; } - linetable = PyTuple_GET_ITEM(args, 14); if (!PyBytes_Check(PyTuple_GET_ITEM(args, 15))) { _PyArg_BadArgument("code", "argument 16", "bytes", PyTuple_GET_ITEM(args, 15)); goto exit; } - exceptiontable = PyTuple_GET_ITEM(args, 15); - if (PyTuple_GET_SIZE(args) < 17) { - goto skip_optional; - } - if (!PyTuple_Check(PyTuple_GET_ITEM(args, 16))) { - _PyArg_BadArgument("code", "argument 17", "tuple", PyTuple_GET_ITEM(args, 16)); + linetable = PyTuple_GET_ITEM(args, 15); + if (!PyBytes_Check(PyTuple_GET_ITEM(args, 16))) { + _PyArg_BadArgument("code", "argument 17", "bytes", PyTuple_GET_ITEM(args, 16)); goto exit; } - freevars = PyTuple_GET_ITEM(args, 16); + exceptiontable = PyTuple_GET_ITEM(args, 16); if (PyTuple_GET_SIZE(args) < 18) { goto skip_optional; } @@ -154,9 +151,17 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) _PyArg_BadArgument("code", "argument 18", "tuple", PyTuple_GET_ITEM(args, 17)); goto exit; } - cellvars = PyTuple_GET_ITEM(args, 17); + freevars = PyTuple_GET_ITEM(args, 17); + if (PyTuple_GET_SIZE(args) < 19) { + goto skip_optional; + } + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 18))) { + _PyArg_BadArgument("code", "argument 19", "tuple", PyTuple_GET_ITEM(args, 18)); + goto exit; + } + cellvars = PyTuple_GET_ITEM(args, 18); skip_optional: - return_value = code_new_impl(type, argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags, code, consts, names, varnames, filename, name, qualname, firstlineno, linetable, exceptiontable, freevars, cellvars); + return_value = code_new_impl(type, argcount, posonlyargcount, kwonlyargcount, nlocals, ntmps, stacksize, flags, code, consts, names, varnames, filename, name, qualname, firstlineno, linetable, exceptiontable, freevars, cellvars); exit: return return_value; @@ -164,11 +169,12 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyDoc_STRVAR(code_replace__doc__, "replace($self, /, *, co_argcount=-1, co_posonlyargcount=-1,\n" -" co_kwonlyargcount=-1, co_nlocals=-1, co_stacksize=-1,\n" -" co_flags=-1, co_firstlineno=-1, co_code=None, co_consts=None,\n" -" co_names=None, co_varnames=None, co_freevars=None,\n" -" co_cellvars=None, co_filename=None, co_name=None,\n" -" co_qualname=None, co_linetable=None, co_exceptiontable=None)\n" +" co_kwonlyargcount=-1, co_nlocals=-1, co_ntmps=-1,\n" +" co_stacksize=-1, co_flags=-1, co_firstlineno=-1, co_code=None,\n" +" co_consts=None, co_names=None, co_varnames=None,\n" +" co_freevars=None, co_cellvars=None, co_filename=None,\n" +" co_name=None, co_qualname=None, co_linetable=None,\n" +" co_exceptiontable=None)\n" "--\n" "\n" "Return a copy of the code object with new values for the specified fields."); @@ -179,8 +185,8 @@ PyDoc_STRVAR(code_replace__doc__, static PyObject * code_replace_impl(PyCodeObject *self, int co_argcount, int co_posonlyargcount, int co_kwonlyargcount, - int co_nlocals, int co_stacksize, int co_flags, - int co_firstlineno, PyBytesObject *co_code, + int co_nlocals, int co_ntmps, int co_stacksize, + int co_flags, int co_firstlineno, PyBytesObject *co_code, PyObject *co_consts, PyObject *co_names, PyObject *co_varnames, PyObject *co_freevars, PyObject *co_cellvars, PyObject *co_filename, @@ -194,14 +200,14 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 18 + #define NUM_KEYWORDS 19 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(co_argcount), &_Py_ID(co_posonlyargcount), &_Py_ID(co_kwonlyargcount), &_Py_ID(co_nlocals), &_Py_ID(co_stacksize), &_Py_ID(co_flags), &_Py_ID(co_firstlineno), &_Py_ID(co_code), &_Py_ID(co_consts), &_Py_ID(co_names), &_Py_ID(co_varnames), &_Py_ID(co_freevars), &_Py_ID(co_cellvars), &_Py_ID(co_filename), &_Py_ID(co_name), &_Py_ID(co_qualname), &_Py_ID(co_linetable), &_Py_ID(co_exceptiontable), }, + .ob_item = { &_Py_ID(co_argcount), &_Py_ID(co_posonlyargcount), &_Py_ID(co_kwonlyargcount), &_Py_ID(co_nlocals), &_Py_ID(co_ntmps), &_Py_ID(co_stacksize), &_Py_ID(co_flags), &_Py_ID(co_firstlineno), &_Py_ID(co_code), &_Py_ID(co_consts), &_Py_ID(co_names), &_Py_ID(co_varnames), &_Py_ID(co_freevars), &_Py_ID(co_cellvars), &_Py_ID(co_filename), &_Py_ID(co_name), &_Py_ID(co_qualname), &_Py_ID(co_linetable), &_Py_ID(co_exceptiontable), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -210,19 +216,20 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"co_argcount", "co_posonlyargcount", "co_kwonlyargcount", "co_nlocals", "co_stacksize", "co_flags", "co_firstlineno", "co_code", "co_consts", "co_names", "co_varnames", "co_freevars", "co_cellvars", "co_filename", "co_name", "co_qualname", "co_linetable", "co_exceptiontable", NULL}; + static const char * const _keywords[] = {"co_argcount", "co_posonlyargcount", "co_kwonlyargcount", "co_nlocals", "co_ntmps", "co_stacksize", "co_flags", "co_firstlineno", "co_code", "co_consts", "co_names", "co_varnames", "co_freevars", "co_cellvars", "co_filename", "co_name", "co_qualname", "co_linetable", "co_exceptiontable", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "replace", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[18]; + PyObject *argsbuf[19]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; int co_argcount = self->co_argcount; int co_posonlyargcount = self->co_posonlyargcount; int co_kwonlyargcount = self->co_kwonlyargcount; int co_nlocals = self->co_nlocals; + int co_ntmps = self->co_ntmps; int co_stacksize = self->co_stacksize; int co_flags = self->co_flags; int co_firstlineno = self->co_firstlineno; @@ -282,8 +289,8 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[4]) { - co_stacksize = _PyLong_AsInt(args[4]); - if (co_stacksize == -1 && PyErr_Occurred()) { + co_ntmps = _PyLong_AsInt(args[4]); + if (co_ntmps == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -291,8 +298,8 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[5]) { - co_flags = _PyLong_AsInt(args[5]); - if (co_flags == -1 && PyErr_Occurred()) { + co_stacksize = _PyLong_AsInt(args[5]); + if (co_stacksize == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -300,8 +307,8 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[6]) { - co_firstlineno = _PyLong_AsInt(args[6]); - if (co_firstlineno == -1 && PyErr_Occurred()) { + co_flags = _PyLong_AsInt(args[6]); + if (co_flags == -1 && PyErr_Occurred()) { goto exit; } if (!--noptargs) { @@ -309,121 +316,130 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[7]) { - if (!PyBytes_Check(args[7])) { - _PyArg_BadArgument("replace", "argument 'co_code'", "bytes", args[7]); + co_firstlineno = _PyLong_AsInt(args[7]); + if (co_firstlineno == -1 && PyErr_Occurred()) { goto exit; } - co_code = (PyBytesObject *)args[7]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[8]) { - if (!PyTuple_Check(args[8])) { - _PyArg_BadArgument("replace", "argument 'co_consts'", "tuple", args[8]); + if (!PyBytes_Check(args[8])) { + _PyArg_BadArgument("replace", "argument 'co_code'", "bytes", args[8]); goto exit; } - co_consts = args[8]; + co_code = (PyBytesObject *)args[8]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[9]) { if (!PyTuple_Check(args[9])) { - _PyArg_BadArgument("replace", "argument 'co_names'", "tuple", args[9]); + _PyArg_BadArgument("replace", "argument 'co_consts'", "tuple", args[9]); goto exit; } - co_names = args[9]; + co_consts = args[9]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[10]) { if (!PyTuple_Check(args[10])) { - _PyArg_BadArgument("replace", "argument 'co_varnames'", "tuple", args[10]); + _PyArg_BadArgument("replace", "argument 'co_names'", "tuple", args[10]); goto exit; } - co_varnames = args[10]; + co_names = args[10]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[11]) { if (!PyTuple_Check(args[11])) { - _PyArg_BadArgument("replace", "argument 'co_freevars'", "tuple", args[11]); + _PyArg_BadArgument("replace", "argument 'co_varnames'", "tuple", args[11]); goto exit; } - co_freevars = args[11]; + co_varnames = args[11]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[12]) { if (!PyTuple_Check(args[12])) { - _PyArg_BadArgument("replace", "argument 'co_cellvars'", "tuple", args[12]); + _PyArg_BadArgument("replace", "argument 'co_freevars'", "tuple", args[12]); goto exit; } - co_cellvars = args[12]; + co_freevars = args[12]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[13]) { - if (!PyUnicode_Check(args[13])) { - _PyArg_BadArgument("replace", "argument 'co_filename'", "str", args[13]); - goto exit; - } - if (PyUnicode_READY(args[13]) == -1) { + if (!PyTuple_Check(args[13])) { + _PyArg_BadArgument("replace", "argument 'co_cellvars'", "tuple", args[13]); goto exit; } - co_filename = args[13]; + co_cellvars = args[13]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[14]) { if (!PyUnicode_Check(args[14])) { - _PyArg_BadArgument("replace", "argument 'co_name'", "str", args[14]); + _PyArg_BadArgument("replace", "argument 'co_filename'", "str", args[14]); goto exit; } if (PyUnicode_READY(args[14]) == -1) { goto exit; } - co_name = args[14]; + co_filename = args[14]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[15]) { if (!PyUnicode_Check(args[15])) { - _PyArg_BadArgument("replace", "argument 'co_qualname'", "str", args[15]); + _PyArg_BadArgument("replace", "argument 'co_name'", "str", args[15]); goto exit; } if (PyUnicode_READY(args[15]) == -1) { goto exit; } - co_qualname = args[15]; + co_name = args[15]; if (!--noptargs) { goto skip_optional_kwonly; } } if (args[16]) { - if (!PyBytes_Check(args[16])) { - _PyArg_BadArgument("replace", "argument 'co_linetable'", "bytes", args[16]); + if (!PyUnicode_Check(args[16])) { + _PyArg_BadArgument("replace", "argument 'co_qualname'", "str", args[16]); + goto exit; + } + if (PyUnicode_READY(args[16]) == -1) { + goto exit; + } + co_qualname = args[16]; + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (args[17]) { + if (!PyBytes_Check(args[17])) { + _PyArg_BadArgument("replace", "argument 'co_linetable'", "bytes", args[17]); goto exit; } - co_linetable = (PyBytesObject *)args[16]; + co_linetable = (PyBytesObject *)args[17]; if (!--noptargs) { goto skip_optional_kwonly; } } - if (!PyBytes_Check(args[17])) { - _PyArg_BadArgument("replace", "argument 'co_exceptiontable'", "bytes", args[17]); + if (!PyBytes_Check(args[18])) { + _PyArg_BadArgument("replace", "argument 'co_exceptiontable'", "bytes", args[18]); goto exit; } - co_exceptiontable = (PyBytesObject *)args[17]; + co_exceptiontable = (PyBytesObject *)args[18]; skip_optional_kwonly: - return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); + return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_ntmps, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_linetable, co_exceptiontable); exit: return return_value; @@ -488,4 +504,4 @@ code__varname_from_oparg(PyCodeObject *self, PyObject *const *args, Py_ssize_t n exit: return return_value; } -/*[clinic end generated code: output=b6c98f17c60ace53 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a9c13c2353dadf56 input=a9049054013a1b77]*/ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index ab31b6582cdaae..647de6ba204e36 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -307,7 +307,7 @@ _PyCode_Validate(struct _PyCodeConstructor *con) { /* Check argument types */ if (con->argcount < con->posonlyargcount || con->posonlyargcount < 0 || - con->kwonlyargcount < 0 || + con->kwonlyargcount < 0 || con->ntmps < 0 || con->stacksize < 0 || con->flags < 0 || con->code == NULL || !PyBytes_Check(con->code) || con->consts == NULL || !PyTuple_Check(con->consts) || @@ -388,6 +388,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->co_posonlyargcount = con->posonlyargcount; co->co_kwonlyargcount = con->kwonlyargcount; + co->co_ntmps = con->ntmps; co->co_stacksize = con->stacksize; co->co_exceptiontable = Py_NewRef(con->exceptiontable); @@ -395,7 +396,9 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) /* derived values */ co->co_nlocalsplus = nlocalsplus; co->co_nlocals = nlocals; - co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE; + /* This function needs to remain in sync with the calculation of + * co_framesize in Tools/build/deepfreeze.py */ + co->co_framesize = nlocalsplus + con->ntmps + con->stacksize + FRAME_SPECIALS_SIZE; co->co_ncellvars = ncellvars; co->co_nfreevars = nfreevars; co->co_version = _Py_next_func_version; @@ -568,7 +571,7 @@ _PyCode_New(struct _PyCodeConstructor *con) PyCodeObject * PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, - int nlocals, int stacksize, int flags, + int nlocals, int ntmps, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, @@ -663,6 +666,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, .posonlyargcount = posonlyargcount, .kwonlyargcount = kwonlyargcount, + .ntmps = ntmps, .stacksize = stacksize, .exceptiontable = exceptiontable, @@ -692,7 +696,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, PyCodeObject * PyCode_New(int argcount, int kwonlyargcount, - int nlocals, int stacksize, int flags, + int nlocals, int ntmps, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, PyObject *qualname, @@ -701,7 +705,7 @@ PyCode_New(int argcount, int kwonlyargcount, PyObject *exceptiontable) { return PyCode_NewWithPosOnlyArgs(argcount, 0, kwonlyargcount, nlocals, - stacksize, flags, code, consts, names, + ntmps, stacksize, flags, code, consts, names, varnames, freevars, cellvars, filename, name, qualname, firstlineno, linetable, @@ -768,6 +772,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) .localsplusnames = nulltuple, .localspluskinds = emptystring, .exceptiontable = emptystring, + .ntmps = 0, .stacksize = 1, }; result = _PyCode_New(&con); @@ -1558,6 +1563,7 @@ code.__new__ as code_new posonlyargcount: int kwonlyargcount: int nlocals: int + ntmps : int stacksize: int flags: int codestring as code: object(subclass_of="&PyBytes_Type") @@ -1579,13 +1585,14 @@ Create a code object. Not for the faint of heart. static PyObject * code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, - int kwonlyargcount, int nlocals, int stacksize, int flags, - PyObject *code, PyObject *consts, PyObject *names, + int kwonlyargcount, int nlocals, int ntmps, int stacksize, + int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *filename, PyObject *name, PyObject *qualname, int firstlineno, PyObject *linetable, PyObject *exceptiontable, PyObject *freevars, PyObject *cellvars) -/*[clinic end generated code: output=069fa20d299f9dda input=e31da3c41ad8064a]*/ +/*[clinic end generated code: output=32ed6a09b0d3c02e input=910db82cd51f56e5]*/ + { PyObject *co = NULL; PyObject *ournames = NULL; @@ -1593,9 +1600,9 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, PyObject *ourfreevars = NULL; PyObject *ourcellvars = NULL; - if (PySys_Audit("code.__new__", "OOOiiiiii", + if (PySys_Audit("code.__new__", "OOOiiiiiii", code, filename, name, argcount, posonlyargcount, - kwonlyargcount, nlocals, stacksize, flags) < 0) { + kwonlyargcount, nlocals, ntmps, stacksize, flags) < 0) { goto cleanup; } @@ -1647,7 +1654,7 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, co = (PyObject *)PyCode_NewWithPosOnlyArgs(argcount, posonlyargcount, kwonlyargcount, - nlocals, stacksize, flags, + nlocals, ntmps, stacksize, flags, code, consts, ournames, ourvarnames, ourfreevars, ourcellvars, filename, @@ -1866,6 +1873,7 @@ static PyMemberDef code_memberlist[] = { {"co_argcount", T_INT, OFF(co_argcount), READONLY}, {"co_posonlyargcount", T_INT, OFF(co_posonlyargcount), READONLY}, {"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY}, + {"co_ntmps", T_INT, OFF(co_ntmps), READONLY}, {"co_stacksize", T_INT, OFF(co_stacksize), READONLY}, {"co_flags", T_INT, OFF(co_flags), READONLY}, {"co_nlocals", T_INT, OFF(co_nlocals), READONLY}, @@ -1956,6 +1964,7 @@ code.replace co_posonlyargcount: int(c_default="self->co_posonlyargcount") = -1 co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = -1 co_nlocals: int(c_default="self->co_nlocals") = -1 + co_ntmps: int(c_default="self->co_ntmps") = -1 co_stacksize: int(c_default="self->co_stacksize") = -1 co_flags: int(c_default="self->co_flags") = -1 co_firstlineno: int(c_default="self->co_firstlineno") = -1 @@ -1977,15 +1986,16 @@ Return a copy of the code object with new values for the specified fields. static PyObject * code_replace_impl(PyCodeObject *self, int co_argcount, int co_posonlyargcount, int co_kwonlyargcount, - int co_nlocals, int co_stacksize, int co_flags, - int co_firstlineno, PyBytesObject *co_code, + int co_nlocals, int co_ntmps, int co_stacksize, + int co_flags, int co_firstlineno, PyBytesObject *co_code, PyObject *co_consts, PyObject *co_names, PyObject *co_varnames, PyObject *co_freevars, PyObject *co_cellvars, PyObject *co_filename, PyObject *co_name, PyObject *co_qualname, PyBytesObject *co_linetable, PyBytesObject *co_exceptiontable) -/*[clinic end generated code: output=b6cd9988391d5711 input=f6f68e03571f8d7c]*/ +/*[clinic end generated code: output=3723fb57c03c4104 input=1a51b717dc2af298]*/ + { #define CHECK_INT_ARG(ARG) \ if (ARG < 0) { \ @@ -1998,6 +2008,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount, CHECK_INT_ARG(co_posonlyargcount); CHECK_INT_ARG(co_kwonlyargcount); CHECK_INT_ARG(co_nlocals); + CHECK_INT_ARG(co_ntmps); CHECK_INT_ARG(co_stacksize); CHECK_INT_ARG(co_flags); CHECK_INT_ARG(co_firstlineno); @@ -2013,10 +2024,10 @@ code_replace_impl(PyCodeObject *self, int co_argcount, co_code = (PyBytesObject *)code; } - if (PySys_Audit("code.__new__", "OOOiiiiii", + if (PySys_Audit("code.__new__", "OOOiiiiiii", co_code, co_filename, co_name, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, - co_stacksize, co_flags) < 0) { + co_ntmps, co_stacksize, co_flags) < 0) { return NULL; } @@ -2048,7 +2059,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount, co = PyCode_NewWithPosOnlyArgs( co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, - co_stacksize, co_flags, (PyObject*)co_code, co_consts, co_names, + co_ntmps, co_stacksize, co_flags, (PyObject*)co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_qualname, co_firstlineno, (PyObject*)co_linetable, (PyObject*)co_exceptiontable); @@ -2075,11 +2086,20 @@ static PyObject * code__varname_from_oparg_impl(PyCodeObject *self, int oparg) /*[clinic end generated code: output=1fd1130413184206 input=c5fa3ee9bac7d4ca]*/ { - PyObject *name = PyTuple_GetItem(self->co_localsplusnames, oparg); - if (name == NULL) { - return NULL; + if (oparg < self->co_nlocalsplus) { + PyObject *name = PyTuple_GetItem(self->co_localsplusnames, oparg); + if (name == NULL) { + return NULL; + } + return Py_NewRef(name); + } + else { + if (oparg >= self->co_nlocalsplus + self->co_ntmps) { + PyErr_SetString(PyExc_RuntimeError, "varname oparg out of range"); + return NULL; + } + return PyUnicode_FromFormat("$%d", oparg - self->co_nlocalsplus); } - return Py_NewRef(name); } /* XXX code objects need to participate in GC? */ @@ -2374,6 +2394,7 @@ _Py_MakeShimCode(const _PyShimCodeDef *codedef) .posonlyargcount = 0, .kwonlyargcount = 0, + .ntmps = codedef->ntmps, .stacksize = codedef->stacksize, .exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty), diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 6bc04bc8e848fc..fca0cef73c1d63 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -397,6 +397,9 @@ mark_stacks(PyCodeObject *code_obj, int len) assert(pop_value(next_stack) == EMPTY_STACK); assert(top_of_stack(next_stack) == Object); break; + case RETURN_VALUE_R: + assert(next_stack == EMPTY_STACK); + break; case RAISE_VARARGS: break; case RERAISE: @@ -1028,7 +1031,7 @@ PyFrameObject* _PyFrame_New_NoTrack(PyCodeObject *code) { CALL_STAT_INC(frame_objects_created); - int slots = code->co_nlocalsplus + code->co_stacksize; + int slots = _PyFrame_NumSlotsForCodeObject(code); PyFrameObject *f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, slots); if (f == NULL) { return NULL; diff --git a/Objects/genobject.c b/Objects/genobject.c index 2adb1e4bf308e4..f9f6b8f16574a8 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -922,7 +922,7 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, PyObject *name, PyObject *qualname) { PyCodeObject *code = f->f_frame->f_code; - int size = code->co_nlocalsplus + code->co_stacksize; + int size = _PyFrame_NumSlotsForCodeObject(code); PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size); if (gen == NULL) { Py_DECREF(f); diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 95f78b19e65eb6..564a701abc9ce2 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,39 +1,39 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { - 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,243,184,0,0,0,151,0,100,0,100,1, - 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, - 100,2,171,1,0,0,0,0,0,0,0,0,1,0,2,0, - 101,2,100,3,101,0,106,6,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,171,2,0,0,0,0, - 0,0,0,0,1,0,2,0,101,1,106,8,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,0, - 0,0,0,0,0,0,0,0,100,4,25,0,0,0,0,0, - 0,0,0,0,90,5,100,5,68,0,93,23,0,0,90,6, - 2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6, - 25,0,0,0,0,0,0,0,0,0,155,0,157,4,171,1, - 0,0,0,0,0,0,0,0,1,0,140,25,4,0,100,1, - 83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, - 101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, - 115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, - 41,5,218,12,112,114,111,103,114,97,109,95,110,97,109,101, - 218,10,101,120,101,99,117,116,97,98,108,101,218,15,117,115, - 101,95,101,110,118,105,114,111,110,109,101,110,116,218,17,99, - 111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, - 218,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, - 122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, - 3,115,121,115,218,17,95,116,101,115,116,105,110,116,101,114, - 110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, - 97,114,103,118,218,11,103,101,116,95,99,111,110,102,105,103, - 115,114,3,0,0,0,218,3,107,101,121,169,0,243,0,0, - 0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, - 97,105,110,46,112,121,250,8,60,109,111,100,117,108,101,62, - 114,18,0,0,0,1,0,0,0,115,100,0,0,0,240,3, - 1,1,1,243,8,0,1,11,219,0,24,225,0,5,208,6, - 26,213,0,27,217,0,5,128,106,144,35,151,40,145,40,213, - 0,27,216,9,38,208,9,26,215,9,38,209,9,38,212,9, - 40,168,24,212,9,50,128,6,240,2,6,12,2,242,0,7, - 1,42,128,67,241,14,0,5,10,208,10,40,144,67,209,10, - 40,152,54,160,35,156,59,209,10,40,214,4,41,242,15,7, - 1,42,114,16,0,0,0, + 227,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, + 0,8,0,0,0,0,0,0,0,243,186,0,0,0,151,0, + 100,0,100,1,108,0,90,0,100,0,100,1,108,1,90,1, + 2,0,101,2,100,2,171,1,0,0,0,0,0,0,0,0, + 1,0,2,0,101,2,100,3,101,0,106,6,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,2, + 0,0,0,0,0,0,0,0,1,0,2,0,101,1,106,8, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,171,0,0,0,0,0,0,0,0,0,100,4,25,0, + 0,0,0,0,0,0,0,0,90,5,100,5,68,0,93,23, + 0,0,90,6,2,0,101,2,100,6,101,6,155,0,100,7, + 101,5,101,6,25,0,0,0,0,0,0,0,0,0,155,0, + 157,4,171,1,0,0,0,0,0,0,0,0,1,0,140,25, + 4,0,100,1,125,0,143,0,41,8,233,0,0,0,0,78, + 122,18,70,114,111,122,101,110,32,72,101,108,108,111,32,87, + 111,114,108,100,122,8,115,121,115,46,97,114,103,118,218,6, + 99,111,110,102,105,103,41,5,218,12,112,114,111,103,114,97, + 109,95,110,97,109,101,218,10,101,120,101,99,117,116,97,98, + 108,101,218,15,117,115,101,95,101,110,118,105,114,111,110,109, + 101,110,116,218,17,99,111,110,102,105,103,117,114,101,95,99, + 95,115,116,100,105,111,218,14,98,117,102,102,101,114,101,100, + 95,115,116,100,105,111,122,7,99,111,110,102,105,103,32,122, + 2,58,32,41,7,218,3,115,121,115,218,17,95,116,101,115, + 116,105,110,116,101,114,110,97,108,99,97,112,105,218,5,112, + 114,105,110,116,218,4,97,114,103,118,218,11,103,101,116,95, + 99,111,110,102,105,103,115,114,3,0,0,0,218,3,107,101, + 121,169,0,243,0,0,0,0,250,18,116,101,115,116,95,102, + 114,111,122,101,110,109,97,105,110,46,112,121,250,8,60,109, + 111,100,117,108,101,62,114,18,0,0,0,1,0,0,0,115, + 100,0,0,0,240,3,1,1,1,243,8,0,1,11,219,0, + 24,225,0,5,208,6,26,213,0,27,217,0,5,128,106,144, + 35,151,40,145,40,213,0,27,216,9,38,208,9,26,215,9, + 38,209,9,38,212,9,40,168,24,212,9,50,128,6,240,2, + 6,12,2,242,0,7,1,42,128,67,241,14,0,5,10,208, + 10,40,144,67,209,10,40,152,54,160,35,156,59,209,10,40, + 214,4,41,243,15,7,1,42,114,16,0,0,0, }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6088fa45ac64d2..800b910f2dd39f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -558,6 +558,22 @@ dummy_func( goto resume_frame; } + register inst(RETURN_VALUE_R, (retval --)) { + assert(EMPTY()); + Py_XINCREF(retval); + _PyFrame_SetStackPointer(frame, stack_pointer); + TRACE_FUNCTION_EXIT(); + DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + inst(GET_AITER, (obj -- iter)) { unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -3318,6 +3334,7 @@ dummy_func( assert(cframe.use_tracing == 0); opcode = _Py_OPCODE(*next_instr); oparg = oparg << 8 | _Py_OPARG(*next_instr); + oparg1 = oparg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); } diff --git a/Python/ceval.c b/Python/ceval.c index a97313c773ee65..88cd0354d037d3 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -726,6 +726,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int // for the big switch below (in combination with the EXTRA_CASES macro). uint8_t opcode; /* Current opcode */ int oparg; /* Current opcode argument, if any */ + int oparg1; /* Current opcode argument, if any */ _Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker; #ifdef LLTRACE int lltrace = 0; @@ -756,7 +757,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int entry_frame.f_code = tstate->interp->interpreter_trampoline; entry_frame.prev_instr = _PyCode_CODE(tstate->interp->interpreter_trampoline); - entry_frame.stacktop = 0; + entry_frame.stacktop = entry_frame.f_code->co_ntmps; entry_frame.owner = FRAME_OWNED_BY_CSTACK; entry_frame.yield_offset = 0; /* Push frame */ @@ -930,6 +931,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int INSTRUCTION_START(EXTENDED_ARG); opcode = _Py_OPCODE(*next_instr); oparg = oparg << 8 | _Py_OPARG(*next_instr); + oparg1 = oparg; // Make sure the next instruction isn't a RESUME, since that needs // to trace properly (and shouldn't have an EXTENDED_ARG, anyways): assert(opcode != RESUME); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index d7a8f0beeec872..adc4428acdfaef 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -145,6 +145,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { _Py_CODEUNIT word = *next_instr; \ opcode = _Py_OPCODE(word); \ oparg = _Py_OPARG(word); \ + oparg1 = oparg; \ } while (0) #define JUMPTO(x) (next_instr = _PyCode_CODE(frame->f_code) + (x)) #define JUMPBY(x) (next_instr += (x)) @@ -186,6 +187,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { opcode = _Py_OPCODE(word) | cframe.use_tracing OR_DTRACE_LINE; \ if (opcode == op) { \ oparg = _Py_OPARG(word); \ + oparg1 = oparg; \ INSTRUCTION_START(op); \ goto PREDICT_ID(op); \ } \ @@ -250,6 +252,9 @@ GETITEM(PyObject *v, Py_ssize_t i) { GETLOCAL(i) = value; \ Py_XDECREF(tmp); } while (0) +/* Access a register */ +#define REG(n) (frame->localsplus[n]) + #define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) #ifdef Py_STATS diff --git a/Python/compile.c b/Python/compile.c index ce714dce6edfe6..2ae6e58f885852 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -124,6 +124,7 @@ #define IS_SCOPE_EXIT_OPCODE(opcode) \ ((opcode) == RETURN_VALUE || \ + (opcode) == RETURN_VALUE_R || \ (opcode) == RAISE_VARARGS || \ (opcode) == RERAISE) @@ -184,31 +185,71 @@ static struct jump_target_label_ NO_LABEL = {-1}; return 0; \ } +enum oparg_type { + OPARG_TYPE_UNUSED, + OPARG_TYPE_EXPLICIT, /* int value */ + OPARG_TYPE_CONST, /* index of const */ + OPARG_TYPE_NAME, /* index of name */ + OPARG_TYPE_TMP, /* index of tmp */ +}; + +typedef struct oparg_ { + enum oparg_type type; + int value; /* logical value set by codegen */ + int final; /* actual reg value, resolved in assembly */ +} oparg_t; + +#define UNUSED_OPARG ((const oparg_t){.value=(0), .type=OPARG_TYPE_UNUSED}) +#define EXPLICIT_OPARG(V) ((const oparg_t){.value=(V), .type=OPARG_TYPE_EXPLICIT}) +#define CONST_OPARG(V) ((const oparg_t){.value=(V), .type=OPARG_TYPE_CONST}) +#define NAME_OPARG(V) ((const oparg_t){.value=(V), .type=OPARG_TYPE_NAME}) +#define TMP_OPARG(V) ((const oparg_t){.value=(V), .type=OPARG_TYPE_TMP}) + +#define IS_UNUSED(OPARG) ((OPARG).type == OPARG_TYPE_UNUSED) +#define SAME_REGISTER(R1, R2) (((R1).type == (R2).type) && ((R1).value == (R2).value)) + +typedef struct instr_opargs_ { + oparg_t arg1; +} instr_opargs; + +#define NO_OPARGS ((const instr_opargs){UNUSED_OPARG}) +#define OPARGS1(A1) ((const instr_opargs){(A1)}) + + struct instr { int i_opcode; int i_oparg; + instr_opargs i_opargs; location i_loc; /* The following fields should not be set by the front-end: */ struct basicblock_ *i_target; /* target block (if jump instruction) */ struct basicblock_ *i_except; /* target block when exception is raised */ }; -/* One arg*/ -#define INSTR_SET_OP1(I, OP, ARG) \ - do { \ - assert(HAS_ARG(OP)); \ - struct instr *_instr__ptr_ = (I); \ - _instr__ptr_->i_opcode = (OP); \ - _instr__ptr_->i_oparg = (ARG); \ - } while (0); +#define IS_REGISTER_INSTR(I) (!IS_UNUSED((I)->i_opargs.arg1)) -/* No args*/ + /* No args*/ #define INSTR_SET_OP0(I, OP) \ do { \ assert(!HAS_ARG(OP)); \ + int _opcode_ = (OP); \ struct instr *_instr__ptr_ = (I); \ - _instr__ptr_->i_opcode = (OP); \ + _instr__ptr_->i_opcode = _opcode_; \ _instr__ptr_->i_oparg = 0; \ + _instr__ptr_->i_opargs = NO_OPARGS; \ + } while (0); + +/* One arg*/ +#define INSTR_SET_OP1(I, OP, ARG, OPARG1) \ + do { \ + assert(HAS_ARG(OP)); \ + int _opcode_ = (OP); \ + int _oparg_ = (ARG); \ + oparg_t _oparg1_ = (OPARG1); \ + struct instr *_instr__ptr_ = (I); \ + _instr__ptr_->i_opcode = _opcode_; \ + _instr__ptr_->i_oparg = _oparg_; \ + _instr__ptr_->i_opargs = OPARGS1(_oparg1_); \ } while (0); typedef struct exceptstack { @@ -254,11 +295,11 @@ is_jump(struct instr *i) } static int -instr_size(struct instr *instruction) +instr_size(struct instr *instr) { - int opcode = instruction->i_opcode; + int opcode = instr->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); - int oparg = instruction->i_oparg; + int oparg = IS_REGISTER_INSTR(instr) ? instr->i_opargs.arg1.final : instr->i_oparg; assert(HAS_ARG(opcode) || oparg == 0); int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); int caches = _PyOpcode_Caches[opcode]; @@ -266,11 +307,11 @@ instr_size(struct instr *instruction) } static void -write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen) +write_instr(_Py_CODEUNIT *codestr, struct instr *instr, int ilen) { - int opcode = instruction->i_opcode; + int opcode = instr->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); - int oparg = instruction->i_oparg; + int oparg = IS_REGISTER_INSTR(instr) ? instr->i_opargs.arg1.final : instr->i_oparg; assert(HAS_ARG(opcode) || oparg == 0); int caches = _PyOpcode_Caches[opcode]; switch (ilen - caches) { @@ -356,7 +397,7 @@ basicblock_last_instr(const basicblock *b) { static inline int basicblock_returns(const basicblock *b) { struct instr *last = basicblock_last_instr(b); - return last && last->i_opcode == RETURN_VALUE; + return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_VALUE_R); } static inline int @@ -452,6 +493,8 @@ struct compiler_unit { struct fblockinfo u_fblock[CO_MAXBLOCKS]; int u_firstlineno; /* the first lineno of the block */ + int u_ntmps; /* 1+highest index of a tmp used in this code unit */ + int u_next_free_tmp; /* index of the first tmp register which is no longer in use */ }; /* This struct captures the global state of a compilation. @@ -480,6 +523,7 @@ struct compiler { struct compiler_unit *u; /* compiler state for current block */ PyObject *c_stack; /* Python list holding compiler_unit ptrs */ PyArena *c_arena; /* pointer to memory allocation arena */ + bool c_regcode; /* produce regmachine code for this file */ }; #define CFG_BUILDER(C) (&((C)->u->u_cfg_builder)) @@ -652,6 +696,17 @@ compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, c->c_filename = Py_NewRef(filename); c->c_arena = arena; + + const char *f = PyUnicode_AsUTF8(c->c_filename); + if (f == NULL) { + PyErr_Clear(); + c->c_regcode = false; + } + else { + c->c_regcode = strstr(f, "mytest"); + } + c->c_regcode = true; + if (!_PyFuture_FromAST(mod, filename, &c->c_future)) { return ERROR; } @@ -871,6 +926,30 @@ compiler_unit_free(struct compiler_unit *u) PyObject_Free(u); } +static int +compiler_unit_get_free_tmp(struct compiler_unit *u) +{ + int tmp = u->u_next_free_tmp++; + if (u->u_next_free_tmp > u->u_ntmps) { + u->u_ntmps = u->u_next_free_tmp; + } + return tmp; +} + +static void +compiler_unit_release_tmps(struct compiler_unit *u, int release_from) +{ + assert(release_from >= 0); + u->u_next_free_tmp = release_from; +} + +#define ALLOCATE_TMP(C) TMP_OPARG(compiler_unit_get_free_tmp((C)->u)) +#define RELEASE_TMPS(C, I) compiler_unit_release_tmps((C)->u, (I)) +/* Note: RELEASE_TMPS frees index I so that it can be reused, but + * it doesn't decref the value of the register (this currently happens + * when the tmp is reused, or when the frame is cleared). + */ + static int compiler_set_qualname(struct compiler *c) { @@ -1120,6 +1199,8 @@ stack_effect(int opcode, int oparg, int jump) case RETURN_VALUE: return -1; + case RETURN_VALUE_R: + return 0; case SETUP_ANNOTATIONS: return 0; case YIELD_VALUE: @@ -1335,7 +1416,8 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) } static int -basicblock_addop(basicblock *b, int opcode, int oparg, location loc) +basicblock_addop(basicblock *b, int opcode, int oparg, instr_opargs opargs, + location loc) { assert(IS_WITHIN_OPCODE_RANGE(opcode)); assert(!IS_ASSEMBLER_OPCODE(opcode)); @@ -1349,6 +1431,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc) struct instr *i = &b->b_instr[off]; i->i_opcode = opcode; i->i_oparg = oparg; + i->i_opargs = opargs; i->i_target = NULL; i->i_loc = loc; @@ -1381,19 +1464,20 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) } static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) +cfg_builder_addop(cfg_builder *g, int opcode, int oparg, instr_opargs opargs, + location loc) { if (cfg_builder_maybe_start_new_block(g) != 0) { return -1; } - return basicblock_addop(g->g_curblock, opcode, oparg, loc); + return basicblock_addop(g->g_curblock, opcode, oparg, opargs, loc); } static int cfg_builder_addop_noarg(cfg_builder *g, int opcode, location loc) { assert(!HAS_ARG(opcode)); - return cfg_builder_addop(g, opcode, 0, loc); + return cfg_builder_addop(g, opcode, 0, NO_OPARGS, loc); } static Py_ssize_t @@ -1604,7 +1688,7 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return cfg_builder_addop(g, opcode, oparg_, loc); + return cfg_builder_addop(g, opcode, oparg_, NO_OPARGS, loc); } static int @@ -1613,12 +1697,15 @@ cfg_builder_addop_j(cfg_builder *g, location loc, { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return cfg_builder_addop(g, opcode, target.id, loc); + return cfg_builder_addop(g, opcode, target.id, NO_OPARGS, loc); } #define ADDOP(C, LOC, OP) \ RETURN_IF_ERROR(cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) +#define ADDOP_REGS(C, LOC, OP, ARGS) \ + RETURN_IF_ERROR(cfg_builder_addop(CFG_BUILDER(C), (OP), 0, (ARGS), (LOC))) + #define ADDOP_IN_SCOPE(C, LOC, OP) { \ if (cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC)) < 0) { \ compiler_exit_scope(C); \ @@ -1672,6 +1759,16 @@ cfg_builder_addop_j(cfg_builder *g, location loc, #define ADD_YIELD_FROM(C, LOC, await) \ RETURN_IF_ERROR(compiler_add_yield_from((C), (LOC), (await))) +#define ADD_RETURN_VALUE(C, LOC) \ + RETURN_IF_ERROR(compiler_add_return_value((C), (LOC))); + +#define ADD_RETURN_VALUE_IN_SCOPE(C, LOC) { \ + if (compiler_add_return_value((C), (LOC)) < 0) { \ + compiler_exit_scope(C); \ + return -1; \ + } \ +} + #define POP_EXCEPT_AND_RERAISE(C, LOC) \ RETURN_IF_ERROR(compiler_pop_except_and_reraise((C), (LOC))) @@ -2568,6 +2665,21 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args) return SUCCESS; } +static int +compiler_add_return_value(struct compiler *c, location loc) +{ + if (c->c_regcode) { + oparg_t val = ALLOCATE_TMP(c); + ADDOP_REGS(c, loc, STORE_FAST, OPARGS1(val)); + ADDOP_REGS(c, loc, RETURN_VALUE_R, OPARGS1(val)); + RELEASE_TMPS(c, val.value); + } + else { + ADDOP(c, loc, RETURN_VALUE); + } + return SUCCESS; +} + static inline int insert_instruction(basicblock *block, int pos, struct instr *instr) { RETURN_IF_ERROR(basicblock_next_instr(block)); @@ -2594,7 +2706,7 @@ wrap_in_stopiteration_handler(struct compiler *c) insert_instruction(c->u->u_cfg_builder.g_entryblock, 0, &setup)); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); - ADDOP(c, NO_LOCATION, RETURN_VALUE); + ADD_RETURN_VALUE(c, NO_LOCATION); USE_LABEL(c, handler); ADDOP_I(c, NO_LOCATION, CALL_INTRINSIC_1, INTRINSIC_STOPITERATION_ERROR); ADDOP_I(c, NO_LOCATION, RERAISE, 1); @@ -2774,7 +2886,7 @@ compiler_class(struct compiler *c, stmt_ty s) assert(PyDict_GET_SIZE(c->u->u_cellvars) == 0); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } - ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE); + ADD_RETURN_VALUE_IN_SCOPE(c, NO_LOCATION); /* create the code object */ co = assemble(c, 1); } @@ -3043,7 +3155,7 @@ compiler_lambda(struct compiler *c, expr_ty e) } else { location loc = LOCATION(e->lineno, e->lineno, 0, 0); - ADDOP_IN_SCOPE(c, loc, RETURN_VALUE); + ADD_RETURN_VALUE_IN_SCOPE(c, loc); co = assemble(c, 1); } compiler_exit_scope(c); @@ -3237,7 +3349,7 @@ compiler_return(struct compiler *c, stmt_ty s) else if (!preserve_tos) { ADDOP_LOAD_CONST(c, loc, s->v.Return.value->v.Constant.value); } - ADDOP(c, loc, RETURN_VALUE); + ADD_RETURN_VALUE(c, loc); return SUCCESS; } @@ -5431,7 +5543,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } if (type != COMP_GENEXP) { - ADDOP(c, LOC(e), RETURN_VALUE); + ADD_RETURN_VALUE(c, LOC(e)); } if (type == COMP_GENEXP) { if (wrap_in_stopiteration_handler(c) < 0) { @@ -7480,7 +7592,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { if (explicit_jump == NULL) { return -1; } - basicblock_addop(explicit_jump, JUMP, b->b_next->b_label, NO_LOCATION); + basicblock_addop(explicit_jump, JUMP, b->b_next->b_label, NO_OPARGS, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next; b->b_next = explicit_jump; @@ -7881,7 +7993,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { if (backwards_jump == NULL) { return -1; } - basicblock_addop(backwards_jump, JUMP, target->b_label, NO_LOCATION); + basicblock_addop(backwards_jump, JUMP, target->b_label, NO_OPARGS, NO_LOCATION); backwards_jump->b_instr[0].i_target = target; last->i_opcode = reversed_opcode; last->i_target = b->b_next; @@ -8353,6 +8465,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, .posonlyargcount = posonlyargcount, .kwonlyargcount = kwonlyargcount, + .ntmps = c->u->u_ntmps, .stacksize = maxdepth, .exceptiontable = a->a_except_table, @@ -8559,7 +8672,7 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { continue; } if (last->i_loc.lineno < 0) { - if (last->i_opcode == RETURN_VALUE) { + if (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_VALUE_R) { for (int i = 0; i < b->b_iused; i++) { assert(b->b_instr[i].i_loc.lineno < 0); @@ -8754,11 +8867,50 @@ add_return_at_end_of_block(struct compiler *c, int addNone) if (addNone) { ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } - ADDOP(c, NO_LOCATION, RETURN_VALUE); + ADD_RETURN_VALUE(c, NO_LOCATION); } return SUCCESS; } +static int +resolve_register(oparg_t *oparg, int nlocalsplus, int ntmps) +{ + switch(oparg->type) { + case OPARG_TYPE_UNUSED: + oparg->final = 0; + break; + case OPARG_TYPE_EXPLICIT: + oparg->final = oparg->value; + break; + case OPARG_TYPE_NAME: + assert(oparg->value >= 0 && oparg->value < nlocalsplus); + oparg->final = oparg->value; + break; + case OPARG_TYPE_TMP: { + assert(oparg->value >= 0 && oparg->value < ntmps); + oparg->final = nlocalsplus + oparg->value; + break; + } + default: + Py_UNREACHABLE(); + } + return SUCCESS; +} + +static int +resolve_registers(cfg_builder *g, int nlocalsplus, int ntmps) +{ + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + for (int i = 0; i < b->b_iused; i++) { + struct instr *inst = &b->b_instr[i]; + if (resolve_register(&inst->i_opargs.arg1, nlocalsplus, ntmps) < 0) { + return -1; + } + } + } + return 0; +} + static PyCodeObject * assemble(struct compiler *c, int addNone) { @@ -8862,6 +9014,10 @@ assemble(struct compiler *c, int addNone) /* Can't modify the bytecode after computing jump offsets. */ assemble_jump_offsets(g->g_entryblock); + if (resolve_registers(g, nlocalsplus, c->u->u_ntmps) < 0) { + goto error; + } + /* Create assembler */ if (assemble_init(&a, c->u->u_firstlineno) < 0) { goto error; @@ -9007,7 +9163,7 @@ fold_tuple_on_constants(PyObject *const_cache, for (int i = 0; i < n; i++) { INSTR_SET_OP0(&inst[i], NOP); } - INSTR_SET_OP1(&inst[n], LOAD_CONST, (int)index); + INSTR_SET_OP1(&inst[n], LOAD_CONST, (int)index, UNUSED_OPARG); return 0; } @@ -9198,7 +9354,8 @@ jump_thread(struct instr *inst, struct instr *target, int opcode) } /* Maximum size of basic block that should be copied in optimizer */ -#define MAX_COPY_SIZE 4 +/* TODO: temporarily bumped from 4 to 6 while RETURN_VALUE_R needs a preceding STORE_FAST */ +#define MAX_COPY_SIZE 6 /* Optimization */ static int @@ -9966,7 +10123,7 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) if (PyErr_Occurred()) { return -1; } - if (cfg_builder_addop(g, opcode, oparg, loc) < 0) { + if (cfg_builder_addop(g, opcode, oparg, NO_OPARGS, loc) < 0) { return -1; } } diff --git a/Python/frame.c b/Python/frame.c index 6a287d4724051a..663541992511c1 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -137,7 +137,7 @@ _PyFrame_Clear(_PyInterpreterFrame *frame) } Py_DECREF(f); } - assert(frame->stacktop >= 0); + assert(frame->stacktop >= _PyFrame_StackbaseIndex(frame)); for (int i = 0; i < frame->stacktop; i++) { Py_XDECREF(frame->localsplus[i]); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 46d421f98ac7ef..ad7fbd0d48c9d1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -742,6 +742,23 @@ goto resume_frame; } + TARGET(RETURN_VALUE_R) { + PyObject *retval = REG(oparg1); + assert(EMPTY()); + Py_XINCREF(retval); + _PyFrame_SetStackPointer(frame, stack_pointer); + TRACE_FUNCTION_EXIT(); + DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + TARGET(GET_AITER) { PyObject *obj = PEEK(1); PyObject *iter; @@ -3709,6 +3726,7 @@ assert(cframe.use_tracing == 0); opcode = _Py_OPCODE(*next_instr); oparg = oparg << 8 | _Py_OPARG(*next_instr); + oparg1 = oparg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); } diff --git a/Python/marshal.c b/Python/marshal.c index 5f392d9e1ecfff..27461d3245e942 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -559,6 +559,7 @@ w_complex_object(PyObject *v, char flag, WFILE *p) w_long(co->co_argcount, p); w_long(co->co_posonlyargcount, p); w_long(co->co_kwonlyargcount, p); + w_long(co->co_ntmps, p); w_long(co->co_stacksize, p); w_long(co->co_flags, p); w_object(co_code, p); @@ -1341,6 +1342,7 @@ r_object(RFILE *p) int argcount; int posonlyargcount; int kwonlyargcount; + int ntmps; int stacksize; int flags; PyObject *code = NULL; @@ -1370,6 +1372,9 @@ r_object(RFILE *p) goto code_error; } kwonlyargcount = (int)r_long(p); + if (PyErr_Occurred()) + goto code_error; + ntmps = (int)r_long(p); if (PyErr_Occurred()) goto code_error; stacksize = (int)r_long(p); @@ -1432,6 +1437,7 @@ r_object(RFILE *p) .posonlyargcount = posonlyargcount, .kwonlyargcount = kwonlyargcount, + .ntmps = ntmps, .stacksize = stacksize, .exceptiontable = exceptiontable, diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index e3d8ed340e442d..905c54c86a1579 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -55,6 +55,7 @@ static const struct { [RAISE_VARARGS] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [INTERPRETER_EXIT] = { 1, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [RETURN_VALUE] = { 1, 0, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [RETURN_VALUE_R] = { 0, 0, DIR_READ, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [GET_AITER] = { 1, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_ANEXT] = { 1, 2, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_AWAITABLE] = { 1, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f1c3f3e0c4ee17..2e781a60270668 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_RETURN_VALUE_R, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,15 +152,15 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, - &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5ef2d3f6aa72b0..d22d76ed92cd5b 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -803,7 +803,8 @@ static const uint8_t INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { static const _PyShimCodeDef INTERPRETER_TRAMPOLINE_CODEDEF = { INTERPRETER_TRAMPOLINE_INSTRUCTIONS, sizeof(INTERPRETER_TRAMPOLINE_INSTRUCTIONS), - 1, + 0, /* ntmps */ + 1, /* stacksize */ "" }; diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 511b26a5ce3dc7..d78adecc12ded0 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -259,8 +259,9 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.field(code, "co_argcount") self.field(code, "co_posonlyargcount") self.field(code, "co_kwonlyargcount") - # The following should remain in sync with _PyFrame_NumSlotsForCodeObject - self.write(f".co_framesize = {code.co_stacksize + len(localsplusnames)} + FRAME_SPECIALS_SIZE,") + # The following should remain in sync with the calculation of co_framesize in codeobject.c:init_code() + self.write(f".co_framesize = {code.co_stacksize + code.co_ntmps + len(localsplusnames)} + FRAME_SPECIALS_SIZE,") + self.field(code, "co_ntmps") self.field(code, "co_stacksize") self.field(code, "co_firstlineno") self.write(f".co_nlocalsplus = {len(localsplusnames)},") diff --git a/Tools/build/umarshal.py b/Tools/build/umarshal.py index f61570cbaff751..a4bbd30006368c 100644 --- a/Tools/build/umarshal.py +++ b/Tools/build/umarshal.py @@ -277,6 +277,7 @@ def R_REF(obj: Any) -> Any: retval.co_argcount = self.r_long() retval.co_posonlyargcount = self.r_long() retval.co_kwonlyargcount = self.r_long() + retval.co_ntmps = self.r_long() retval.co_stacksize = self.r_long() retval.co_flags = self.r_long() retval.co_code = self.r_object()